diff --git a/.gitignore b/.gitignore index a87b8bbc1..836ccfd0e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,5 @@ node_modules/* -js/*deck.js -js/*deck.js.map - -js/node_modules/* -js/vendor/ -js/public/ -js/build/ +js/ build/ css/style.css css/vendor.css diff --git a/js/.babelrc.js b/js/.babelrc.js deleted file mode 100644 index 21cf7022f..000000000 --- a/js/.babelrc.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - presets: [ - [ - '@babel/preset-env', - { - targets: { - browsers: ['last 2 versions', 'ie >= 11'] - } - } - ] - ] -} diff --git a/js/.jshintrc b/js/.jshintrc deleted file mode 100644 index 59bd4ee6b..000000000 --- a/js/.jshintrc +++ /dev/null @@ -1,49 +0,0 @@ -{ - "esversion": 6, - - "globals": { - "jasmine" : false, - "spyOn" : false, - "it" : false, - "describe" : false, - "expect" : false, - "beforeEach" : false, - "waits" : false, - "waitsFor" : false, - "runs" : false, - "require" : false, - "module": true - }, - - "asi" : true, - "boss" : true, - "browser" : true, - "curly" : true, - "debug" : true, - "devel" : true, - "eqeqeq" : true, - "eqnull" : false, - "evil" : false, - "forin" : true, - "immed" : true, - "indent" : 4, - "jquery" : true, - "latedef" : true, - "laxbreak" : false, - "newcap" : true, - "noarg" : true, - "node" : false, - "noempty" : false, - "nomen" : false, - "nonew" : true, - "onevar" : true, - "plusplus" : false, - "quotmark" : "single", - "regexp" : false, - "sub" : true, - "trailing" : true, - "undef" : true, - "unused" : true, - "white" : false, - "scripturl" : true -} diff --git a/js/app/App.js b/js/app/App.js deleted file mode 100644 index 332a318ec..000000000 --- a/js/app/App.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -/* global angular */ - - -angular.module('markdown', []) - .provider('markdown', [function () { - var opts = {}; - return { - config: function (newOpts) { - opts = newOpts; - }, - $get: function () { - return new window.showdown.Converter(opts); - } - }; - }]) - .filter('markdown', ['markdown', function (markdown) { - return function (text) { - return markdown.makeHtml(text || ''); - }; - }]); - -import uirouter from '@uirouter/angularjs'; -import ngsanitize from 'angular-sanitize'; -import angularuiselect from 'ui-select'; -import ngsortable from 'ng-sortable'; -import md from 'angular-markdown-it'; -import nganimate from 'angular-animate'; -import 'angular-file-upload'; -import ngInfiniteScroll from 'ng-infinite-scroll'; -import '../legacy/jquery.atwho.min'; -import '../legacy/jquery.caret.min'; - -var app = angular.module('Deck', [ - ngsanitize, - uirouter, - angularuiselect, - ngsortable, md, nganimate, - 'angularFileUpload', - ngInfiniteScroll -]); - -export default app; diff --git a/js/app/Config.js b/js/app/Config.js deleted file mode 100644 index fcb2203fe..000000000 --- a/js/app/Config.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -/* global app oc_requesttoken markdownitLinkTarget */ - -import app from './App.js'; -import md from 'angular-markdown-it'; -import markdownitLinkTarget from 'markdown-it-link-target'; -import markdownitCheckbox from 'legacy/markdown-it-checkbox.js'; - -app.config(function ($provide, $interpolateProvider, $httpProvider, $urlRouterProvider, $stateProvider, $compileProvider, markdownItConverterProvider) { - 'use strict'; - $httpProvider.defaults.headers.common.requesttoken = oc_requesttoken; - - - $compileProvider.debugInfoEnabled(true); - // This should fix adding "unsafe:" prefix to ui-select href links containing javascript - // inline JS is blocked by CSP anyway and filtered out by our markdown renderer as well - $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|javascript):/); - - markdownItConverterProvider.config({ - breaks: true, - linkify: true, - xhtmlOut: true - }); - markdownItConverterProvider.use(markdownitLinkTarget).use(markdownitCheckbox); - - $urlRouterProvider.otherwise('/'); - - $stateProvider - .state('list', { - url: '/:filter', - templateUrl: '/boardlist.mainView.html', - controller: 'ListController', - reloadOnSearch: false, - params: { - filter: {value: '', dynamic: true} - } - }) - .state('board', { - url: '/board/:boardId/:filter', - templateUrl: '/board.html', - controller: 'BoardController', - params: { - filter: {value: '', dynamic: true} - } - }) - .state('board.detail', { - url: '/detail/', - reloadOnSearch: false, - params: { - tab: {value: 0, dynamic: true}, - }, - views: { - 'sidebarView@': { - templateUrl: '/board.sidebarView.html', - controller: 'BoardController' - } - } - }) - .state('board.card', { - url: '/card/:cardId', - params: { - tab: {value: 0, dynamic: true}, - }, - views: { - 'sidebarView@': { - templateUrl: '/card.sidebarView.html', - controller: 'CardController' - } - } - }); - - $provide.decorator('nvFileOverDirective', function ($delegate) { - var directive = $delegate[0], - link = directive.link; - - directive.compile = function () { - return function (scope, element, attrs) { - var overClass = attrs.overClass || 'nv-file-over'; - link.apply(this, arguments); - let counter = 0; - element.on('dragenter', function (event) { - counter++; - }); - element.on('dragleave', function (event) { - counter--; - if (counter <= 0) { - $('.' + overClass).removeClass(overClass); - } - }); - }; - }; - - return $delegate; - }); - -}); diff --git a/js/app/Run.js b/js/app/Run.js deleted file mode 100644 index c5cd45606..000000000 --- a/js/app/Run.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from './App.js'; - -/* global Snap */ -app.run(function ($document, $rootScope, $transitions, BoardService) { - 'use strict'; - - $document.click(function (event) { - $rootScope.$broadcast('documentClicked', event); - }); - $transitions.onEnter({from: 'list'}, function ($state, $transition$) { - BoardService.unsetCurrrent(); - }); - $transitions.onEnter({to: 'list'}, function ($state, $transition$) { - BoardService.unsetCurrrent(); - document.title = "Deck - " + oc_defaults.name; - }); - $transitions.onEnter({to: 'board.card'}, function ($state, $transition$) { - $rootScope.sidebar.show = true; - }); - $transitions.onEnter({to: 'board.detail'}, function ($state, $transition$) { - $rootScope.sidebar.show = true; - }); - $transitions.onEnter({to: 'board'}, function ($state) { - $rootScope.sidebar.show = false; - }); - $transitions.onExit({from: 'board.card'}, function ($state) { - $rootScope.sidebar.show = false; - }); - $transitions.onExit({from: 'board.detail'}, function ($state) { - $rootScope.sidebar.show = false; - }); - - $('link[rel="shortcut icon"]').attr( - 'href', - OC.filePath('deck', 'img', 'app-512.png') - ); - - // Select all elements with data-toggle="tooltips" in the document - $('body').tooltip({ - selector: '[data-toggle="tooltip"]' - }); - -}); diff --git a/js/controller/ActivityController.js b/js/controller/ActivityController.js deleted file mode 100644 index 018e0fbf5..000000000 --- a/js/controller/ActivityController.js +++ /dev/null @@ -1,350 +0,0 @@ -/* - * @copyright Copyright (c) 2018 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -/* global OC OCA OCP t escapeHTML Handlebars moment */ - -import CommentCollection from '../legacy/commentcollection'; -import CommentModel from '../legacy/commentmodel'; - -class ActivityController { - constructor ($scope, CardService, ActivityService, BoardService) { - 'ngInject'; - this.cardservice = CardService; - this.boardservice = BoardService; - this.activityservice = ActivityService; - this.$scope = $scope; - this.type = ''; - this.loading = false; - this.status = { - commentCreateLoading: false - }; - this.$scope.newComment = ''; - this.$scope.newCommentString = 'New comment…'; - - this.currentUser = OC.getCurrentUser(); - - const self = this; - this.$scope.$watch(function () { - return self.element.id; - }, function (params) { - if (self.type === 'deck_card') { - self.activityservice.loadComments(self.element.id); - } - - if (self.getData(self.element.id).length === 0) { - self.loading = true; - self.fetchUntilResults(); - } - self.activityservice.fetchNewerActivities(self.type, self.element.id).then(function () {}); - if (self.type === 'deck_card') { - self.cardservice.getCurrent().commentsUnread = 0; - } - }, true); - - let $target = $('.newCommentForm .message'); - this.applyAtWho($target); - - this.activityservice.subscribe(this.$scope, function() { - self.$scope.$apply(); - }); - - if (typeof OCA.Activity.Templates !== 'undefined') { - OCA.Activity.Templates.userLocal = Handlebars.template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) { - var helper; - // Compiled handlesbars template - // ' {{ name }}'; - return " " - + container.escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : {},{"name":"name","hash":{},"data":data}) : helper))) - + ""; - },"useData":true}); - } else { - OCA.Activity.RichObjectStringParser._userLocalTemplate = ' {{ name }}'; - } - } - - applyAtWho($target) { - const self = this; - if (!$target) { - return; - } - $target.atwho({ - at: '@', - callbacks: { - remoteFilter: function(query, callback) { - let uids = self.boardservice.getUsers(); - uids = uids.filter((x) => x.uid.toLowerCase().includes(query.toLowerCase()) || x.displayname.toLowerCase().includes(query.toLowerCase())); - callback(uids); - }, - highlighter: function (li) { - // misuse the highlighter callback to instead of - // highlighting loads the avatars. - var $li = $(li); - $li.find('.avatar').avatar(undefined, 32); - return $li; - }, - sorter: function (q, items) { return items; } - }, - displayTpl: function (item) { - return '
  • ' + - '' + - '' + - '' + - '' + escapeHTML(item.displayname) + '' + - '
  • '; - }, - insertTpl: function (item) { - return '' + - '' + - '' + - '' + - '' + escapeHTML(item.displayname) + '' + - ''; - }, - searchKey: 'displayname' - }); - $target.on('inserted.atwho', function (je, $el) { - $(je.target).find( - 'span[data-username="' + $el.find('[data-username]').data('username') + '"]' - ).avatar(undefined, 16); - }); - $target.on('shown.atwho', function (je) { - $target.find('.avatar').avatar(undefined, 16); - }); - } - - commentBodyToPlain(content) { - let $comment = $('
    ').html(content); - $comment.find('.avatar-name-wrapper').each(function () { - var $this = $(this); - var $inserted = $this.parent(); - $inserted.html('@' + $this.find('.avatar').data('username')); - }); - $comment.html(OCP.Comments.richToPlain($comment.html())); - $comment.html($comment.html().replace(//gi, '\n')); - return $comment.text(); - } - - static _composeHTMLMention(uid, displayName) { - var avatar = '' + - '' + - ''; - - var isCurrentUser = (uid === OC.getCurrentUser().uid); - - return '' + - '' + - '' + - avatar + - '' + escapeHTML(displayName) + '' + - '' + - ''; - } - - formatMessage(activity) { - let message = activity.message; - let mentions = activity.commentModel.get('mentions'); - const editMode = false; - message = escapeHTML(message).replace(/\n/g, '
    '); - - for(var i in mentions) { - if(!mentions.hasOwnProperty(i)) { - return; - } - var mention = '@' + mentions[i].mentionId; - // escape possible regex characters in the name - mention = mention.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - - const displayName = ActivityController._composeHTMLMention(mentions[i].mentionId, mentions[i].mentionDisplayName); - // replace every mention either at the start of the input or after a whitespace - // followed by a non-word character. - message = message.replace(new RegExp('(^|\\s)(' + mention + ')\\b', 'g'), - function(match, p1) { - // to get number of whitespaces (0 vs 1) right - return p1+displayName; - } - ); - - } - if(editMode !== true) { - message = OCP.Comments.plainToRich(message); - } - return message; - } - - postComment() { - const self = this; - this.status.commentCreateLoading = true; - - let content = this.commentBodyToPlain(self.$scope.newComment); - if (content.length < 1) { - self.status.commentCreateLoading = false; - OC.Notification.showTemporary(t('deck', 'Please provide a content for your comment.')); - return; - } - var model = this.activityservice.commentCollection.create({ - actorId: OC.getCurrentUser().uid, - actorDisplayName: OC.getCurrentUser().displayName, - actorType: 'users', - verb: 'comment', - message: content, - creationDateTime: (new Date()).toUTCString() - }, { - at: 0, - // wait for real creation before adding - wait: true, - success: function() { - self.$scope.newComment = ''; - self.activityservice.fetchNewerActivities(self.type, self.element.id).then(function () {}); - self.status.commentCreateLoading = false; - }, - error: function() { - self.status.commentCreateLoading = false; - OC.Notification.showTemporary(t('deck', 'Posting the comment failed.')); - } - }); - } - - updateComment(item) { - item.commentEdit = this.formatMessage(item); - let $target = $('.newCommentForm .message'); - this.applyAtWho($target); - /** Workaround to trigger avatar rendering after the view has been updated */ - window.setTimeout(function () { - $target.find('.avatar').avatar(undefined, 16); - }, 0); - } - - editComment(item) { - const self = this; - let content = this.commentBodyToPlain(item.commentEdit); - if (content.length < 1) { - OC.Notification.showTemporary(t('deck', 'Please provide a content for your comment.')); - return; - } - /** We need to save the model and afterwards run a fetch to update the mentions - * and call apply to propagate the changes to angular - */ - item.commentModel.on('sync', function() { - item.commentModel.off('sync'); - item.commentModel.fetch({ - success: function() { - self.$scope.$apply(); - } - }); - }); - item.commentModel.save({ - message: content, - }); - item.message = content; - item.commentEdit = undefined; - } - - deleteComment(item) { - item.commentModel.destroy(); - item.deleted = true; - item.commentModel = undefined; - item.message = t('deck', 'The comment has been deleted'); - } - - getData(id) { - return this.activityservice.getData(this.type, id); - } - - parseMessage(activity) { - let subject = activity.subject_rich[0]; - let parameters = activity.subject_rich[1]; - if (parameters.after && typeof parameters.after.id === 'string' && parameters.after.id.startsWith('dt:')) { - let dateTime = parameters.after.id.substr(3); - parameters.after.name = moment(dateTime).format('L LTS'); - } - return OCA.Activity.RichObjectStringParser.parseMessage(subject, parameters); - } - - fetchUntilResults () { - const self = this; - let dataLengthBefore = self.getData(self.element.id).length; - let _executeFetch = function() { - let promise = self.activityservice.fetchMoreActivities(self.type, self.element.id); - promise.then(function (data) { - let dataLengthAfter = self.getData(self.element.id).length; - if (data !== null && (dataLengthAfter <= dataLengthBefore || dataLengthAfter < self.activityservice.RESULT_PER_PAGE)) { - _executeFetch(); - } else { - self.loading = false; - } - }, function () { - self.loading = false; - self.$scope.$apply(); - }); - - }; - _executeFetch(); - } - - getComments() { - return this.activityservice.comments; - } - - getActivityStream() { - let activities = this.activityservice.getData(this.type, this.element.id); - return activities; - } - - page() { - if (!this.activityservice.since[this.type][this.element.id].finished) { - this.loading = true; - this.fetchUntilResults(); - } else { - this.loading = false; - } - } - - loadingNewer() { - return this.activityservice.runningNewer; - } - - t(text) { - return t('deck', text); - } -} - -let activityComponent = { - templateUrl: OC.linkTo('deck', 'templates/part.card.activity.html'), - controller: ActivityController, - bindings: { - type: '@', - element: '=' - } -}; -export default activityComponent; diff --git a/js/controller/AppController.js b/js/controller/AppController.js deleted file mode 100644 index 6410473f4..000000000 --- a/js/controller/AppController.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -import app from '../app/App.js'; - -/* globals oc_current_user: false */ -app.controller('AppController', function ($scope, $location, $http, $log, $rootScope, $attrs) { - $rootScope.sidebar = { - show: false - }; - $scope.sidebar = $rootScope.sidebar; - $scope.user = oc_current_user; - $rootScope.config = JSON.parse($attrs.config); - - $rootScope.compactMode = localStorage.getItem('deck.compactMode') === 'true'; - $scope.appNavigationHide = localStorage.getItem('deck.appNavigationHide') === 'true'; - - $scope.toggleSidebar = function() { - if ($(window).width() > 768) { - $log.debug($scope.appNavigationHide); - $scope.appNavigationHide = !$scope.appNavigationHide; - localStorage.setItem('deck.appNavigationHide', JSON.stringify($scope.appNavigationHide)); - } - }; -}); diff --git a/js/controller/AttachmentController.js b/js/controller/AttachmentController.js deleted file mode 100644 index da8ce5292..000000000 --- a/js/controller/AttachmentController.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * @copyright Copyright (c) 2018 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -/* global OC */ - -class AttachmentListController { - constructor ($scope, CardService, FileService) { - 'ngInject'; - this.cardservice = CardService; - this.fileservice = FileService; - this.attachments = CardService.getCurrent().attachments; - } - - mimetypeForAttachment(attachment) { - let url = OC.MimeType.getIconUrl(attachment.extendedData.mimetype); - let styles = { - 'background-image': `url("${url}")`, - }; - return styles; - } - - attachmentUrl(attachment) { - let cardId = this.cardservice.getCurrent().id; - let attachmentId = attachment.id; - return OC.generateUrl(`/apps/deck/cards/${cardId}/attachment/${attachmentId}`); - } - - getAttachmentMarkdown(attachment) { - const inlineMimetypes = ['image/png', 'image/jpg', 'image/jpeg']; - let url = this.attachmentUrl(attachment); - let filename = attachment.data; - let insertText = `[📎 ${filename}](${url})`; - if (inlineMimetypes.indexOf(attachment.extendedData.mimetype) > -1) { - insertText = `![📎 ${filename}](${url})`; - } - return insertText; - } - - select(attachment) { - this.onSelect({attachment: this.getAttachmentMarkdown(attachment)}); - } - - abort() { - this.onAbort(); - } - -} - -let attachmentListComponent = { - templateUrl: '/card.attachments.html', - controller: AttachmentListController, - bindings: { - isFileSelector: '<', - attachments: '=', - onSelect: '&', - onAbort: '&' - } -}; -export default attachmentListComponent; diff --git a/js/controller/BoardController.js b/js/controller/BoardController.js deleted file mode 100644 index 802756db0..000000000 --- a/js/controller/BoardController.js +++ /dev/null @@ -1,568 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -/* global oc_defaults oc_config OC OCP OCA t n */ - -import app from '../app/App.js'; -import Vue from 'vue'; - -Vue.prototype.t = t; -Vue.prototype.n = n; -Vue.prototype.OC = OC; - -import CollaborationView from '../views/CollaborationView'; - -app.controller('BoardController', function ($rootScope, $scope, $element, $stateParams, StatusService, BoardService, StackService, CardService, LabelService, $state, $transitions, $filter, FileService) { - - $scope.sidebar = $rootScope.sidebar; - - $scope.id = $stateParams.boardId; - $scope.status = { - addCard: [], - }; - $scope.newLabel = {}; - - $scope.OC = OC; - $scope.stackservice = StackService; - $scope.boardservice = BoardService; - $scope.cardservice = CardService; - $scope.statusservice = StatusService.getInstance(); - $scope.labelservice = LabelService; - $scope.defaultColors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD']; - $scope.board = BoardService.getCurrent(); - $scope.uploader = FileService.uploader; - $scope.searchText = ''; - - $scope.startTitleEdit = function(card) { - card.renameTitle = card.title; - card.status = card.status || {}; - card.status.editCard = true; - }; - - $scope.finishTitleEdit = function(card) { - var newTitle; - if (!card.renameTitle || !card.renameTitle.trim()) { - newTitle = ''; - } else { - newTitle = card.renameTitle.trim(); - } - - if (newTitle === card.title) { - // title unchanged - card.status.editCard = false; - delete card.renameTitle; - } else if (newTitle !== '') { - // title changed - card.title = newTitle; - CardService.update(card).then(function (data) { - card.status.editCard = false; - delete card.renameTitle; - }); - } else { - // empty title - card.status.editCard = false; - delete card.renameTitle; - } - }; - - $scope.$watch(function() { - return $scope.params.tab; - }, function (newTab, oldTab) { - if (newTab === 2 && oldTab !== 2) { - CardService.fetchDeleted($scope.id); - StackService.fetchDeleted($scope.id); - } - }); - - // workaround for $stateParams changes not being propagated - $scope.$watch(function() { - return $state.params; - }, function (params) { - $scope.params = params; - }, true); - $scope.params = $state.params; - - /** - * Check for markdown checkboxes in description to render the counter - * - * This should probably be moved to the backend at some point - * - * @param text - * @returns array of [finished, total] checkboxes - */ - $scope.getCheckboxes = function(text) { - const regTotal = /\[(X|\s|\_|\-)\]/igm; - const regFinished = /\[(X|\_|\-)\]/igm; - return [ - ((text || '').match(regFinished) || []).length, - ((text || '').match(regTotal) || []).length - ]; - }; - - $scope.search = function (searchText) { - $scope.searchText = searchText; - $scope.refreshData(); - }; - - $scope.$watch(function () { - if (typeof BoardService.getCurrent() !== 'undefined') { - return BoardService.getCurrent().title; - } else { - return null; - } - }, function () { - $scope.setPageTitle(); - }); - $scope.setPageTitle = function () { - if (BoardService.getCurrent()) { - document.title = BoardService.getCurrent().title + ' | Deck - ' + oc_defaults.name; - } else { - document.title = 'Deck - ' + oc_defaults.name; - } - }; - - $scope.statusservice.retainWaiting(); - $scope.statusservice.retainWaiting(); - - // handle filter parameter for switching between archived/unarchived cards - $scope.switchFilter = function (filter) { - $state.go('.', {filter: filter}); - }; - $scope.$watch(function() { - return $scope.params.filter; - }, function (filter) { - if (filter === 'archive') { - $scope.loadArchived(); - } else { - $scope.loadDefault(); - } - }); - - if (parseInt(oc_config.version.split('.')[0]) >= 16) { - const ComponentVM = new Vue({ - render: h => h(CollaborationView), - data: { - model: BoardService.getCurrent() - }, - }); - $scope.mountCollections = function () { - const MountingPoint = document.getElementById('collaborationResources'); - if (MountingPoint) { - ComponentVM.model = BoardService.getCurrent(); - ComponentVM.$mount(MountingPoint); - } - }; - $scope.$$postDigest($scope.mountCollections); - $scope.$watch(function () { - return BoardService.getCurrent(); - }, function () { - ComponentVM.model = BoardService.getCurrent(); - if ($scope.sidebar.show) { - $scope.$$postDigest($scope.mountCollections); - } - }); - } - - $scope.toggleCompactMode = function() { - $rootScope.compactMode = !$rootScope.compactMode; - localStorage.setItem('deck.compactMode', JSON.stringify($rootScope.compactMode)); - }; - - $scope.stacksData = StackService; - $scope.stacks = []; - $scope.$watch('stacksData', function () { - $scope.refreshData(); - }, true); - $scope.refreshData = function () { - if ($scope.params.filter === 'archive') { - $scope.filterData('-lastModified', $scope.searchText); - } else { - $scope.filterData('order', $scope.searchText); - } - }; - $scope.checkCanEdit = function () { - return !BoardService.getCurrent().archived; - }; - - // filter cards here, as ng-sortable will not work nicely with html-inline filters - $scope.filterData = function (order, text) { - if ($scope.stacks === undefined) { - return; - } - angular.copy(StackService.getData(), $scope.stacks); - $scope.stacks = $filter('orderBy')($scope.stacks, 'order'); - angular.forEach($scope.stacks, function (value, key) { - var cards = $filter('cardSearchFilter')(value.cards, text); - cards = $filter('orderBy')(cards, order); - $scope.stacks[key].cards = cards; - }); - }; - - $scope.loadDefault = function () { - StackService.fetchAll($scope.id).then(function (data) { - $scope.statusservice.releaseWaiting(); - }, function (error) { - $scope.statusservice.setError('Error occured', error); - }); - }; - - $scope.loadArchived = function () { - StackService.fetchArchived($scope.id).then(function (data) { - $scope.statusservice.releaseWaiting(); - }, function (error) { - $scope.statusservice.setError('Error occured', error); - }); - }; - - // Handle initial Loading - BoardService.fetchOne($scope.id).then(function (data) { - $scope.statusservice.releaseWaiting(); - $scope.setPageTitle(); - }, function (error) { - $scope.statusservice.setError('Error occured', error); - }); - - $scope.searchForUser = function (search) { - BoardService.searchUsers(search); - }; - - $scope.newStack = {'boardId': $scope.id}; - $scope.newCard = {}; - - // Create a new Stack - $scope.createStack = function () { - StackService.create($scope.newStack).then(function (data) { - $scope.newStack.title = ''; - }); - }; - - $scope.createCard = function (stack, title) { - if (this['addCardForm' + stack].$valid) { - var newCard = { - 'title': title, - 'stackId': stack, - 'type': 'plain' - }; - CardService.create(newCard).then(function (data) { - $scope.stackservice.addCard(data); - $scope.newCard.title = ''; - }); - } - }; - - $scope.stackDelete = function (stack) { - $scope.stackservice.delete(stack.id); - }; - - $scope.stackUndoDelete = function (deletedStack) { - return StackService.undoDelete(deletedStack); - }; - - $scope.cardDelete = function (card) { - CardService.delete(card.id).then(function () { - StackService.removeCard(card); - $scope.sidebar.show = false; - }); - }; - - $scope.cardOrCardAndStackUndoDelete = function (deletedCard) { - var associatedDeletedStack = $scope.stackservice.deleted[deletedCard.stackId]; - if(associatedDeletedStack !== undefined) { - $scope.cardAndStackUndoDeleteAskForConfirmation(deletedCard, associatedDeletedStack); - } else { - $scope.cardUndoDelete(deletedCard); - } - }; - - $scope.cardAndStackUndoDeleteAskForConfirmation = function(deletedCard, associatedDeletedStack) { - OC.dialogs.confirm( - t('deck', 'The associated stack is deleted as well, it will be restored as well.'), - t('deck', 'Restore associated stack'), - function(state) { - if (state) { - $scope.cardAndStackUndoDelete(deletedCard, associatedDeletedStack); - } - } - ); - }; - - $scope.cardAndStackUndoDelete = function(deletedCard, associatedDeletedStack) { - $scope.stackUndoDelete(associatedDeletedStack).then(function() { - $scope.cardUndoDelete(deletedCard); - }); - }; - - $scope.cardUndoDelete = function(deletedCard) { - CardService.undoDelete(deletedCard).then(function() { - StackService.addCard(deletedCard); - }); - }; - - $scope.cardArchive = function (card) { - CardService.archive(card); - StackService.removeCard(card); - }; - - $scope.isCurrentUserAssigned = function (card) { - if (! CardService.get(card.id).assignedUsers) { - return false; - } - var userList = CardService.get(card.id).assignedUsers.filter(function (obj) { - return obj.participant.uid === OC.getCurrentUser().uid; - }); - return userList.length === 1; - }; - - $scope.cardAssignToMe = function (card) { - CardService.assignUser(card, OC.getCurrentUser().uid) - .then( - function() {StackService.updateCard(card);} - ); - // TODO: remove this jquery call. Fix and use appPopoverMenuUtils instead - $('.popovermenu').addClass('hidden'); - }; - - $scope.cardUnassignFromMe = function (card) { - CardService.unassignUser(card, OC.getCurrentUser().uid); - StackService.updateCard(card); - // TODO: remove this jquery call.Fix and use appPopoverMenuUtils instead - $('.popovermenu').addClass('hidden'); - }; - $scope.cardUnarchive = function (card) { - CardService.unarchive(card); - StackService.removeCard(card); - }; - - $scope.labelDelete = function (label) { - LabelService.delete(label.id); - // remove from board data - var i = BoardService.getCurrent().labels.indexOf(label); - BoardService.getCurrent().labels.splice(i, 1); - - // remove from cards - var cards = CardService.data; - for (var card in cards) { - if (Object.prototype.hasOwnProperty.call(cards, card)) { - var labelsFromCard = cards[card].labels; - - labelsFromCard.forEach(function (labelFromCard, index) { - if (labelFromCard.id === label.id) { - cards[card].labels.splice(index, 1); - } - }); - } - } - }; - - $scope.labelCreate = function (label) { - label.boardId = $scope.id; - LabelService.create(label).then(function (data) { - $scope.newStack.title = ''; - BoardService.getCurrent().labels.push(data); - $scope.status.createLabel = false; - $scope.newLabel = {}; - }).catch((err) => { - OC.Notification.showTemporary(err); - }); - }; - - $scope.labelUpdateBefore = function (label) { - label.renameTitle = label.title; - }; - - $scope.labelUpdate = function (label) { - label.edit = false; - LabelService.update(label).catch((err) => { - label.title = label.renameTitle; - OC.Notification.showTemporary(err); - }); - - // update labels in UI - var cards = CardService.data; - for (var card in cards) { - if (Object.prototype.hasOwnProperty.call(cards, card)) { - var labelsFromCard = cards[card].labels; - - labelsFromCard.forEach(function (labelFromCard, index) { - if (labelFromCard.id === label.id) { - cards[card].labels[index] = label; - } - }); - } - } - }; - - $scope.aclAdd = function (sharee) { - sharee.boardId = $scope.id; - BoardService.addAcl(sharee); - $scope.status.addSharee = null; - }; - - $scope.aclDelete = function (acl) { - BoardService.deleteAcl(acl).then(function(data) { - $scope.loadDefault(); - $scope.refreshData(); - }); - }; - - $scope.aclUpdate = function (acl) { - BoardService.updateAcl(acl); - }; - - $scope.aclTypeString = function (acl) { - if (typeof acl === 'undefined') { - return ''; - } - switch (acl.type) { - case OC.Share.SHARE_TYPE_USER: - return 'user'; - case OC.Share.SHARE_TYPE_GROUP: - return 'group'; - case OC.Share.SHARE_TYPE_CIRCLE: - return 'circles'; - default: - return ''; - } - }; - - // settings for card sorting - $scope.sortOptions = { - id: 'card', - itemMoved: function (event) { - event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column; - var order = event.dest.index; - var card = $scope.cardservice.get(event.source.itemScope.c.id); - var newStack = event.dest.sortableScope.$parent.s.id; - var oldStack = card.stackId; - card.stackId = newStack; - CardService.update(card); - CardService.reorder(card, order).then(function (data) { - StackService.addCard(card); - StackService.reorderCard(card, order); - StackService.removeCard({ - id: card.id, - stackId: oldStack - }); - }); - }, - orderChanged: function (event) { - var order = event.dest.index; - var card = $scope.cardservice.get(event.source.itemScope.c.id); - var stack = event.dest.sortableScope.$parent.s.id; - CardService.reorder(card, order).then(function (data) { - StackService.reorderCard(card, order); - $scope.refreshData(); - }); - }, - scrollableContainer: '#innerBoard', - containerPositioning: 'relative', - containment: '#innerBoard', - longTouch: true, - // auto scroll on drag - dragMove: function (itemPosition, containment, eventObj) { - if (eventObj) { - var container = $('#board'); - var offset = container.offset(); - var targetX = eventObj.pageX - (offset.left || container.scrollLeft()); - var targetY = eventObj.pageY - (offset.top || container.scrollTop()); - if (targetX < offset.left) { - container.scrollLeft(container.scrollLeft() - 25); - } else if (targetX > container.width()) { - container.scrollLeft(container.scrollLeft() + 25); - } - if (targetY < offset.top) { - container.scrollTop(container.scrollTop() - 25); - } else if (targetY > container.height()) { - container.scrollTop(container.scrollTop() + 25); - } - } - }, - accept: function (sourceItemHandleScope, destSortableScope, destItemScope) { - return sourceItemHandleScope.sortableScope.options.id === 'card'; - } - }; - - $scope.sortOptionsStack = { - id: 'stack', - orderChanged: function (event) { - var order = event.dest.index; - var stack = event.source.itemScope.s; - StackService.reorder(stack, order).then(function (data) { - $scope.refreshData(); - }); - }, - scrollableContainer: '#board', - containerPositioning: 'relative', - containment: '#innerBoard', - dragMove: function (itemPosition, containment, eventObj) { - if (eventObj) { - var container = $('#board'); - var offset = container.offset(); - var targetX = eventObj.pageX - (offset.left || container.scrollLeft()); - var targetY = eventObj.pageY - (offset.top || container.scrollTop()); - if (targetX < offset.left) { - container.scrollLeft(container.scrollLeft() - 50); - } else if (targetX > container.width()) { - container.scrollLeft(container.scrollLeft() + 50); - } - if (targetY < offset.top) { - container.scrollTop(container.scrollTop() - 50); - } else if (targetY > container.height()) { - container.scrollTop(container.scrollTop() + 50); - } - } - }, - accept: function (sourceItemHandleScope, destSortableScope, destItemScope) { - return sourceItemHandleScope.sortableScope.options.id === 'stack'; - } - }; - - $scope.labelStyle = function (color) { - return { - 'background-color': '#' + color, - 'color': $filter('textColorFilter')(color) - }; - }; - - $scope.colorValue = function(color) { - const re = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/; - if (re.test(color)) { - return color; - } - return ''; - }; - - $scope.attachmentCount = function(card) { - if (Array.isArray(card.attachments)) { - return card.attachments.filter((obj) => obj.deletedAt === 0).length; - } - return card.attachmentCount; - }; - - $scope.unreadCommentCount = function(card) { - return card.commentsUnread; - }; - - $scope.isTimelineEnabled = function() { - return OCP.Comments && OCA.Activity; - }; - -}); diff --git a/js/controller/CardController.js b/js/controller/CardController.js deleted file mode 100644 index 27f185487..000000000 --- a/js/controller/CardController.js +++ /dev/null @@ -1,286 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -/* global app moment angular OC OCP OCA */ -import app from '../app/App.js'; - -app.controller('CardController', function ($scope, $rootScope, $sce, $location, $stateParams, $state, $interval, $timeout, $filter, BoardService, CardService, StackService, StatusService, markdownItConverter, FileService) { - $scope.sidebar = $rootScope.sidebar; - $scope.status = { - renameTitle: '', - lastEdit: 0, - lastSave: Date.now() - }; - - $scope.cardservice = CardService; - $scope.fileservice = FileService; - $scope.cardId = $stateParams.cardId; - - $scope.statusservice = StatusService.getInstance(); - $scope.boardservice = BoardService; - - $scope.isArray = angular.isArray; - // workaround for $stateParams changes not being propagated - $scope.$watch(function() { - return $state.params; - }, function (params) { - $scope.params = params; - $scope.fileservice.reset(); - }, true); - $scope.params = $state.params; - - $scope.addAttachmentToDescription = function(insertText) { - let el = document.querySelectorAll('textarea')[0]; - let start = el.selectionStart; - let end = el.selectionEnd; - let text = $scope.status.edit.description || ''; - let before = text.substring(0, start); - let after = text.substring(end, text.length); - let newText = before + '\n' + insertText + '\n' + after; - $scope.status.edit.description = newText; - el.selectionStart = el.selectionEnd = start + newText.length; - el.focus(); - $scope.status.continueEdit = false; - $scope.cardEditDescriptionChanged(); - $scope.status.selectAttachment = false; - }; - - $scope.abortAttachmentSelection = function() { - $scope.status.continueEdit = false; - $scope.status.selectAttachment = false; - let el = document.querySelectorAll('textarea')[0]; - el.focus(); - }; - - $scope.statusservice.retainWaiting(); - - $scope.description = function() { - return $scope.rendered; - }; - - $scope.updateMarkdown = function(content) { - // only trust the html from markdown-it-checkbox - $scope.rendered = $sce.trustAsHtml(markdownItConverter.render(content || '')); - }; - - CardService.fetchOne($scope.cardId).then(function (data) { - $scope.statusservice.releaseWaiting(); - $scope.archived = CardService.getCurrent().archived; - $scope.updateMarkdown(CardService.getCurrent().description); - }, function (error) { - }); - - $scope.cardRenameShow = function () { - if ($scope.archived || !BoardService.canEdit()) { - return false; - } else { - $scope.status.renameTitle = CardService.getCurrent().title; - $scope.status.cardRename = true; - } - }; - - $scope.toggleCheckbox = function (id) { - $('#markdown input[type=checkbox]').attr('disabled', true); - $scope.status.edit = angular.copy(CardService.getCurrent()); - var reg = /\[(X|\s|\_|\-)\]/ig; - var nth = 0; - $scope.status.edit.description = $scope.status.edit.description.replace(reg, function (match, i, original) { - var result = match; - if ('' + nth++ === '' + id) { - if (match.match(/^\[\s\]/i)) { - result = match.replace(/\[\s\]/i, '[x]'); - } - if (match.match(/^\[x\]/i)) { - result = match.replace(/\[x\]/i, '[ ]'); - } - return result; - } - return match; - }); - CardService.update($scope.status.edit).then(function (data) { - var header = $('.tabDetails'); - header.find('.save-indicator.unsaved').hide(); - header.find('.save-indicator.saved').fadeIn(250).fadeOut(1000); - }); - $('#markdown input[type=checkbox]').removeAttr('disabled'); - - }; - $scope.clickCardDescription = function ($event) { - var checkboxId = $($event.target).data('id'); - if ($event.target.tagName === 'LABEL') { - $scope.toggleCheckbox(checkboxId); - $event.stopPropagation(); - return false; - } - if ($event.target.tagName === 'INPUT') { - $event.stopPropagation(); - return; - } - if (BoardService.isArchived() || CardService.getCurrent().archived) { - return false; - } - if ($scope.card.archived || !$scope.boardservice.canEdit()) { - return false; - } - $scope.status.cardEditDescription = true; - $scope.status.edit = angular.copy(CardService.getCurrent()); - return true; - }; - $scope.cardEditDescriptionChanged = function ($event) { - $scope.status.lastEdit = Date.now(); - var header = $('.tabDetails'); - header.find('.save-indicator.unsaved').show(); - header.find('.save-indicator.saved').hide(); - }; - $interval(function() { - var currentTime = Date.now(); - var timeSinceEdit = currentTime-$scope.status.lastEdit; - if (timeSinceEdit > 1000 && $scope.status.lastEdit > $scope.status.lastSave && !$scope.status.saving) { - $scope.status.lastSave = currentTime; - $scope.status.saving = true; - var header = $('.tabDetails'); - header.find('.save-indicator.unsaved').fadeIn(500); - CardService.update($scope.status.edit).then(function (data) { - var header = $('.tabDetails'); - header.find('.save-indicator.unsaved').hide(); - header.find('.save-indicator.saved').fadeIn(250).fadeOut(1000); - $scope.status.saving = false; - }); - } - }, 500, 0, false); - - // handle rename to update information on the board as well - $scope.cardRename = function (card) { - var newTitle; - if (!$scope.status.renameTitle || !$scope.status.renameTitle.trim()) { - newTitle = ''; - } else { - newTitle = $scope.status.renameTitle.trim(); - } - - if (newTitle === card.title) { - // title unchanged - $scope.status.renameCard = false; - } else if (newTitle !== '') { - // title changed - card.title = newTitle; - CardService.rename(card).then(function (data) { - $scope.status.renameCard = false; - }); - } else { - // empty title - $scope.status.renameTitle = card.title; - $scope.status.renameCard = false; - } - }; - $scope.cardUpdate = function (card) { - CardService.update(card).then(function (data) { - $scope.status.cardEditDescription = false; - $scope.updateMarkdown($scope.status.edit.description); - var header = $('.tabDetails'); - header.find('.save-indicator.unsaved').hide(); - header.find('.save-indicator.saved').fadeIn(500).fadeOut(1000); - }); - }; - - $scope.labelAssign = function (element, model) { - CardService.assignLabel($scope.cardId, element.id).then(function (data) { - }); - }; - - $scope.labelRemove = function (element, model) { - CardService.removeLabel($scope.cardId, element.id).then(function (data) { - }); - }; - - $scope.setDuedate = function (duedate) { - var element = CardService.getCurrent(); - var newDate = moment(element.duedate); - if(!newDate.isValid()) { - newDate = moment(); - } - newDate.date(duedate.date()); - newDate.month(duedate.month()); - newDate.year(duedate.year()); - element.duedate = newDate.toISOString(); - CardService.update(element); - }; - $scope.setDuedateTime = function (time) { - var element = CardService.getCurrent(); - var newDate = moment(element.duedate); - if(!newDate.isValid()) { - newDate = moment(); - } - newDate.hour(time.hour()); - newDate.minute(time.minute()); - element.duedate = newDate.toISOString(); - CardService.update(element); - }; - - $scope.resetDuedate = function () { - var element = CardService.getCurrent(); - element.duedate = null; - CardService.update(element); - }; - - /** - * Show ui-select field when clicking the add button - */ - $scope.toggleAssignUser = function() { - $scope.status.showAssignUser = !$scope.status.showAssignUser; - if ($scope.status.showAssignUser === true) { - $timeout(function () { - $('#assignUserSelect').find('a').click(); - }); - } - }; - - /** - * Hide ui-select when select list is closed - */ - $scope.assingUserOpenClose = function(isOpen) { - $scope.status.showAssignUser = isOpen; - }; - - $scope.addAssignedUser = function(item) { - CardService.assignUser(CardService.getCurrent(), item.uid).then(function (data) { - }); - $scope.status.showAssignUser = false; - }; - - $scope.removeAssignedUser = function(uid) { - CardService.unassignUser(CardService.getCurrent(), uid).then(function (data) { - }); - }; - - $scope.labelStyle = function (color) { - return { - 'background-color': '#' + color, - 'color': $filter('textColorFilter')(color) - }; - }; - - $scope.isTimelineEnabled = function() { - return OCP.Comments && OCA.Activity; - }; - -}); diff --git a/js/controller/ColorPickerController.js b/js/controller/ColorPickerController.js deleted file mode 100644 index 8de938556..000000000 --- a/js/controller/ColorPickerController.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * @copyright Copyright (c) 2018 Oskar Kurz - * - * @author Oskar Kurz - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -import app from '../app/App.js'; - -/* global oc_defaults OC */ -app.controller('ColorPickerController', ['$scope', function ($scope) { - $scope.hashedColor = ''; - - $scope.setColor = function (object, color) { - object.color = color; - object.hashedColor = '#' + color; - - return object; - }; - - $scope.setHashedColor = function (object) { - object.color = object.hashedColor.substr(1); - return object; - }; - - $scope.getCustomBackground = function (color) { - return {'background-color': color}; - }; -}]); diff --git a/js/controller/ListController.js b/js/controller/ListController.js deleted file mode 100644 index c88d43226..000000000 --- a/js/controller/ListController.js +++ /dev/null @@ -1,255 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -/* global app angular oc_isadmin */ - -var ListController = function ($scope, $location, $filter, BoardService, $element, $timeout, $stateParams, $state, StatusService, $http, $q, $rootScope) { - - function calculateNewColor() { - var boards = BoardService.getAll(); - var boardKeys = Object.keys(boards); - var colorOccurrences = []; - - for (var i = 0; i < $scope.colors.length; i++) { - colorOccurrences.push(0); - } - - for (var j = 0; j < boardKeys.length; j++) { - var key = boardKeys[j]; - var board = boards[key]; - - if (board && $scope.colors.indexOf(board.color) !== -1) { - colorOccurrences[$scope.colors.indexOf(board.color)]++; - } - } - - return $scope.colors[colorOccurrences.indexOf(Math.min.apply(Math, colorOccurrences))]; - } - - $scope.boards = []; - $scope.newBoard = {}; - $scope.status = { - deleteUndo: [], - filter: $stateParams.filter ? $stateParams.filter : '', - sidebar: false - }; - $scope.colors = ['0082c9', '00c9c6','00c906', 'c92b00', 'F1DB50', '7C31CC', '3A3B3D', 'CACBCD']; - $scope.boardservice = BoardService; - $scope.updatingBoard = null; - $scope.isAdmin = oc_isadmin; - $scope.canCreate = $rootScope.config.canCreate; - - if ($scope.isAdmin) { - OC.Apps.enableDynamicSlideToggle(); - $scope.groups = []; - $scope.groupLimit = []; - $scope.groupLimitDisabled = true; - let fetchGroups = function () { - var deferred = $q.defer(); - // TODO: move to groups/details once 15 is min version - $http.get(OC.linkToOCS('cloud', 2) + 'groups').then(function (response) { - $scope.groups = response.data.ocs.data.groups.reduce((obj, item) => { - obj.push({ - id: item, - displayname: item, - }); - return obj; - }, []); - deferred.resolve($scope.groups); - }, function (error) { - deferred.reject('Error while loading groups'); - }); - $http.get(OC.generateUrl('apps/deck/config')).then(function (response) { - $scope.groupLimit = response.data.groupLimit; - $scope.groupLimitDisabled = false; - deferred.resolve(response.data); - }, function (error) { - deferred.reject('Error while loading groupLimit'); - }); - return deferred.promise; - }; - - let updateConfig = function() { - $scope.groupLimitDisabled = true; - var deferred = $q.defer(); - $http.post(OC.generateUrl('apps/deck/config/groupLimit'), {value: $scope.groupLimit}).then(function (response) { - $scope.groupLimitDisabled = false; - deferred.resolve(response.data); - }, function (error) { - deferred.reject('Error while saving groupLimit'); - }); - return deferred.promise; - }; - - $scope.groupLimitAdd = function (element, model) { - $scope.groupLimit.push(element); - updateConfig(); - }; - $scope.groupLimitRemove = function (element, model) { - $scope.groupLimit = $scope.groupLimit.filter((el) => { - return el.id !== element.id; - }); - updateConfig(); - }; - fetchGroups(); - } - - var filterData = function () { - if($element.attr('id') === 'app-navigation') { - $scope.boardservice.sidebar = $scope.boardservice.getData(); - $scope.boardservice.sidebar = $filter('orderBy')($scope.boardservice.sidebar, 'title'); - $scope.boardservice.sidebar = $filter('cardFilter')($scope.boardservice.sidebar, {archived: false}); - } else { - $scope.boardservice.sorted = $scope.boardservice.getData(); - if ($scope.status.filter === 'archived') { - var filter = {}; - filter[$scope.status.filter] = true; - $scope.boardservice.sorted = $filter('cardFilter')($scope.boardservice.sorted, filter); - } else if ($scope.status.filter === 'shared') { - $scope.boardservice.sorted = $filter('cardFilter')($scope.boardservice.sorted, {archived: false}); - $scope.boardservice.sorted = $filter('boardFilterAcl')($scope.boardservice.sorted); - } else { - $scope.boardservice.sorted = $filter('cardFilter')($scope.boardservice.sorted, {archived: false}); - } - $scope.boardservice.sorted = $filter('orderBy')($scope.boardservice.sorted, ['deletedAt', 'title']); - } - }; - - var finishedLoading = function() { - filterData(); - $scope.newBoard.color = calculateNewColor(); - }; - - var initialize = function () { - $scope.statusservice = StatusService.listStatus; - - if($element.attr('id') === 'app-navigation') { - $scope.statusservice.retainWaiting(); - BoardService.fetchAll().then(function(data) { - finishedLoading(); - $scope.statusservice.releaseWaiting(); - BoardService.loaded = true; - }, function (error) { - $scope.statusservice.setError('Error occured', error); - }); - } else { - /* initialize main list controller when board list is loaded */ - var boardDataWatch = $scope.$watch(function () { - return $scope.boardservice.loaded; - }, function () { - if (BoardService.loaded === true) { - boardDataWatch(); - finishedLoading(); - } - }); - } - - $scope.$watch(function () { - return $scope.boardservice.data; - }, function () { - filterData(); - }, true); - - /* Watch for board filter change */ - $scope.$watchCollection(function(){ - return $state.params; - }, function(){ - $scope.status.filter = $state.params.filter; - filterData(); - }); - }; - initialize(); - - $scope.selectColor = function(color) { - $scope.newBoard.color = color; - }; - - $scope.gotoBoard = function(board) { - if(board.deletedAt > 0) { - return false; - } - return $state.go('board', {boardId: board.id}); - }; - - $scope.boardCreate = function() { - if(!$scope.newBoard.title || !$scope.newBoard.color) { - $scope.status.addBoard=false; - return; - } - BoardService.create($scope.newBoard) - .then(function (response) { - $scope.newBoard = {}; - $scope.newBoard.color = calculateNewColor(); - $scope.status.addBoard=false; - filterData(); - }, function(error) { - $scope.status.createBoard = 'Unable to insert board: ' + error.message; - }); - }; - - $scope.boardUpdate = function(board) { - BoardService.update(board).then(function(data) { - board.status.edit = false; - filterData(); - }); - }; - - $scope.boardUpdateBegin = function(board) { - $scope.updatingBoard = angular.copy(board); - }; - - $scope.boardUpdateReset = function(board) { - board.title = $scope.updatingBoard.title; - board.color = $scope.updatingBoard.color; - filterData(); - board.status.edit = false; - }; - - $scope.boardArchive = function (board) { - board.archived = true; - BoardService.update(board).then(function(data) { - filterData(); - }); - }; - - $scope.boardUnarchive = function (board) { - board.archived = false; - BoardService.update(board).then(function(data) { - filterData(); - }); - }; - - $scope.boardDelete = function(board) { - BoardService.delete(board.id).then(function (data) { - filterData(); - }); - }; - - $scope.boardDeleteUndo = function (board) { - BoardService.deleteUndo(board.id).then(function (data) { - filterData(); - }); - }; - -}; - -export default ListController; diff --git a/js/directive/appPopoverMenuUtils.js b/js/directive/appPopoverMenuUtils.js deleted file mode 100644 index 37b495919..000000000 --- a/js/directive/appPopoverMenuUtils.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.directive('appPopoverMenuUtils', function () { - 'use strict'; - return { - restrict: 'C', - link: function (scope, elm) { - var menu = elm.find('.popovermenu'); - var button = elm.find('button'); - button.click(function (e) { - var popovermenus = $('.popovermenu'); - var shouldShow = menu.hasClass('hidden'); - popovermenus.addClass('hidden'); - if (shouldShow) { - menu.toggleClass('hidden'); - } - e.stopPropagation(); - }); - scope.$on('documentClicked', function (scope, event) { - /* prevent closing popover if target has no-close class */ - if (event.target !== button && !$(event.target).hasClass('no-close')) { - menu.addClass('hidden'); - } - }); - } - }; -}); diff --git a/js/directive/appnavigationentryutils.js b/js/directive/appnavigationentryutils.js deleted file mode 100644 index ca9d39557..000000000 --- a/js/directive/appnavigationentryutils.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -import app from '../app/App.js'; -// OwnCloud Click Handling -// https://doc.owncloud.org/server/8.0/developer_manual/app/css.html -app.directive('appNavigationEntryUtils', function () { - 'use strict'; - return { - restrict: 'C', - link: function (scope, elm) { - - var menu = elm.siblings('.app-navigation-entry-menu'); - var 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'); - } - }); - } - }; -}); - diff --git a/js/directive/autofocusoninsert.js b/js/directive/autofocusoninsert.js deleted file mode 100644 index 20aedd299..000000000 --- a/js/directive/autofocusoninsert.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.directive('autofocusOnInsert', function () { - 'use strict'; - return function (scope, elm) { - elm.focus(); - }; -}); \ No newline at end of file diff --git a/js/directive/avatar.js b/js/directive/avatar.js deleted file mode 100644 index 8f20ab3e2..000000000 --- a/js/directive/avatar.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.directive('avatar', function() { - 'use strict'; - return { - restrict: 'AEC', - transclude: true, - replace: true, - template: '
    ', - scope: { attr: '=' }, - link: function(scope, element, attr){ - scope.uid = attr.displayname; - scope.displayname = attr.displayname; - scope.size = attr.size; - if (typeof scope.size === 'undefined') { - scope.size = 32; - } - var value = attr.user; - var avatardiv = $(element).find('.avatardiv'); - if(typeof attr.contactsmenu !== 'undefined' && attr.contactsmenu !== 'false') { - avatardiv.contactsMenu(value, 0, $(element)); - avatardiv.addClass('has-contactsmenu'); - } - if(typeof attr.tooltip !== 'undefined' && attr.tooltip !== 'false') { - $(element).tooltip({ - title: scope.displayname, - placement: 'top' - }); - } - avatardiv.avatar(value, scope.size, false, false, false, attr.displayname); - }, - controller: function () {} - }; -}); diff --git a/js/directive/bindHtmlCompile.js b/js/directive/bindHtmlCompile.js deleted file mode 100644 index dbaa2d5e7..000000000 --- a/js/directive/bindHtmlCompile.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * @copyright Copyright (c) 2018 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.directive('bindHtmlCompile', function ($compile) { - 'use strict'; - - return { - restrict: 'A', - link: function (scope, element, attrs) { - scope.$watch(function () { - return scope.$eval(attrs.bindHtmlCompile); - }, function (value) { - element.html(value); - $compile(element.contents())(scope); - }); - } - }; -}); diff --git a/js/directive/contactsmenudelete.js b/js/directive/contactsmenudelete.js deleted file mode 100644 index dca0c4bf9..000000000 --- a/js/directive/contactsmenudelete.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * @copyright Copyright (c) 2018 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.directive('contactsmenudelete', function() { - 'use strict'; - return { - restrict: 'A', - priority: 1, - link: function(scope, element, attr){ - var user = attr.user; - var menu = $(element).parent().find('.contactsmenu-popover'); - if (oc_current_user === user) { - menu.children(':first').remove(); - } - var menuEntry = $('
  • ' + t('deck', 'Remove user from card') + '
  • '); - menuEntry.on('click', function () { - scope.removeAssignedUser(user); - }); - $(menu).append(menuEntry); - } - }; -}); \ No newline at end of file diff --git a/js/directive/contenteditable.js b/js/directive/contenteditable.js deleted file mode 100644 index abf91d8c1..000000000 --- a/js/directive/contenteditable.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * @copyright Copyright (c) 2018 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -import app from '../app/App'; - -app.directive('ngContenteditable', function($compile) { - return { - require: 'ngModel', - restrict: 'A', - scope: { - submit: '&ngSubmit' - }, - link: function(scope, element, attrs, ngModel) { - - //read the text typed in the div (syncing model with the view) - function read() { - ngModel.$setViewValue(element.html()); - } - - //render the data now in your model into your view - //$render is invoked when the modelvalue differs from the viewvalue - //see documentation: https://docs.angularjs.org/api/ng/type/ngModel.NgModelController# - ngModel.$render = function() { - element.html(ngModel.$viewValue || ''); - }; - - //do this whenever someone starts typing - element.bind('blur keyup change', function(event) { - scope.$apply(read); - }); - - element.bind('keydown', function(event) { - if(event.which === 13 && event.shiftKey) { - scope.submit(); - } - }); - - } - }; -}); diff --git a/js/directive/datepicker.js b/js/directive/datepicker.js deleted file mode 100644 index 74eadae80..000000000 --- a/js/directive/datepicker.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - * @copyright Copyright (c) 2017 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -/* global app */ -/* gloabl t */ -/* global moment */ - -app.directive('datepicker', function () { - 'use strict'; - return { - link: function (scope, elm, attr) { - return elm.datepicker({ - dateFormat: moment.localeData().longDateFormat('L').replace('YYYY', 'YY').toLowerCase(), - onSelect: function(date, inst) { - var selectedDate = $(this).datepicker('getDate'); - scope.setDuedate(moment(selectedDate)); - scope.$apply(); - }, - beforeShow: function(input, inst) { - var dp, marginLeft; - dp = $(inst).datepicker('widget'); - marginLeft = -Math.abs($(input).outerWidth() - dp.outerWidth()) / 2 + 'px'; - dp.css({ - 'margin-left': marginLeft - }); - $('div.ui-datepicker:before').css({ - 'left': 100 + 'px' - }); - return $('.hasDatepicker').datepicker(); - }, - minDate: null - }); - } - }; -}); \ No newline at end of file diff --git a/js/directive/elastic.js b/js/directive/elastic.js deleted file mode 100644 index 4c3b63a23..000000000 --- a/js/directive/elastic.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -// original idea from blockloop: http://stackoverflow.com/a/24090733 -app.directive('elastic', [ - '$timeout', - function($timeout) { - return { - restrict: 'A', - link: function($scope, element) { - $scope.initialHeight = $scope.initialHeight || element[0].style.height; - var resize = function() { - element[0].style.height = $scope.initialHeight; - element[0].style.height = "" + element[0].scrollHeight + "px"; - }; - element.on("input change", resize); - $timeout(resize, 0); - } - }; - } -]); \ No newline at end of file diff --git a/js/directive/search.js b/js/directive/search.js deleted file mode 100644 index 5478e0204..000000000 --- a/js/directive/search.js +++ /dev/null @@ -1,61 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.directive('search', function ($document, $location) { - 'use strict'; - - return { - restrict: 'E', - scope: { - 'onSearch': '=' - }, - link: function (scope) { - if (OCA.Search && OCA.Search.Core) { - // eslint-disable-next-line no-unused-vars - const search = new OCA.Search((term) => { - scope.$apply(function () { - scope.onSearch(term); - }); - }, () => { - scope.$apply(function () { - scope.onSearch(''); - }); - }); - } else { - const box = $('#searchbox'); - box.val($location.search().search); - - var doSearch = function () { - var value = box.val(); - scope.$apply(function () { - scope.onSearch(value); - }); - }; - - box.on('search keyup', function (event) { - doSearch(); - }); - } - } - }; -}); diff --git a/js/directive/timepicker.js b/js/directive/timepicker.js deleted file mode 100644 index a39dff033..000000000 --- a/js/directive/timepicker.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * @copyright Copyright (c) 2017 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; -import '../legacy/jquery.ui.timepicker.js'; -import 'legacy/jquery.ui.timepicker.css'; - -/* global app */ -/* global t */ -/* global moment */ - -app.directive('timepicker', function() { - 'use strict'; - return { - restrict: 'A', - link: function(scope, elm, attr) { - return $(elm).timepicker({ - onSelect: function(date, inst) { - scope.setDuedateTime(moment('2000-01-01 ' + date)); - scope.$apply(); - }, - myPosition: 'center top', - atPosition: 'center bottom', - hourText: t('deck', 'Hours'), - minuteText: t('deck', 'Minutes'), - showPeriodLabels: false - }); - } - }; -}); diff --git a/js/filters/boardFilterAcl.js b/js/filters/boardFilterAcl.js deleted file mode 100644 index bbb3cf481..000000000 --- a/js/filters/boardFilterAcl.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * @copyright Copyright (c) 2017 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.filter('boardFilterAcl', function() { - return function(boards) { - var _result = []; - angular.forEach(boards, function(board){ - if(board.acl !== null && Object.keys(board.acl).length > 0) { - _result.push(board); - } - }); - return _result; - }; -}); \ No newline at end of file diff --git a/js/filters/bytesFilter.js b/js/filters/bytesFilter.js deleted file mode 100644 index 67d2ce6ab..000000000 --- a/js/filters/bytesFilter.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * @copyright Copyright (c) 2018 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -import app from '../app/App.js'; - -app.filter('bytes', function () { - return function (bytes, precision) { - if (isNaN(parseFloat(bytes, 10)) || !isFinite(bytes)) { - return '-'; - } - if (typeof precision === 'undefined') { - precision = 2; - } - var units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'], - number = Math.floor(Math.log(bytes) / Math.log(1024)); - return (bytes / Math.pow(1024, Math.floor(number))).toFixed(precision) + ' ' + units[number]; - }; -}); \ No newline at end of file diff --git a/js/filters/cardFilter.js b/js/filters/cardFilter.js deleted file mode 100644 index d8be5e5c1..000000000 --- a/js/filters/cardFilter.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -// usage | cardFilter({ member: 'admin'}) - -app.filter('cardFilter', function() { - return function(cards, rules) { - var _result = []; - angular.forEach(cards, function(card){ - var _card = card; - var keys = Object.keys(rules); - keys.some(function(key, condition) { - if(_card[key]===rules[key]) { - _result.push(_card); - } - }); - }); - return _result; - }; -}); \ No newline at end of file diff --git a/js/filters/cardSearchFilter.js b/js/filters/cardSearchFilter.js deleted file mode 100644 index 3c8edf13b..000000000 --- a/js/filters/cardSearchFilter.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.filter('cardSearchFilter', function() { - return function(cards, searchString) { - var _result = {}; - var rules = { - title: searchString, - //owner: searchString, - }; - angular.forEach(cards, function(card){ - var _card = card; - Object.keys(rules).some(function(rule) { - if(_card[rule].search(rules[rule])>=0) { - _result[_card.id] = _card; - } - }); - }); - - return $.map(_result, function(value, index) { - return [value]; - }); - }; -}); \ No newline at end of file diff --git a/js/filters/dateFilters.js b/js/filters/dateFilters.js deleted file mode 100644 index 0f5c4ff99..000000000 --- a/js/filters/dateFilters.js +++ /dev/null @@ -1,63 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -/* global app */ -/* global OC */ -/* global moment */ - -app.filter('relativeDateFilter', function() { - return function (timestamp) { - return OC.Util.relativeModifiedDate(timestamp*1000); - }; -}); - -app.filter('relativeDateFilterString', function() { - return function (date) { - return OC.Util.relativeModifiedDate(Date.parse(date)); - }; -}); - -app.filter('dateToTimestamp', function() { - return function (date) { - return Date.parse(date); - }; -}); - -app.filter('parseDate', function() { - return function (date) { - if(moment(date).isValid()) { - var dateFormat = moment.localeData().longDateFormat('L'); - return moment(date).format(dateFormat); - } - return ''; - }; -}); - -app.filter('parseTime', function() { - return function (date) { - if(moment(date).isValid()) { - return moment(date).format('HH:mm'); - } - return ''; - }; -}); \ No newline at end of file diff --git a/js/filters/iconWhiteFilter.js b/js/filters/iconWhiteFilter.js deleted file mode 100644 index 0a699ce13..000000000 --- a/js/filters/iconWhiteFilter.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.filter('iconWhiteFilter', function () { - return function (hex) { - // RGB2HLS by Garry Tan - // http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c - var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); - var color = result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; - if (result === null) { - return ''; - } - var r = color.r / 255; - var g = color.g / 255; - var b = color.b / 255; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, l = (max + min) / 2; - - if (max === min) { - h = s = 0; // achromatic - } else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - if (l < 0.5) { - return '-white'; - } else { - return ''; - } - }; -}); diff --git a/js/filters/lightenColorFilter.js b/js/filters/lightenColorFilter.js deleted file mode 100644 index 770866ed6..000000000 --- a/js/filters/lightenColorFilter.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.filter('lightenColorFilter', function() { - return function (hex) { - var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); - var color = result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; - if (result !== null) { - return 'rgba(' + color.r + ',' + color.g + ',' + color.b + ',0.7)'; - } else { - return '#' + hex; - } - }; -}); diff --git a/js/filters/orderObjectBy.js b/js/filters/orderObjectBy.js deleted file mode 100644 index 151b6a1b8..000000000 --- a/js/filters/orderObjectBy.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.filter('orderObjectBy', function(){ - return function(input, attribute) { - if (!angular.isObject(input)) { - return input; - } - var array = []; - for(var objectKey in input) { - if ({}.hasOwnProperty.call(input, objectKey)) { - array.push(input[objectKey]); - } - } - - array.sort(function(a, b){ - a = parseInt(a[attribute]); - b = parseInt(b[attribute]); - return a < b; - }); - return array; - }; -}); \ No newline at end of file diff --git a/js/filters/textColorFilter.js b/js/filters/textColorFilter.js deleted file mode 100644 index c2bb5bccb..000000000 --- a/js/filters/textColorFilter.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * @copyright Copyright (c) 2016 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -app.filter('textColorFilter', function () { - return function (hex) { - // RGB2HLS by Garry Tan - // http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c - var result = /^#?([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); - var color = result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; - if (result !== null) { - var r = color.r / 255; - var g = color.g / 255; - var b = color.b / 255; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, l = (max + min) / 2; - - if (max === min) { - h = s = 0; // achromatic - } else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - if (l < 0.5) { - return '#ffffff'; - } else { - return '#000000'; - } - } else { - return '#000000'; - } - - }; -}); diff --git a/js/filters/withoutAssignedUsers.js b/js/filters/withoutAssignedUsers.js deleted file mode 100644 index 49a51de9e..000000000 --- a/js/filters/withoutAssignedUsers.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * @copyright Copyright (c) 2017 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -import app from '../app/App.js'; - -/* global app */ -/* global angular */ - -/* - * Remove all assignedUsers from users list - */ -app.filter('withoutAssignedUsers', function () { - return function (users, assignedUsers) { - var _result = []; - angular.forEach(users, function (user) { - var _found = false; - angular.forEach(assignedUsers, function (assignedUser) { - if (assignedUser.participant.uid === user.uid) { - _found = true; - } - }); - if (_found === false) { - _result.push(user); - } - }); - return _result; - }; -}); \ No newline at end of file diff --git a/js/init-collections.js b/js/init-collections.js deleted file mode 100644 index 9a6d06911..000000000 --- a/js/init-collections.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * @copyright Copyright (c) 2019 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ - -'use strict'; - -/* global __webpack_nonce__ __webpack_public_path__ OC t n */ -// eslint-disable-next-line -__webpack_nonce__ = btoa(OC.requestToken); -// eslint-disable-next-line -__webpack_public_path__ = OC.linkTo('deck', 'js/build/'); - -import Vue from 'vue'; - -Vue.prototype.t = t; -Vue.prototype.n = n; -Vue.prototype.OC = OC; - -import BoardSelector from './views/BoardSelector'; - -import './../css/collections.css'; - -((function(OCP) { - - OCP.Collaboration.registerType('deck', { - action: () => { - return new Promise((resolve, reject) => { - const container = document.createElement('div'); - container.id = 'deck-board-select'; - const body = document.getElementById('body-user'); - body.append(container); - const ComponentVM = new Vue({ - render: h => h(BoardSelector), - }); - ComponentVM.$mount(container); - ComponentVM.$root.$on('close', () => { - ComponentVM.$el.remove(); - ComponentVM.$destroy(); - reject(); - }); - ComponentVM.$root.$on('select', (id) => { - resolve(id); - ComponentVM.$el.remove(); - ComponentVM.$destroy(); - }); - }); - }, - typeString: t('deck', 'Link to a board'), - typeIconClass: 'icon-deck' - }); -})(window.OCP)); diff --git a/js/init.js b/js/init.js deleted file mode 100644 index 0c93ea624..000000000 --- a/js/init.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -import "@babel/polyfill"; - -/* global __webpack_nonce__ __webpack_public_path__ OC t n */ -// eslint-disable-next-line -__webpack_nonce__ = btoa(OC.requestToken); -// eslint-disable-next-line -__webpack_public_path__ = OC.linkTo('deck', 'js/build/'); - -// used for building a vendor stylesheet -import 'ng-sortable/dist/ng-sortable.css'; - -import angular from 'angular'; -import markdownit from 'markdown-it'; -global.markdownit = markdownit; - -import app from './app/App.js'; -import './app/Config.js'; -import './app/Run.js'; - - -import ListController from 'controller/ListController.js'; -import attachmentListComponent from './controller/AttachmentController.js'; -import activityComponent from './controller/ActivityController.js'; - -app.controller('ListController', ListController); -app.component('attachmentListComponent', attachmentListComponent); -app.component('activityComponent', activityComponent); - - -// require all the js files from subdirectories -var context = require.context('.', true, /(controller|service|filters|directive)\/(.*)\.js$/); - -context.keys().forEach(function (key) { - context(key); -}); - diff --git a/js/legacy/commentcollection.js b/js/legacy/commentcollection.js deleted file mode 100644 index 6c7427abf..000000000 --- a/js/legacy/commentcollection.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @licence - */ - -import CommentModel from './commentmodel.js'; -import CommentSummaryModel from './commentsummarymodel.js'; - -/** - * @class CommentCollection - * @classdesc - * - * Collection of comments assigned to a file - * - */ -var CommentCollection = OC.Backbone.Collection.extend( - /** @lends OCA.AnnouncementCenter.Comments.CommentCollection.prototype */ { - - sync: OC.Backbone.davSync, - - model: CommentModel, - - /** - * Object type - * - * @type string - */ - _objectType: 'deckCard', - - /** - * Object id - * - * @type string - */ - _objectId: null, - - /** - * True if there are no more page results left to fetch - * - * @type bool - */ - _endReached: false, - - /** - * Number of comments to fetch per page - * - * @type int - */ - _limit : 5, - - /** - * Initializes the collection - * - * @param {string} [options.objectType] object type - * @param {string} [options.objectId] object id - */ - initialize: function(models, options) { - options = options || {}; - if (options.objectType) { - this._objectType = options.objectType; - } - if (options.objectId) { - this._objectId = options.objectId; - } - }, - - url: function() { - return OC.linkToRemote('dav') + '/comments/' + - encodeURIComponent(this._objectType) + '/' + - encodeURIComponent(this._objectId) + '/'; - }, - - setObjectId: function(objectId) { - this._objectId = objectId; - }, - - hasMoreResults: function() { - return !this._endReached; - }, - - reset: function() { - this._endReached = false; - this._summaryModel = null; - return OC.Backbone.Collection.prototype.reset.apply(this, arguments); - }, - - /** - * Fetch the next set of results - */ - fetchNext: function(options) { - var self = this; - if (!this.hasMoreResults()) { - return null; - } - - var body = '\n' + - '\n' + - // load one more so we know there is more - ' ' + (this._limit + 1) + '\n' + - ' ' + this.length + '\n' + - '\n'; - - options = options || {}; - var success = options.success; - options = _.extend({ - remove: false, - parse: true, - data: body, - davProperties: CommentCollection.prototype.model.prototype.davProperties, - success: function(resp) { - if (resp.length <= self._limit) { - // no new entries, end reached - self._endReached = true; - } else { - // remove last entry, for next page load - resp = _.initial(resp); - } - if (!self.set(resp, options)) { - return false; - } - if (success) { - success.apply(null, arguments); - } - self.trigger('sync', 'REPORT', self, options); - } - }, options); - - return this.sync('REPORT', this, options); - }, - - /** - * Returns the matching summary model - * - * @return {OCA.AnnouncementCenter.Comments.CommentSummaryModel} summary model - */ - getSummaryModel: function() { - if (!this._summaryModel) { - this._summaryModel = new CommentSummaryModel({ - id: this._objectId, - objectType: this._objectType - }); - } - return this._summaryModel; - }, - - /** - * Updates the read marker for this comment thread - * - * @param {Date} [date] optional date, defaults to now - * @param {Object} [options] backbone options - */ - updateReadMarker: function(date, options) { - options = options || {}; - - return this.getSummaryModel().save({ - readMarker: (date || new Date()).toUTCString() - }, options); - } -}); - -export default CommentCollection; - diff --git a/js/legacy/commentmodel.js b/js/legacy/commentmodel.js deleted file mode 100644 index 1cf5c6bc3..000000000 --- a/js/legacy/commentmodel.js +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2016 - * - * This file is licensed under the Affero General Public License version 3 - * or later. - * - * See the COPYING-README file. - * - */ - -var NS_OWNCLOUD = 'http://owncloud.org/ns'; -/** - * @class CommentModel - * @classdesc - * - * Comment - * - */ -var CommentModel = OC.Backbone.Model.extend( - /** @lends OCA.Comments.CommentModel.prototype */ { - sync: OC.Backbone.davSync, - - /** - * Object type - * - * @type string - */ - _objectType: 'deckCard', - - /** - * Object id - * - * @type string - */ - _objectId: null, - - initialize: function(model, options) { - options = options || {}; - if (options.objectType) { - this._objectType = options.objectType; - } - if (options.objectId) { - this._objectId = options.objectId; - } - }, - - defaults: { - actorType: 'users', - objectType: 'deckCard' - }, - - davProperties: { - 'id': '{' + NS_OWNCLOUD + '}id', - 'message': '{' + NS_OWNCLOUD + '}message', - 'actorType': '{' + NS_OWNCLOUD + '}actorType', - 'actorId': '{' + NS_OWNCLOUD + '}actorId', - 'actorDisplayName': '{' + NS_OWNCLOUD + '}actorDisplayName', - 'creationDateTime': '{' + NS_OWNCLOUD + '}creationDateTime', - 'objectType': '{' + NS_OWNCLOUD + '}objectType', - 'objectId': '{' + NS_OWNCLOUD + '}objectId', - 'isUnread': '{' + NS_OWNCLOUD + '}isUnread', - 'mentions': '{' + NS_OWNCLOUD + '}mentions' - }, - - parse: function(data) { - return { - id: data.id, - message: data.message, - actorType: data.actorType, - actorId: data.actorId, - actorDisplayName: data.actorDisplayName, - creationDateTime: data.creationDateTime, - objectType: data.objectType, - objectId: data.objectId, - isUnread: (data.isUnread === 'true'), - mentions: this._parseMentions(data.mentions) - }; - }, - - _parseMentions: function(mentions) { - if(_.isUndefined(mentions)) { - return {}; - } - var result = {}; - for(var i in mentions) { - var mention = mentions[i]; - if(_.isUndefined(mention.localName) || mention.localName !== 'mention') { - continue; - } - result[i] = {}; - for (var child = mention.firstChild; child; child = child.nextSibling) { - if(_.isUndefined(child.localName) || !child.localName.startsWith('mention')) { - continue; - } - result[i][child.localName] = child.textContent; - } - } - return result; - }, - - url: function() { - let baseUrl; - if (typeof this.collection === 'undefined') { - baseUrl = OC.linkToRemote('dav') + '/comments/' + - encodeURIComponent(this.get('objectType')) + '/' + - encodeURIComponent(this.get('objectId')) + '/'; - } else { - baseUrl = this.collection.url(); - } - if (typeof this.get('id') !== 'undefined') { - return baseUrl + this.get('id'); - } else { - return baseUrl; - } - } -}); - -export default CommentModel; - diff --git a/js/legacy/commentsummarymodel.js b/js/legacy/commentsummarymodel.js deleted file mode 100644 index ca80d329c..000000000 --- a/js/legacy/commentsummarymodel.js +++ /dev/null @@ -1,54 +0,0 @@ - -var NS_OWNCLOUD = 'http://owncloud.org/ns'; -/** - * @class OCA.AnnouncementCenter.Comments.CommentSummaryModel - * @classdesc - * - * Model containing summary information related to comments - * like the read marker. - * - */ -var CommentSummaryModel = OC.Backbone.Model.extend( - /** @lends OCA.AnnouncementCenter.Comments.CommentSummaryModel.prototype */ { - sync: OC.Backbone.davSync, - - /** - * Object type - * - * @type string - */ - _objectType: 'deckCard', - - /** - * Object id - * - * @type string - */ - _objectId: null, - - davProperties: { - 'readMarker': '{' + NS_OWNCLOUD + '}readMarker' - }, - - /** - * Initializes the summary model - * - * @param {string} [options.objectType] object type - * @param {string} [options.objectId] object id - */ - initialize: function(attrs, options) { - options = options || {}; - if (options.objectType) { - this._objectType = options.objectType; - } - }, - - url: function() { - return OC.linkToRemote('dav') + '/comments/' + - encodeURIComponent(this._objectType) + '/' + - encodeURIComponent(this.id) + '/'; - } -}); - -export default CommentSummaryModel; - diff --git a/js/legacy/jquery.atwho.min.js b/js/legacy/jquery.atwho.min.js deleted file mode 100644 index d1e60152b..000000000 --- a/js/legacy/jquery.atwho.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(t,e){"function"==typeof define&&define.amd?define(["jquery"],function(t){return e(t)}):"object"==typeof exports?module.exports=e(require("jquery")):e(jQuery)}(this,function(t){var e,i;i={ESC:27,TAB:9,ENTER:13,CTRL:17,A:65,P:80,N:78,LEFT:37,UP:38,RIGHT:39,DOWN:40,BACKSPACE:8,SPACE:32},e={beforeSave:function(t){return r.arrayToDefaultHash(t)},matcher:function(t,e,i,n){var r,o,s,a,h;return t=t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),i&&(t="(?:^|\\s)"+t),r=decodeURI("%C3%80"),o=decodeURI("%C3%BF"),h=n?" ":"",a=new RegExp(t+"([A-Za-z"+r+"-"+o+"0-9_"+h+"'.+-]*)$|"+t+"([^\\x00-\\xff]*)$","gi"),s=a.exec(e),s?s[2]||s[1]:null},filter:function(t,e,i){var n,r,o,s;for(n=[],r=0,s=e.length;s>r;r++)o=e[r],~new String(o[i]).toLowerCase().indexOf(t.toLowerCase())&&n.push(o);return n},remoteFilter:null,sorter:function(t,e,i){var n,r,o,s;if(!t)return e;for(n=[],r=0,s=e.length;s>r;r++)o=e[r],o.atwho_order=new String(o[i]).toLowerCase().indexOf(t.toLowerCase()),o.atwho_order>-1&&n.push(o);return n.sort(function(t,e){return t.atwho_order-e.atwho_order})},tplEval:function(t,e){var i,n,r;r=t;try{return"string"!=typeof t&&(r=t(e)),r.replace(/\$\{([^\}]*)\}/g,function(t,i,n){return e[i]})}catch(n){return i=n,""}},highlighter:function(t,e){var i;return e?(i=new RegExp(">\\s*([^<]*?)("+e.replace("+","\\+")+")([^<]*)\\s*<","ig"),t.replace(i,function(t,e,i,n){return"> "+e+""+i+""+n+" <"})):t},beforeInsert:function(t,e,i){return t},beforeReposition:function(t){return t},afterMatchFailed:function(t,e){}};var n;n=function(){function e(e){this.currentFlag=null,this.controllers={},this.aliasMaps={},this.$inputor=t(e),this.setupRootElement(),this.listen()}return e.prototype.createContainer=function(e){var i;return null!=(i=this.$el)&&i.remove(),t(e.body).append(this.$el=t("
    "))},e.prototype.setupRootElement=function(e,i){var n,r;if(null==i&&(i=!1),e)this.window=e.contentWindow,this.document=e.contentDocument||this.window.document,this.iframe=e;else{this.document=this.$inputor[0].ownerDocument,this.window=this.document.defaultView||this.document.parentWindow;try{this.iframe=this.window.frameElement}catch(r){if(n=r,this.iframe=null,t.fn.atwho.debug)throw new Error("iframe auto-discovery is failed.\nPlease use `setIframe` to set the target iframe manually.\n"+n)}}return this.createContainer((this.iframeAsRoot=i)?this.document:document)},e.prototype.controller=function(t){var e,i,n,r;if(this.aliasMaps[t])i=this.controllers[this.aliasMaps[t]];else{r=this.controllers;for(n in r)if(e=r[n],n===t){i=e;break}}return i?i:this.controllers[this.currentFlag]},e.prototype.setContextFor=function(t){return this.currentFlag=t,this},e.prototype.reg=function(t,e){var i,n;return n=(i=this.controllers)[t]||(i[t]=this.$inputor.is("[contentEditable]")?new l(this,t):new s(this,t)),e.alias&&(this.aliasMaps[e.alias]=t),n.init(e),this},e.prototype.listen=function(){return this.$inputor.on("compositionstart",function(t){return function(e){var i;return null!=(i=t.controller())&&i.view.hide(),t.isComposing=!0,null}}(this)).on("compositionend",function(t){return function(e){return t.isComposing=!1,setTimeout(function(e){return t.dispatch(e)}),null}}(this)).on("keyup.atwhoInner",function(t){return function(e){return t.onKeyup(e)}}(this)).on("keydown.atwhoInner",function(t){return function(e){return t.onKeydown(e)}}(this)).on("blur.atwhoInner",function(t){return function(e){var i;return(i=t.controller())?(i.expectedQueryCBId=null,i.view.hide(e,i.getOpt("displayTimeout"))):void 0}}(this)).on("click.atwhoInner",function(t){return function(e){return t.dispatch(e)}}(this)).on("scroll.atwhoInner",function(t){return function(){var e;return e=t.$inputor.scrollTop(),function(i){var n,r;return n=i.target.scrollTop,e!==n&&null!=(r=t.controller())&&r.view.hide(i),e=n,!0}}}(this)())},e.prototype.shutdown=function(){var t,e,i;i=this.controllers;for(t in i)e=i[t],e.destroy(),delete this.controllers[t];return this.$inputor.off(".atwhoInner"),this.$el.remove()},e.prototype.dispatch=function(t){var e,i,n,r;n=this.controllers,r=[];for(e in n)i=n[e],r.push(i.lookUp(t));return r},e.prototype.onKeyup=function(e){var n;switch(e.keyCode){case i.ESC:e.preventDefault(),null!=(n=this.controller())&&n.view.hide();break;case i.DOWN:case i.UP:case i.CTRL:case i.ENTER:t.noop();break;case i.P:case i.N:e.ctrlKey||this.dispatch(e);break;default:this.dispatch(e)}},e.prototype.onKeydown=function(e){var n,r;if(r=null!=(n=this.controller())?n.view:void 0,r&&r.visible())switch(e.keyCode){case i.ESC:e.preventDefault(),r.hide(e);break;case i.UP:e.preventDefault(),r.prev();break;case i.DOWN:e.preventDefault(),r.next();break;case i.P:if(!e.ctrlKey)return;e.preventDefault(),r.prev();break;case i.N:if(!e.ctrlKey)return;e.preventDefault(),r.next();break;case i.TAB:case i.ENTER:case i.SPACE:if(!r.visible())return;if(!this.controller().getOpt("spaceSelectsMatch")&&e.keyCode===i.SPACE)return;if(!this.controller().getOpt("tabSelectsMatch")&&e.keyCode===i.TAB)return;r.highlighted()?(e.preventDefault(),r.choose(e)):r.hide(e);break;default:t.noop()}},e}();var r,o=[].slice;r=function(){function i(e,i){this.app=e,this.at=i,this.$inputor=this.app.$inputor,this.id=this.$inputor[0].id||this.uid(),this.expectedQueryCBId=null,this.setting=null,this.query=null,this.pos=0,this.range=null,0===(this.$el=t("#atwho-ground-"+this.id,this.app.$el)).length&&this.app.$el.append(this.$el=t("
    ")),this.model=new u(this),this.view=new c(this)}return i.prototype.uid=function(){return(Math.random().toString(16)+"000000000").substr(2,8)+(new Date).getTime()},i.prototype.init=function(e){return this.setting=t.extend({},this.setting||t.fn.atwho["default"],e),this.view.init(),this.model.reload(this.setting.data)},i.prototype.destroy=function(){return this.trigger("beforeDestroy"),this.model.destroy(),this.view.destroy(),this.$el.remove()},i.prototype.callDefault=function(){var i,n,r,s;s=arguments[0],i=2<=arguments.length?o.call(arguments,1):[];try{return e[s].apply(this,i)}catch(r){return n=r,t.error(n+" Or maybe At.js doesn't have function "+s)}},i.prototype.trigger=function(t,e){var i,n;return null==e&&(e=[]),e.push(this),i=this.getOpt("alias"),n=i?t+"-"+i+".atwho":t+".atwho",this.$inputor.trigger(n,e)},i.prototype.callbacks=function(t){return this.getOpt("callbacks")[t]||e[t]},i.prototype.getOpt=function(t,e){var i,n;try{return this.setting[t]}catch(n){return i=n,null}},i.prototype.insertContentFor=function(e){var i,n;return n=this.getOpt("insertTpl"),i=t.extend({},e.data("item-data"),{"atwho-at":this.at}),this.callbacks("tplEval").call(this,n,i,"onInsert")},i.prototype.renderView=function(t){var e;return e=this.getOpt("searchKey"),t=this.callbacks("sorter").call(this,this.query.text,t.slice(0,1001),e),this.view.render(t.slice(0,this.getOpt("limit")))},i.arrayToDefaultHash=function(e){var i,n,r,o;if(!t.isArray(e))return e;for(o=[],i=0,r=e.length;r>i;i++)n=e[i],t.isPlainObject(n)?o.push(n):o.push({name:n});return o},i.prototype.lookUp=function(t){var e,i;if((!t||"click"!==t.type||this.getOpt("lookUpOnClick"))&&(!this.getOpt("suspendOnComposing")||!this.app.isComposing))return(e=this.catchQuery(t))?(this.app.setContextFor(this.at),(i=this.getOpt("delay"))?this._delayLookUp(e,i):this._lookUp(e),e):(this.expectedQueryCBId=null,e)},i.prototype._delayLookUp=function(t,e){var i,n;return i=Date.now?Date.now():(new Date).getTime(),this.previousCallTime||(this.previousCallTime=i),n=e-(i-this.previousCallTime),n>0&&e>n?(this.previousCallTime=i,this._stopDelayedCall(),this.delayedCallTimeout=setTimeout(function(e){return function(){return e.previousCallTime=0,e.delayedCallTimeout=null,e._lookUp(t)}}(this),e)):(this._stopDelayedCall(),this.previousCallTime!==i&&(this.previousCallTime=0),this._lookUp(t))},i.prototype._stopDelayedCall=function(){return this.delayedCallTimeout?(clearTimeout(this.delayedCallTimeout),this.delayedCallTimeout=null):void 0},i.prototype._generateQueryCBId=function(){return{}},i.prototype._lookUp=function(e){var i;return i=function(t,e){return t===this.expectedQueryCBId?e&&e.length>0?this.renderView(this.constructor.arrayToDefaultHash(e)):this.view.hide():void 0},this.expectedQueryCBId=this._generateQueryCBId(),this.model.query(e.text,t.proxy(i,this,this.expectedQueryCBId))},i}();var s,a=function(t,e){function i(){this.constructor=t}for(var n in e)h.call(e,n)&&(t[n]=e[n]);return i.prototype=e.prototype,t.prototype=new i,t.__super__=e.prototype,t},h={}.hasOwnProperty;s=function(e){function i(){return i.__super__.constructor.apply(this,arguments)}return a(i,e),i.prototype.catchQuery=function(){var t,e,i,n,r,o,s;return e=this.$inputor.val(),t=this.$inputor.caret("pos",{iframe:this.app.iframe}),s=e.slice(0,t),r=this.callbacks("matcher").call(this,this.at,s,this.getOpt("startWithSpace"),this.getOpt("acceptSpaceBar")),n="string"==typeof r,n&&r.length0?t.getRangeAt(0):void 0},n.prototype._setRange=function(e,i,n){return null==n&&(n=this._getRange()),n&&i?(i=t(i)[0],"after"===e?(n.setEndAfter(i),n.setStartAfter(i)):(n.setEndBefore(i),n.setStartBefore(i)),n.collapse(!1),this._clearRange(n)):void 0},n.prototype._clearRange=function(t){var e;return null==t&&(t=this._getRange()),e=this.app.window.getSelection(),null==this.ctrl_a_pressed?(e.removeAllRanges(),e.addRange(t)):void 0},n.prototype._movingEvent=function(t){var e;return"click"===t.type||(e=t.which)===i.RIGHT||e===i.LEFT||e===i.UP||e===i.DOWN},n.prototype._unwrap=function(e){var i;return e=t(e).unwrap().get(0),(i=e.nextSibling)&&i.nodeValue&&(e.nodeValue+=i.nodeValue,t(i).remove()),e},n.prototype.catchQuery=function(e){var n,r,o,s,a,h,l,u,c,p,f,d;if((d=this._getRange())&&d.collapsed){if(e.which===i.ENTER)return(r=t(d.startContainer).closest(".atwho-query")).contents().unwrap(),r.is(":empty")&&r.remove(),(r=t(".atwho-query",this.app.document)).text(r.text()).contents().last().unwrap(),void this._clearRange();if(/firefox/i.test(navigator.userAgent)){if(t(d.startContainer).is(this.$inputor))return void this._clearRange();e.which===i.BACKSPACE&&d.startContainer.nodeType===document.ELEMENT_NODE&&(c=d.startOffset-1)>=0?(o=d.cloneRange(),o.setStart(d.startContainer,c),t(o.cloneContents()).contents().last().is(".atwho-inserted")&&(a=t(d.startContainer).contents().get(c),this._setRange("after",t(a).contents().last()))):e.which===i.LEFT&&d.startContainer.nodeType===document.TEXT_NODE&&(n=t(d.startContainer.previousSibling),n.is(".atwho-inserted")&&0===d.startOffset&&this._setRange("after",n.contents().last()))}if(t(d.startContainer).closest(".atwho-inserted").addClass("atwho-query").siblings().removeClass("atwho-query"),(r=t(".atwho-query",this.app.document)).length>0&&r.is(":empty")&&0===r.text().length&&r.remove(),this._movingEvent(e)||r.removeClass("atwho-inserted"),r.length>0)switch(e.which){case i.LEFT:return this._setRange("before",r.get(0),d),void r.removeClass("atwho-query");case i.RIGHT:return this._setRange("after",r.get(0).nextSibling,d),void r.removeClass("atwho-query")}if(r.length>0&&(f=r.attr("data-atwho-at-query"))&&(r.empty().html(f).attr("data-atwho-at-query",null),this._setRange("after",r.get(0),d)),o=d.cloneRange(),o.setStart(d.startContainer,0),u=this.callbacks("matcher").call(this,this.at,o.toString(),this.getOpt("startWithSpace"),this.getOpt("acceptSpaceBar")),h="string"==typeof u,0===r.length&&h&&(s=d.startOffset-this.at.length-u.length)>=0&&(d.setStart(d.startContainer,s),r=t("",this.app.document).attr(this.getOpt("editableAtwhoQueryAttrs")).addClass("atwho-query"),d.surroundContents(r.get(0)),l=r.contents().last().get(0),l&&(/firefox/i.test(navigator.userAgent)?(d.setStart(l,l.length),d.setEnd(l,l.length),this._clearRange(d)):this._setRange("after",l,d))),!(h&&u.length=0&&(this._movingEvent(e)&&r.hasClass("atwho-inserted")?r.removeClass("atwho-query"):!1!==this.callbacks("afterMatchFailed").call(this,this.at,r)&&this._setRange("after",this._unwrap(r.text(r.text()).contents().first()))),null)}},n.prototype.rect=function(){var e,i,n;return n=this.query.el.offset(),n&&this.query.el[0].getClientRects().length?(this.app.iframe&&!this.app.iframeAsRoot&&(i=(e=t(this.app.iframe)).offset(),n.left+=i.left-this.$inputor.scrollLeft(),n.top+=i.top-this.$inputor.scrollTop()),n.bottom=n.top+this.query.el.height(),n):void 0},n.prototype.insert=function(t,e){var i,n,r,o,s;return this.$inputor.is(":focus")||this.$inputor.focus(),n=this.getOpt("functionOverrides"),n.insert?n.insert.call(this,t,e):(o=""===(o=this.getOpt("suffix"))?o:o||" ",i=e.data("item-data"),this.query.el.removeClass("atwho-query").addClass("atwho-inserted").html(t).attr("data-atwho-at-query",""+i["atwho-at"]+this.query.text).attr("contenteditable","false"),(r=this._getRange())&&(this.query.el.length&&r.setEndAfter(this.query.el[0]),r.collapse(!1),r.insertNode(s=this.app.document.createTextNode(""+o)),this._setRange("after",s,r)),this.$inputor.is(":focus")||this.$inputor.focus(),this.$inputor.change())},n}(r);var u;u=function(){function e(t){this.context=t,this.at=this.context.at,this.storage=this.context.$inputor}return e.prototype.destroy=function(){return this.storage.data(this.at,null)},e.prototype.saved=function(){return this.fetch()>0},e.prototype.query=function(t,e){var i,n,r;return n=this.fetch(),r=this.context.getOpt("searchKey"),n=this.context.callbacks("filter").call(this.context,t,n,r)||[],i=this.context.callbacks("remoteFilter"),n.length>0||!i&&0===n.length?e(n):i.call(this.context,t,e)},e.prototype.fetch=function(){return this.storage.data(this.at)||[]},e.prototype.save=function(t){return this.storage.data(this.at,this.context.callbacks("beforeSave").call(this.context,t||[]))},e.prototype.load=function(t){return!this.saved()&&t?this._load(t):void 0},e.prototype.reload=function(t){return this._load(t)},e.prototype._load=function(e){return"string"==typeof e?t.ajax(e,{dataType:"json"}).done(function(t){return function(e){return t.save(e)}}(this)):this.save(e)},e}();var c;c=function(){function e(e){this.context=e,this.$el=t("
      "),this.$elUl=this.$el.children(),this.timeoutID=null,this.context.$el.append(this.$el),this.bindEvent()}return e.prototype.init=function(){var t,e;return e=this.context.getOpt("alias")||this.context.at.charCodeAt(0),t=this.context.getOpt("headerTpl"),t&&1===this.$el.children().length&&this.$el.prepend(t),this.$el.attr({id:"at-view-"+e})},e.prototype.destroy=function(){return this.$el.remove()},e.prototype.bindEvent=function(){var e,i,n;return e=this.$el.find("ul"),i=0,n=0,e.on("mousemove.atwho-view","li",function(r){return function(r){var o;if((i!==r.clientX||n!==r.clientY)&&(i=r.clientX,n=r.clientY,o=t(r.currentTarget),!o.hasClass("cur")))return e.find(".cur").removeClass("cur"),o.addClass("cur")}}(this)).on("click.atwho-view","li",function(i){return function(n){return e.find(".cur").removeClass("cur"),t(n.currentTarget).addClass("cur"),i.choose(n),n.preventDefault()}}(this))},e.prototype.visible=function(){return t.expr.filters.visible(this.$el[0])},e.prototype.highlighted=function(){return this.$el.find(".cur").length>0},e.prototype.choose=function(t){var e,i;return(e=this.$el.find(".cur")).length&&(i=this.context.insertContentFor(e),this.context._stopDelayedCall(),this.context.insert(this.context.callbacks("beforeInsert").call(this.context,i,e,t),e),this.context.trigger("inserted",[e,t]),this.hide(t)),this.context.getOpt("hideWithoutSuffix")?this.stopShowing=!0:void 0},e.prototype.reposition=function(e){var i,n,r,o;return i=this.context.app.iframeAsRoot?this.context.app.window:window,e.bottom+this.$el.height()-t(i).scrollTop()>t(i).height()&&(e.bottom=e.top-this.$el.height()),e.left>(r=t(i).width()-this.$el.width()-5)&&(e.left=r),n={left:e.left,top:e.bottom},null!=(o=this.context.callbacks("beforeReposition"))&&o.call(this.context,n),this.$el.offset(n),this.context.trigger("reposition",[n])},e.prototype.next=function(){var t,e,i,n;return t=this.$el.find(".cur").removeClass("cur"),e=t.next(),e.length||(e=this.$el.find("li:first")),e.addClass("cur"),i=e[0],n=i.offsetTop+i.offsetHeight+(i.nextSibling?i.nextSibling.offsetHeight:0),this.scrollTop(Math.max(0,n-this.$el.height()))},e.prototype.prev=function(){var t,e,i,n;return t=this.$el.find(".cur").removeClass("cur"),i=t.prev(),i.length||(i=this.$el.find("li:last")),i.addClass("cur"),n=i[0],e=n.offsetTop+n.offsetHeight+(n.nextSibling?n.nextSibling.offsetHeight:0),this.scrollTop(Math.max(0,e-this.$el.height()))},e.prototype.scrollTop=function(t){var e;return e=this.context.getOpt("scrollDuration"),e?this.$elUl.animate({scrollTop:t},e):this.$elUl.scrollTop(t)},e.prototype.show=function(){var t;return this.stopShowing?void(this.stopShowing=!1):(this.visible()||(this.$el.show(),this.$el.scrollTop(0),this.context.trigger("shown")),(t=this.context.rect())?this.reposition(t):void 0)},e.prototype.hide=function(t,e){var i;if(this.visible())return isNaN(e)?(this.$el.hide(),this.context.trigger("hidden",[t])):(i=function(t){return function(){return t.hide()}}(this),clearTimeout(this.timeoutID),this.timeoutID=setTimeout(i,e))},e.prototype.render=function(e){var i,n,r,o,s,a,h;if(!(t.isArray(e)&&e.length>0))return void this.hide();for(this.$el.find("ul").empty(),n=this.$el.find("ul"),h=this.context.getOpt("displayTpl"),r=0,s=e.length;s>r;r++)o=e[r],o=t.extend({},o,{"atwho-at":this.context.at}),a=this.context.callbacks("tplEval").call(this.context,h,o,"onDisplay"),i=t(this.context.callbacks("highlighter").call(this.context,a,this.context.query.text)),i.data("item-data",o),n.append(i);return this.show(),this.context.getOpt("highlightFirst")?n.find("li:first").addClass("cur"):void 0},e}();var p;p={load:function(t,e){var i;return(i=this.controller(t))?i.model.load(e):void 0},isSelecting:function(){var t;return!!(null!=(t=this.controller())?t.view.visible():void 0)},hide:function(){var t;return null!=(t=this.controller())?t.view.hide():void 0},reposition:function(){var t;return(t=this.controller())?t.view.reposition(t.rect()):void 0},setIframe:function(t,e){return this.setupRootElement(t,e),null},run:function(){return this.dispatch()},destroy:function(){return this.shutdown(),this.$inputor.data("atwho",null)}},t.fn.atwho=function(e){var i,r;return i=arguments,r=null,this.filter('textarea, input, [contenteditable=""], [contenteditable=true]').each(function(){var o,s;return(s=(o=t(this)).data("atwho"))||o.data("atwho",s=new n(this)),"object"!=typeof e&&e?p[e]&&s?r=p[e].apply(s,Array.prototype.slice.call(i,1)):t.error("Method "+e+" does not exist on jQuery.atwho"):s.reg(e.at,e)}),null!=r?r:this},t.fn.atwho["default"]={at:void 0,alias:void 0,data:null,displayTpl:"
    • ${name}
    • ",insertTpl:"${atwho-at}${name}",headerTpl:null,callbacks:e,functionOverrides:{},searchKey:"name",suffix:void 0,hideWithoutSuffix:!1,startWithSpace:!0,acceptSpaceBar:!1,highlightFirst:!0,limit:5,maxLen:20,minLen:0,displayTimeout:300,delay:null,spaceSelectsMatch:!1,tabSelectsMatch:!0,editableAtwhoQueryAttrs:{},scrollDuration:150,suspendOnComposing:!0,lookUpOnClick:!0},t.fn.atwho.debug=!1}); \ No newline at end of file diff --git a/js/legacy/jquery.caret.min.js b/js/legacy/jquery.caret.min.js deleted file mode 100644 index 183c47b8e..000000000 --- a/js/legacy/jquery.caret.min.js +++ /dev/null @@ -1,561 +0,0 @@ -/* - * @copyright Copyright (c) 2018 Julius Härtl - * - * @author Julius Härtl - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 program. If not, see . - * - */ -(function($, undefined) { - - var _input = document.createElement('input'); - - var _support = { - setSelectionRange: ('setSelectionRange' in _input) || ('selectionStart' in _input), - createTextRange: ('createTextRange' in _input) || ('selection' in document) - }; - - var _rNewlineIE = /\r\n/g, - _rCarriageReturn = /\r/g; - - var _getValue = function(input) { - if (typeof(input.value) !== 'undefined') { - return input.value; - } - return $(input).text(); - }; - - var _setValue = function(input, value) { - if (typeof(input.value) !== 'undefined') { - input.value = value; - } else { - $(input).text(value); - } - }; - - var _getIndex = function(input, pos) { - var norm = _getValue(input).replace(_rCarriageReturn, ''); - var len = norm.length; - - if (typeof(pos) === 'undefined') { - pos = len; - } - - pos = Math.floor(pos); - - // Negative index counts backward from the end of the input/textarea's value - if (pos < 0) { - pos = len + pos; - } - - // Enforce boundaries - if (pos < 0) { pos = 0; } - if (pos > len) { pos = len; } - - return pos; - }; - - var _hasAttr = function(input, attrName) { - return input.hasAttribute ? input.hasAttribute(attrName) : (typeof(input[attrName]) !== 'undefined'); - }; - - /** - * @class - * @constructor - */ - var Range = function(start, end, length, text) { - this.start = start || 0; - this.end = end || 0; - this.length = length || 0; - this.text = text || ''; - }; - - Range.prototype.toString = function() { - return JSON.stringify(this, null, ' '); - }; - - var _getCaretW3 = function(input) { - return input.selectionStart; - }; - - /** - * @see http://stackoverflow.com/q/6943000/467582 - */ - var _getCaretIE = function(input) { - var caret, range, textInputRange, rawValue, len, endRange; - - // Yeah, you have to focus twice for IE 7 and 8. *cries* - input.focus(); - input.focus(); - - range = document.selection.createRange(); - - if (range && range.parentElement() === input) { - rawValue = _getValue(input); - - len = rawValue.length; - - // Create a working TextRange that lives only in the input - textInputRange = input.createTextRange(); - textInputRange.moveToBookmark(range.getBookmark()); - - // Check if the start and end of the selection are at the very end - // of the input, since moveStart/moveEnd doesn't return what we want - // in those cases - endRange = input.createTextRange(); - endRange.collapse(false); - - if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { - caret = rawValue.replace(_rNewlineIE, '\n').length; - } else { - caret = -textInputRange.moveStart("character", -len); - } - - return caret; - } - - // NOTE: This occurs when you highlight part of a textarea and then click in the middle of the highlighted portion in IE 6-10. - // There doesn't appear to be anything we can do about it. -// alert("Your browser is incredibly stupid. I don't know what else to say."); -// alert(range + '\n\n' + range.parentElement().tagName + '#' + range.parentElement().id); - - return 0; - }; - - /** - * Gets the position of the caret in the given input. - * @param {HTMLInputElement|HTMLTextAreaElement} input input or textarea element - * @returns {Number} - * @see http://stackoverflow.com/questions/263743/how-to-get-cursor-position-in-textarea/263796#263796 - */ - var _getCaret = function(input) { - if (!input) { - return undefined; - } - - // Mozilla, et al. - if (_support.setSelectionRange) { - return _getCaretW3(input); - } - // IE - else if (_support.createTextRange) { - return _getCaretIE(input); - } - - return undefined; - }; - - var _setCaretW3 = function(input, pos) { - input.setSelectionRange(pos, pos); - }; - - var _setCaretIE = function(input, pos) { - var range = input.createTextRange(); - range.move('character', pos); - range.select(); - }; - - /** - * Sets the position of the caret in the given input. - * @param {HTMLInputElement|HTMLTextAreaElement} input input or textarea element - * @param {Number} pos - * @see http://parentnode.org/javascript/working-with-the-cursor-position/ - */ - var _setCaret = function(input, pos) { - input.focus(); - - pos = _getIndex(input, pos); - - // Mozilla, et al. - if (_support.setSelectionRange) { - _setCaretW3(input, pos); - } - // IE - else if (_support.createTextRange) { - _setCaretIE(input, pos); - } - }; - - /** - * Inserts the specified text at the current caret position in the given input. - * @param {HTMLInputElement|HTMLTextAreaElement} input input or textarea element - * @param {String} text - * @see http://parentnode.org/javascript/working-with-the-cursor-position/ - */ - var _insertAtCaret = function(input, text) { - var curPos = _getCaret(input); - - var oldValueNorm = _getValue(input).replace(_rCarriageReturn, ''); - - var newLength = +(curPos + text.length + (oldValueNorm.length - curPos)); - var maxLength = +input.getAttribute('maxlength'); - - if(_hasAttr(input, 'maxlength') && newLength > maxLength) { - var delta = text.length - (newLength - maxLength); - text = text.substr(0, delta); - } - - _setValue(input, oldValueNorm.substr(0, curPos) + text + oldValueNorm.substr(curPos)); - - _setCaret(input, curPos + text.length); - }; - - var _getInputRangeW3 = function(input) { - var range = new Range(); - - range.start = input.selectionStart; - range.end = input.selectionEnd; - - var min = Math.min(range.start, range.end); - var max = Math.max(range.start, range.end); - - range.length = max - min; - range.text = _getValue(input).substring(min, max); - - return range; - }; - - /** @see http://stackoverflow.com/a/3648244/467582 */ - var _getInputRangeIE = function(input) { - var range = new Range(); - - input.focus(); - - var selection = document.selection.createRange(); - - if (selection && selection.parentElement() === input) { - var len, normalizedValue, textInputRange, endRange, start = 0, end = 0; - var rawValue = _getValue(input); - - len = rawValue.length; - normalizedValue = rawValue.replace(/\r\n/g, "\n"); - - // Create a working TextRange that lives only in the input - textInputRange = input.createTextRange(); - textInputRange.moveToBookmark(selection.getBookmark()); - - // Check if the start and end of the selection are at the very end - // of the input, since moveStart/moveEnd doesn't return what we want - // in those cases - endRange = input.createTextRange(); - endRange.collapse(false); - - if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { - start = end = len; - } else { - start = -textInputRange.moveStart("character", -len); - start += normalizedValue.slice(0, start).split("\n").length - 1; - - if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) { - end = len; - } else { - end = -textInputRange.moveEnd("character", -len); - end += normalizedValue.slice(0, end).split("\n").length - 1; - } - } - - /// normalize newlines - start -= (rawValue.substring(0, start).split('\r\n').length - 1); - end -= (rawValue.substring(0, end).split('\r\n').length - 1); - /// normalize newlines - - range.start = start; - range.end = end; - range.length = range.end - range.start; - range.text = normalizedValue.substr(range.start, range.length); - } - - return range; - }; - - /** - * Gets the selected text range of the given input. - * @param {HTMLInputElement|HTMLTextAreaElement} input input or textarea element - * @returns {Range} - * @see http://stackoverflow.com/a/263796/467582 - * @see http://stackoverflow.com/a/2966703/467582 - */ - var _getInputRange = function(input) { - if (!input) { - return undefined; - } - - // Mozilla, et al. - if (_support.setSelectionRange) { - return _getInputRangeW3(input); - } - // IE - else if (_support.createTextRange) { - return _getInputRangeIE(input); - } - - return undefined; - }; - - var _setInputRangeW3 = function(input, startPos, endPos) { - input.setSelectionRange(startPos, endPos); - }; - - var _setInputRangeIE = function(input, startPos, endPos) { - var tr = input.createTextRange(); - tr.moveEnd('textedit', -1); - tr.moveStart('character', startPos); - tr.moveEnd('character', endPos - startPos); - tr.select(); - }; - - /** - * Sets the selected text range of (i.e., highlights text in) the given input. - * @param {HTMLInputElement|HTMLTextAreaElement} input input or textarea element - * @param {Number} startPos Zero-based index - * @param {Number} endPos Zero-based index - * @see http://parentnode.org/javascript/working-with-the-cursor-position/ - * @see http://stackoverflow.com/a/2966703/467582 - */ - var _setInputRange = function(input, startPos, endPos) { - startPos = _getIndex(input, startPos); - endPos = _getIndex(input, endPos); - - // Mozilla, et al. - if (_support.setSelectionRange) { - _setInputRangeW3(input, startPos, endPos); - } - // IE - else if (_support.createTextRange) { - _setInputRangeIE(input, startPos, endPos); - } - }; - - /** - * Replaces the currently selected text with the given string. - * @param {HTMLInputElement|HTMLTextAreaElement} input input or textarea element - * @param {String} text New text that will replace the currently selected text. - * @see http://parentnode.org/javascript/working-with-the-cursor-position/ - */ - var _replaceInputRange = function(input, text) { - var $input = $(input); - - var oldValue = $input.val(); - var selection = _getInputRange(input); - - var newLength = +(selection.start + text.length + (oldValue.length - selection.end)); - var maxLength = +$input.attr('maxlength'); - - if($input.is('[maxlength]') && newLength > maxLength) { - var delta = text.length - (newLength - maxLength); - text = text.substr(0, delta); - } - - // Now that we know what the user selected, we can replace it - var startText = oldValue.substr(0, selection.start); - var endText = oldValue.substr(selection.end); - - $input.val(startText + text + endText); - - // Reset the selection - var startPos = selection.start; - var endPos = startPos + text.length; - - _setInputRange(input, selection.length ? startPos : endPos, endPos); - }; - - var _selectAllW3 = function(elem) { - var selection = window.getSelection(); - var range = document.createRange(); - range.selectNodeContents(elem); - selection.removeAllRanges(); - selection.addRange(range); - }; - - var _selectAllIE = function(elem) { - var range = document.body.createTextRange(); - range.moveToElementText(elem); - range.select(); - }; - - /** - * Select all text in the given element. - * @param {HTMLElement} elem Any block or inline element other than a form element. - */ - var _selectAll = function(elem) { - var $elem = $(elem); - if ($elem.is('input, textarea') || elem.select) { - $elem.select(); - return; - } - - // Mozilla, et al. - if (_support.setSelectionRange) { - _selectAllW3(elem); - } - // IE - else if (_support.createTextRange) { - _selectAllIE(elem); - } - }; - - var _deselectAll = function() { - if (document.selection) { - document.selection.empty(); - } - else if (window.getSelection) { - window.getSelection().removeAllRanges(); - } - }; - - $.extend($.fn, { - - /** - * Gets or sets the position of the caret or inserts text at the current caret position in an input or textarea element. - * @returns {Number|jQuery} The current caret position if invoked as a getter (with no arguments) - * or this jQuery object if invoked as a setter or inserter. - * @see http://web.archive.org/web/20080704185920/http://parentnode.org/javascript/working-with-the-cursor-position/ - * @since 1.0.0 - * @example - *
      -		 *    // Get position
      -		 *    var pos = $('input:first').caret();
      -		 * 
      - * @example - *
      -		 *    // Set position
      -		 *    $('input:first').caret(15);
      -		 *    $('input:first').caret(-3);
      -		 * 
      - * @example - *
      -		 *    // Insert text at current position
      -		 *    $('input:first').caret('Some text');
      -		 * 
      - */ - caret: function() { - var $inputs = this.filter('input, textarea'); - - // getCaret() - if (arguments.length === 0) { - var input = $inputs.get(0); - return _getCaret(input); - } - // setCaret(position) - else if (typeof arguments[0] === 'number') { - var pos = arguments[0]; - $inputs.each(function(_i, input) { - _setCaret(input, pos); - }); - } - // insertAtCaret(text) - else { - var text = arguments[0]; - $inputs.each(function(_i, input) { - _insertAtCaret(input, text); - }); - } - - return this; - }, - - /** - * Gets or sets the selection range or replaces the currently selected text in an input or textarea element. - * @returns {Range|jQuery} The current selection range if invoked as a getter (with no arguments) - * or this jQuery object if invoked as a setter or replacer. - * @see http://stackoverflow.com/a/2966703/467582 - * @since 1.0.0 - * @example - *
      -		 *    // Get selection range
      -		 *    var range = $('input:first').range();
      -		 * 
      - * @example - *
      -		 *    // Set selection range
      -		 *    $('input:first').range(15);
      -		 *    $('input:first').range(15, 20);
      -		 *    $('input:first').range(-3);
      -		 *    $('input:first').range(-8, -3);
      -		 * 
      - * @example - *
      -		 *    // Replace the currently selected text
      -		 *    $('input:first').range('Replacement text');
      -		 * 
      - */ - range: function() { - var $inputs = this.filter('input, textarea'); - - // getRange() = { start: pos, end: pos } - if (arguments.length === 0) { - var input = $inputs.get(0); - return _getInputRange(input); - } - // setRange(startPos, endPos) - else if (typeof arguments[0] === 'number') { - var startPos = arguments[0]; - var endPos = arguments[1]; - $inputs.each(function(_i, input) { - _setInputRange(input, startPos, endPos); - }); - } - // replaceRange(text) - else { - var text = arguments[0]; - $inputs.each(function(_i, input) { - _replaceInputRange(input, text); - }); - } - - return this; - }, - - /** - * Selects all text in each element of this jQuery object. - * @returns {jQuery} This jQuery object - * @see http://stackoverflow.com/a/11128179/467582 - * @since 1.5.0 - * @example - *
      -		 *     // Select the contents of span elements when clicked
      -		 *     $('span').on('click', function() { $(this).highlight(); });
      -		 * 
      - */ - selectAll: function() { - return this.each(function(_i, elem) { - _selectAll(elem); - }); - } - - }); - - $.extend($, { - /** - * Deselects all text on the page. - * @returns {jQuery} The jQuery function - * @since 1.5.0 - * @example - *
      -		 *     // Select some text
      -		 *     $('span').selectAll();
      -		 *
      -		 *     // Deselect the text
      -		 *     $.deselectAll();
      -		 * 
      - */ - deselectAll: function() { - _deselectAll(); - return this; - } - }); - -}(window.jQuery || window.Zepto || window.$)); diff --git a/js/legacy/jquery.ui.timepicker.css b/js/legacy/jquery.ui.timepicker.css deleted file mode 100644 index b5930fb73..000000000 --- a/js/legacy/jquery.ui.timepicker.css +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Timepicker stylesheet - * Highly inspired from datepicker - * FG - Nov 2010 - Web3R - * - * version 0.0.3 : Fixed some settings, more dynamic - * version 0.0.4 : Removed width:100% on tables - * version 0.1.1 : set width 0 on tables to fix an ie6 bug - */ - -.ui-timepicker-inline { display: inline; } - -#ui-timepicker-div { padding: 0.2em; } -.ui-timepicker-table { display: inline-table; width: 0; } -.ui-timepicker-table table { margin:0.15em 0 0 0; border-collapse: collapse; } - -.ui-timepicker-hours, .ui-timepicker-minutes { padding: 0.2em; } - -.ui-timepicker-table .ui-timepicker-title { line-height: 1.8em; text-align: center; } -.ui-timepicker-table td { padding: 0.1em; width: 2.2em; } -.ui-timepicker-table th.periods { padding: 0.1em; width: 2.2em; } - -/* span for disabled cells */ -.ui-timepicker-table td span { - display:block; - padding:0.2em 0.3em 0.2em 0.5em; - width: 1.2em; - - text-align:right; - text-decoration:none; -} -/* anchors for clickable cells */ -.ui-timepicker-table td a { - display:block; - padding:0.2em 0.3em 0.2em 0.5em; - width: 1.2em; - cursor: pointer; - text-align:right; - text-decoration:none; -} - - -/* buttons and button pane styling */ -.ui-timepicker .ui-timepicker-buttonpane { - background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; -} -.ui-timepicker .ui-timepicker-buttonpane button { margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -/* The close button */ -.ui-timepicker .ui-timepicker-close { float: right } - -/* the now button */ -.ui-timepicker .ui-timepicker-now { float: left; } - -/* the deselect button */ -.ui-timepicker .ui-timepicker-deselect { float: left; } - - diff --git a/js/legacy/jquery.ui.timepicker.js b/js/legacy/jquery.ui.timepicker.js deleted file mode 100644 index 7b4d04dc7..000000000 --- a/js/legacy/jquery.ui.timepicker.js +++ /dev/null @@ -1,1496 +0,0 @@ -/* - * jQuery UI Timepicker - * - * Copyright 2010-2013, Francois Gelinas - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://fgelinas.com/code/timepicker - * - * Depends: - * jquery.ui.core.js - * jquery.ui.position.js (only if position settings are used) - * - * Change version 0.1.0 - moved the t-rex up here - * - ____ - ___ .-~. /_"-._ - `-._~-. / /_ "~o\ :Y - \ \ / : \~x. ` ') - ] Y / | Y< ~-.__j - / ! _.--~T : l l< /.-~ - / / ____.--~ . ` l /~\ \<|Y - / / .-~~" /| . ',-~\ \L| - / / / .^ \ Y~Y \.^>/l_ "--' - / Y .-"( . l__ j_j l_/ /~_.-~ . - Y l / \ ) ~~~." / `/"~ / \.__/l_ - | \ _.-" ~-{__ l : l._Z~-.___.--~ - | ~---~ / ~~"---\_ ' __[> - l . _.^ ___ _>-y~ - \ \ . .-~ .-~ ~>--" / - \ ~---" / ./ _.-' - "-.,_____.,_ _.--~\ _.-~ - ~~ ( _} -Row - `. ~( - ) \ - /,`--'~\--'~\ - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ->T-Rex<- -*/ - -(function ($) { - - $.extend($.ui, { timepicker: { version: "0.3.3"} }); - - var PROP_NAME = 'timepicker', - tpuuid = new Date().getTime(); - - /* Time picker manager. - Use the singleton instance of this class, $.timepicker, to interact with the time picker. - Settings for (groups of) time pickers are maintained in an instance object, - allowing multiple different settings on the same page. */ - - function Timepicker() { - this.debug = true; // Change this to true to start debugging - this._curInst = null; // The current instance in use - this._disabledInputs = []; // List of time picker inputs that have been disabled - this._timepickerShowing = false; // True if the popup picker is showing , false if not - this._inDialog = false; // True if showing within a "dialog", false if not - this._dialogClass = 'ui-timepicker-dialog'; // The name of the dialog marker class - this._mainDivId = 'ui-timepicker-div'; // The ID of the main timepicker division - this._inlineClass = 'ui-timepicker-inline'; // The name of the inline marker class - this._currentClass = 'ui-timepicker-current'; // The name of the current hour / minutes marker class - this._dayOverClass = 'ui-timepicker-days-cell-over'; // The name of the day hover marker class - - this.regional = []; // Available regional settings, indexed by language code - this.regional[''] = { // Default regional settings - hourText: 'Hour', // Display text for hours section - minuteText: 'Minute', // Display text for minutes link - amPmText: ['AM', 'PM'], // Display text for AM PM - closeButtonText: 'Done', // Text for the confirmation button (ok button) - nowButtonText: 'Now', // Text for the now button - deselectButtonText: 'Deselect' // Text for the deselect button - }; - this._defaults = { // Global defaults for all the time picker instances - showOn: 'focus', // 'focus' for popup on focus, - // 'button' for trigger button, or 'both' for either (not yet implemented) - button: null, // 'button' element that will trigger the timepicker - showAnim: 'fadeIn', // Name of jQuery animation for popup - showOptions: {}, // Options for enhanced animations - appendText: '', // Display text following the input box, e.g. showing the format - - beforeShow: null, // Define a callback function executed before the timepicker is shown - onSelect: null, // Define a callback function when a hour / minutes is selected - onClose: null, // Define a callback function when the timepicker is closed - - timeSeparator: ':', // The character to use to separate hours and minutes. - periodSeparator: ' ', // The character to use to separate the time from the time period. - showPeriod: false, // Define whether or not to show AM/PM with selected time - showPeriodLabels: true, // Show the AM/PM labels on the left of the time picker - showLeadingZero: true, // Define whether or not to show a leading zero for hours < 10. [true/false] - showMinutesLeadingZero: true, // Define whether or not to show a leading zero for minutes < 10. - altField: '', // Selector for an alternate field to store selected time into - defaultTime: 'now', // Used as default time when input field is empty or for inline timePicker - // (set to 'now' for the current time, '' for no highlighted time) - myPosition: 'left top', // Position of the dialog relative to the input. - // see the position utility for more info : http://jqueryui.com/demos/position/ - atPosition: 'left bottom', // Position of the input element to match - // Note : if the position utility is not loaded, the timepicker will attach left top to left bottom - //NEW: 2011-02-03 - onHourShow: null, // callback for enabling / disabling on selectable hours ex : function(hour) { return true; } - onMinuteShow: null, // callback for enabling / disabling on time selection ex : function(hour,minute) { return true; } - - hours: { - starts: 0, // first displayed hour - ends: 23 // last displayed hour - }, - minutes: { - starts: 0, // first displayed minute - ends: 55, // last displayed minute - interval: 5, // interval of displayed minutes - manual: [] // optional extra manual entries for minutes - }, - rows: 4, // number of rows for the input tables, minimum 2, makes more sense if you use multiple of 2 - // 2011-08-05 0.2.4 - showHours: true, // display the hours section of the dialog - showMinutes: true, // display the minute section of the dialog - optionalMinutes: false, // optionally parse inputs of whole hours with minutes omitted - - // buttons - showCloseButton: false, // shows an OK button to confirm the edit - showNowButton: false, // Shows the 'now' button - showDeselectButton: false, // Shows the deselect time button - - maxTime: { - hour: null, - minute: null - }, - minTime: { - hour: null, - minute: null - } - - }; - $.extend(this._defaults, this.regional['']); - - this.tpDiv = $(''); - } - - $.extend(Timepicker.prototype, { - /* Class name added to elements to indicate already configured with a time picker. */ - markerClassName: 'hasTimepicker', - - /* Debug logging (if enabled). */ - log: function () { - if (this.debug) - console.log.apply('', arguments); - }, - - _widgetTimepicker: function () { - return this.tpDiv; - }, - - /* Override the default settings for all instances of the time picker. - @param settings object - the new settings to use as defaults (anonymous object) - @return the manager object */ - setDefaults: function (settings) { - extendRemove(this._defaults, settings || {}); - return this; - }, - - /* Attach the time picker to a jQuery selection. - @param target element - the target input field or division or span - @param settings object - the new settings to use for this time picker instance (anonymous) */ - _attachTimepicker: function (target, settings) { - // check for settings on the control itself - in namespace 'time:' - var inlineSettings = null; - for (var attrName in this._defaults) { - var attrValue = target.getAttribute('time:' + attrName); - if (attrValue) { - inlineSettings = inlineSettings || {}; - try { - inlineSettings[attrName] = eval(attrValue); - } catch (err) { - inlineSettings[attrName] = attrValue; - } - } - } - var nodeName = target.nodeName.toLowerCase(); - var inline = (nodeName == 'div' || nodeName == 'span'); - - if (!target.id) { - this.uuid += 1; - target.id = 'tp' + this.uuid; - } - var inst = this._newInst($(target), inline); - inst.settings = $.extend({}, settings || {}, inlineSettings || {}); - if (nodeName == 'input') { - this._connectTimepicker(target, inst); - // init inst.hours and inst.minutes from the input value - this._setTimeFromField(inst); - } else if (inline) { - this._inlineTimepicker(target, inst); - } - - - }, - - /* Create a new instance object. */ - _newInst: function (target, inline) { - var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars - return { - id: id, input: target, // associated target - inline: inline, // is timepicker inline or not : - tpDiv: (!inline ? this.tpDiv : // presentation div - $('
      ')) - }; - }, - - /* Attach the time picker to an input field. */ - _connectTimepicker: function (target, inst) { - var input = $(target); - inst.append = $([]); - inst.trigger = $([]); - if (input.hasClass(this.markerClassName)) { return; } - this._attachments(input, inst); - input.addClass(this.markerClassName). - keydown(this._doKeyDown). - keyup(this._doKeyUp). - bind("setData.timepicker", function (event, key, value) { - inst.settings[key] = value; - }). - bind("getData.timepicker", function (event, key) { - return this._get(inst, key); - }); - $.data(target, PROP_NAME, inst); - }, - - /* Handle keystrokes. */ - _doKeyDown: function (event) { - var inst = $.timepicker._getInst(event.target); - var handled = true; - inst._keyEvent = true; - if ($.timepicker._timepickerShowing) { - switch (event.keyCode) { - case 9: $.timepicker._hideTimepicker(); - handled = false; - break; // hide on tab out - case 13: - $.timepicker._updateSelectedValue(inst); - $.timepicker._hideTimepicker(); - - return false; // don't submit the form - break; // select the value on enter - case 27: $.timepicker._hideTimepicker(); - break; // hide on escape - default: handled = false; - } - } - else if (event.keyCode == 36 && event.ctrlKey) { // display the time picker on ctrl+home - $.timepicker._showTimepicker(this); - } - else { - handled = false; - } - if (handled) { - event.preventDefault(); - event.stopPropagation(); - } - }, - - /* Update selected time on keyUp */ - /* Added verion 0.0.5 */ - _doKeyUp: function (event) { - var inst = $.timepicker._getInst(event.target); - $.timepicker._setTimeFromField(inst); - $.timepicker._updateTimepicker(inst); - }, - - /* Make attachments based on settings. */ - _attachments: function (input, inst) { - var appendText = this._get(inst, 'appendText'); - var isRTL = this._get(inst, 'isRTL'); - if (inst.append) { inst.append.remove(); } - if (appendText) { - inst.append = $('' + appendText + ''); - input[isRTL ? 'before' : 'after'](inst.append); - } - input.unbind('focus.timepicker', this._showTimepicker); - input.unbind('click.timepicker', this._adjustZIndex); - - if (inst.trigger) { inst.trigger.remove(); } - - var showOn = this._get(inst, 'showOn'); - if (showOn == 'focus' || showOn == 'both') { // pop-up time picker when in the marked field - input.bind("focus.timepicker", this._showTimepicker); - input.bind("click.timepicker", this._adjustZIndex); - } - if (showOn == 'button' || showOn == 'both') { // pop-up time picker when 'button' element is clicked - var button = this._get(inst, 'button'); - - // Add button if button element is not set - if(button == null) { - button = $(''); - input.after(button); - } - - $(button).bind("click.timepicker", function () { - if ($.timepicker._timepickerShowing && $.timepicker._lastInput == input[0]) { - $.timepicker._hideTimepicker(); - } else if (!inst.input.is(':disabled')) { - $.timepicker._showTimepicker(input[0]); - } - return false; - }); - - } - }, - - - /* Attach an inline time picker to a div. */ - _inlineTimepicker: function(target, inst) { - var divSpan = $(target); - if (divSpan.hasClass(this.markerClassName)) - return; - divSpan.addClass(this.markerClassName).append(inst.tpDiv). - bind("setData.timepicker", function(event, key, value){ - inst.settings[key] = value; - }).bind("getData.timepicker", function(event, key){ - return this._get(inst, key); - }); - $.data(target, PROP_NAME, inst); - - this._setTimeFromField(inst); - this._updateTimepicker(inst); - inst.tpDiv.show(); - }, - - _adjustZIndex: function(input) { - input = input.target || input; - var inst = $.timepicker._getInst(input); - inst.tpDiv.css('zIndex', $.timepicker._getZIndex(input) +1); - }, - - /* Pop-up the time picker for a given input field. - @param input element - the input field attached to the time picker or - event - if triggered by focus */ - _showTimepicker: function (input) { - input = input.target || input; - if (input.nodeName.toLowerCase() != 'input') { input = $('input', input.parentNode)[0]; } // find from button/image trigger - - if ($.timepicker._isDisabledTimepicker(input) || $.timepicker._lastInput == input) { return; } // already here - - // fix v 0.0.8 - close current timepicker before showing another one - $.timepicker._hideTimepicker(); - - var inst = $.timepicker._getInst(input); - if ($.timepicker._curInst && $.timepicker._curInst != inst) { - $.timepicker._curInst.tpDiv.stop(true, true); - } - var beforeShow = $.timepicker._get(inst, 'beforeShow'); - extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); - inst.lastVal = null; - $.timepicker._lastInput = input; - - $.timepicker._setTimeFromField(inst); - - // calculate default position - if ($.timepicker._inDialog) { input.value = ''; } // hide cursor - if (!$.timepicker._pos) { // position below input - $.timepicker._pos = $.timepicker._findPos(input); - $.timepicker._pos[1] += input.offsetHeight; // add the height - } - var isFixed = false; - $(input).parents().each(function () { - isFixed |= $(this).css('position') == 'fixed'; - return !isFixed; - }); - - var offset = { left: $.timepicker._pos[0], top: $.timepicker._pos[1] }; - - $.timepicker._pos = null; - // determine sizing offscreen - inst.tpDiv.css({ position: 'absolute', display: 'block', top: '-1000px' }); - $.timepicker._updateTimepicker(inst); - - - // position with the ui position utility, if loaded - if ( ( ! inst.inline ) && ( typeof $.ui.position == 'object' ) ) { - inst.tpDiv.position({ - of: inst.input, - my: $.timepicker._get( inst, 'myPosition' ), - at: $.timepicker._get( inst, 'atPosition' ), - // offset: $( "#offset" ).val(), - // using: using, - collision: 'flip' - }); - var offset = inst.tpDiv.offset(); - $.timepicker._pos = [offset.top, offset.left]; - } - - - // reset clicked state - inst._hoursClicked = false; - inst._minutesClicked = false; - - // fix width for dynamic number of time pickers - // and adjust position before showing - offset = $.timepicker._checkOffset(inst, offset, isFixed); - inst.tpDiv.css({ position: ($.timepicker._inDialog && $.blockUI ? - 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', - left: offset.left + 'px', top: offset.top + 'px' - }); - if ( ! inst.inline ) { - var showAnim = $.timepicker._get(inst, 'showAnim'); - var duration = $.timepicker._get(inst, 'duration'); - - var postProcess = function () { - $.timepicker._timepickerShowing = true; - var borders = $.timepicker._getBorders(inst.tpDiv); - inst.tpDiv.find('iframe.ui-timepicker-cover'). // IE6- only - css({ left: -borders[0], top: -borders[1], - width: inst.tpDiv.outerWidth(), height: inst.tpDiv.outerHeight() - }); - }; - - // Fixed the zIndex problem for real (I hope) - FG - v 0.2.9 - $.timepicker._adjustZIndex(input); - //inst.tpDiv.css('zIndex', $.timepicker._getZIndex(input) +1); - - if ($.effects && $.effects[showAnim]) { - inst.tpDiv.show(showAnim, $.timepicker._get(inst, 'showOptions'), duration, postProcess); - } - else { - inst.tpDiv.show((showAnim ? duration : null), postProcess); - } - if (!showAnim || !duration) { postProcess(); } - if (inst.input.is(':visible') && !inst.input.is(':disabled')) { inst.input.focus(); } - $.timepicker._curInst = inst; - } - }, - - // This is an enhanced copy of the zIndex function of UI core 1.8.?? For backward compatibility. - // Enhancement returns maximum zindex value discovered while traversing parent elements, - // rather than the first zindex value found. Ensures the timepicker popup will be in front, - // even in funky scenarios like non-jq dialog containers with large fixed zindex values and - // nested zindex-influenced elements of their own. - _getZIndex: function (target) { - var elem = $(target); - var maxValue = 0; - var position, value; - while (elem.length && elem[0] !== document) { - position = elem.css("position"); - if (position === "absolute" || position === "relative" || position === "fixed") { - value = parseInt(elem.css("zIndex"), 10); - if (!isNaN(value) && value !== 0) { - if (value > maxValue) { maxValue = value; } - } - } - elem = elem.parent(); - } - - return maxValue; - }, - - /* Refresh the time picker - @param target element - The target input field or inline container element. */ - _refreshTimepicker: function(target) { - var inst = this._getInst(target); - if (inst) { - this._updateTimepicker(inst); - } - }, - - - /* Generate the time picker content. */ - _updateTimepicker: function (inst) { - inst.tpDiv.empty().append(this._generateHTML(inst)); - this._rebindDialogEvents(inst); - - }, - - _rebindDialogEvents: function (inst) { - var borders = $.timepicker._getBorders(inst.tpDiv), - self = this; - inst.tpDiv - .find('iframe.ui-timepicker-cover') // IE6- only - .css({ left: -borders[0], top: -borders[1], - width: inst.tpDiv.outerWidth(), height: inst.tpDiv.outerHeight() - }) - .end() - // after the picker html is appended bind the click & double click events (faster in IE this way - // then letting the browser interpret the inline events) - // the binding for the minute cells also exists in _updateMinuteDisplay - .find('.ui-timepicker-minute-cell') - .unbind() - .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectMinutes, this)) - .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectMinutes, this)) - .end() - .find('.ui-timepicker-hour-cell') - .unbind() - .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectHours, this)) - .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectHours, this)) - .end() - .find('.ui-timepicker td a') - .unbind() - .bind('mouseout', function () { - $(this).removeClass('ui-state-hover'); - if (this.className.indexOf('ui-timepicker-prev') != -1) $(this).removeClass('ui-timepicker-prev-hover'); - if (this.className.indexOf('ui-timepicker-next') != -1) $(this).removeClass('ui-timepicker-next-hover'); - }) - .bind('mouseover', function () { - if ( ! self._isDisabledTimepicker(inst.inline ? inst.tpDiv.parent()[0] : inst.input[0])) { - $(this).parents('.ui-timepicker-calendar').find('a').removeClass('ui-state-hover'); - $(this).addClass('ui-state-hover'); - if (this.className.indexOf('ui-timepicker-prev') != -1) $(this).addClass('ui-timepicker-prev-hover'); - if (this.className.indexOf('ui-timepicker-next') != -1) $(this).addClass('ui-timepicker-next-hover'); - } - }) - .end() - .find('.' + this._dayOverClass + ' a') - .trigger('mouseover') - .end() - .find('.ui-timepicker-now').bind("click", function(e) { - $.timepicker.selectNow(e); - }).end() - .find('.ui-timepicker-deselect').bind("click",function(e) { - $.timepicker.deselectTime(e); - }).end() - .find('.ui-timepicker-close').bind("click",function(e) { - $.timepicker._hideTimepicker(); - }).end(); - }, - - /* Generate the HTML for the current state of the time picker. */ - _generateHTML: function (inst) { - - var h, m, row, col, html, hoursHtml, minutesHtml = '', - showPeriod = (this._get(inst, 'showPeriod') == true), - showPeriodLabels = (this._get(inst, 'showPeriodLabels') == true), - showLeadingZero = (this._get(inst, 'showLeadingZero') == true), - showHours = (this._get(inst, 'showHours') == true), - showMinutes = (this._get(inst, 'showMinutes') == true), - amPmText = this._get(inst, 'amPmText'), - rows = this._get(inst, 'rows'), - amRows = 0, - pmRows = 0, - amItems = 0, - pmItems = 0, - amFirstRow = 0, - pmFirstRow = 0, - hours = Array(), - hours_options = this._get(inst, 'hours'), - hoursPerRow = null, - hourCounter = 0, - hourLabel = this._get(inst, 'hourText'), - showCloseButton = this._get(inst, 'showCloseButton'), - closeButtonText = this._get(inst, 'closeButtonText'), - showNowButton = this._get(inst, 'showNowButton'), - nowButtonText = this._get(inst, 'nowButtonText'), - showDeselectButton = this._get(inst, 'showDeselectButton'), - deselectButtonText = this._get(inst, 'deselectButtonText'), - showButtonPanel = showCloseButton || showNowButton || showDeselectButton; - - - - // prepare all hours and minutes, makes it easier to distribute by rows - for (h = hours_options.starts; h <= hours_options.ends; h++) { - hours.push (h); - } - hoursPerRow = Math.ceil(hours.length / rows); // always round up - - if (showPeriodLabels) { - for (hourCounter = 0; hourCounter < hours.length; hourCounter++) { - if (hours[hourCounter] < 12) { - amItems++; - } - else { - pmItems++; - } - } - hourCounter = 0; - - amRows = Math.floor(amItems / hours.length * rows); - pmRows = Math.floor(pmItems / hours.length * rows); - - // assign the extra row to the period that is more densely populated - if (rows != amRows + pmRows) { - // Make sure: AM Has Items and either PM Does Not, AM has no rows yet, or AM is more dense - if (amItems && (!pmItems || !amRows || (pmRows && amItems / amRows >= pmItems / pmRows))) { - amRows++; - } else { - pmRows++; - } - } - amFirstRow = Math.min(amRows, 1); - pmFirstRow = amRows + 1; - - if (amRows == 0) { - hoursPerRow = Math.ceil(pmItems / pmRows); - } else if (pmRows == 0) { - hoursPerRow = Math.ceil(amItems / amRows); - } else { - hoursPerRow = Math.ceil(Math.max(amItems / amRows, pmItems / pmRows)); - } - } - - - html = ''; - - if (showHours) { - - html += ''; // Close the Hour td - } - - if (showMinutes) { - html += ''; - } - - html += ''; - - - if (showButtonPanel) { - var buttonPanel = ''; - } - html += '
      ' + - '
      ' + - hourLabel + - '
      ' + - ''; - - for (row = 1; row <= rows; row++) { - html += ''; - // AM - if (row == amFirstRow && showPeriodLabels) { - html += ''; - } - // PM - if (row == pmFirstRow && showPeriodLabels) { - html += ''; - } - for (col = 1; col <= hoursPerRow; col++) { - if (showPeriodLabels && row < pmFirstRow && hours[hourCounter] >= 12) { - html += this._generateHTMLHourCell(inst, undefined, showPeriod, showLeadingZero); - } else { - html += this._generateHTMLHourCell(inst, hours[hourCounter], showPeriod, showLeadingZero); - hourCounter++; - } - } - html += ''; - } - html += '
      ' + amPmText[0] + '' + amPmText[1] + '
      ' + // Close the hours cells table - '
      '; - html += this._generateHTMLMinutes(inst); - html += '
      '; - if (showNowButton) { - buttonPanel += ''; - } - if (showDeselectButton) { - buttonPanel += ''; - } - if (showCloseButton) { - buttonPanel += ''; - } - - html += buttonPanel + '
      '; - - return html; - }, - - /* Special function that update the minutes selection in currently visible timepicker - * called on hour selection when onMinuteShow is defined */ - _updateMinuteDisplay: function (inst) { - var newHtml = this._generateHTMLMinutes(inst); - inst.tpDiv.find('td.ui-timepicker-minutes').html(newHtml); - this._rebindDialogEvents(inst); - // after the picker html is appended bind the click & double click events (faster in IE this way - // then letting the browser interpret the inline events) - // yes I know, duplicate code, sorry -/* .find('.ui-timepicker-minute-cell') - .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectMinutes, this)) - .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectMinutes, this)); -*/ - - }, - - /* - * Generate the minutes table - * This is separated from the _generateHTML function because is can be called separately (when hours changes) - */ - _generateHTMLMinutes: function (inst) { - - var m, row, html = '', - rows = this._get(inst, 'rows'), - minutes = Array(), - minutes_options = this._get(inst, 'minutes'), - minutesPerRow = null, - minuteCounter = 0, - showMinutesLeadingZero = (this._get(inst, 'showMinutesLeadingZero') == true), - onMinuteShow = this._get(inst, 'onMinuteShow'), - minuteLabel = this._get(inst, 'minuteText'); - - if ( ! minutes_options.starts) { - minutes_options.starts = 0; - } - if ( ! minutes_options.ends) { - minutes_options.ends = 59; - } - if ( ! minutes_options.manual) { - minutes_options.manual = []; - } - for (m = minutes_options.starts; m <= minutes_options.ends; m += minutes_options.interval) { - minutes.push(m); - } - for (i = 0; i < minutes_options.manual.length;i++) { - var currMin = minutes_options.manual[i]; - - // Validate & filter duplicates of manual minute input - if (typeof currMin != 'number' || currMin < 0 || currMin > 59 || $.inArray(currMin, minutes) >= 0) { - continue; - } - minutes.push(currMin); - } - - // Sort to get correct order after adding manual minutes - // Use compare function to sort by number, instead of string (default) - minutes.sort(function(a, b) { - return a-b; - }); - - minutesPerRow = Math.round(minutes.length / rows + 0.49); // always round up - - /* - * The minutes table - */ - // if currently selected minute is not enabled, we have a problem and need to select a new minute. - if (onMinuteShow && - (onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours , inst.minutes]) == false) ) { - // loop minutes and select first available - for (minuteCounter = 0; minuteCounter < minutes.length; minuteCounter += 1) { - m = minutes[minuteCounter]; - if (onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours, m])) { - inst.minutes = m; - break; - } - } - } - - - - html += '
      ' + - minuteLabel + - '
      ' + - ''; - - minuteCounter = 0; - for (row = 1; row <= rows; row++) { - html += ''; - while (minuteCounter < row * minutesPerRow) { - var m = minutes[minuteCounter]; - var displayText = ''; - if (m !== undefined ) { - displayText = (m < 10) && showMinutesLeadingZero ? "0" + m.toString() : m.toString(); - } - html += this._generateHTMLMinuteCell(inst, m, displayText); - minuteCounter++; - } - html += ''; - } - - html += '
      '; - - return html; - }, - - /* Generate the content of a "Hour" cell */ - _generateHTMLHourCell: function (inst, hour, showPeriod, showLeadingZero) { - - var displayHour = hour; - if ((hour > 12) && showPeriod) { - displayHour = hour - 12; - } - if ((displayHour == 0) && showPeriod) { - displayHour = 12; - } - if ((displayHour < 10) && showLeadingZero) { - displayHour = '0' + displayHour; - } - - var html = ""; - var enabled = true; - var onHourShow = this._get(inst, 'onHourShow'); //custom callback - var maxTime = this._get(inst, 'maxTime'); - var minTime = this._get(inst, 'minTime'); - - if (hour == undefined) { - html = ' '; - return html; - } - - if (onHourShow) { - enabled = onHourShow.apply((inst.input ? inst.input[0] : null), [hour]); - } - - if (enabled) { - if ( !isNaN(parseInt(maxTime.hour)) && hour > maxTime.hour ) enabled = false; - if ( !isNaN(parseInt(minTime.hour)) && hour < minTime.hour ) enabled = false; - } - - if (enabled) { - html = '' + - '' + - displayHour.toString() + - ''; - } - else { - html = - '' + - '' + - displayHour.toString() + - '' + - ''; - } - return html; - }, - - /* Generate the content of a "Hour" cell */ - _generateHTMLMinuteCell: function (inst, minute, displayText) { - var html = ""; - var enabled = true; - var hour = inst.hours; - var onMinuteShow = this._get(inst, 'onMinuteShow'); //custom callback - var maxTime = this._get(inst, 'maxTime'); - var minTime = this._get(inst, 'minTime'); - - if (onMinuteShow) { - //NEW: 2011-02-03 we should give the hour as a parameter as well! - enabled = onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours,minute]); //trigger callback - } - - if (minute == undefined) { - html = ' '; - return html; - } - - if (enabled && hour !== null) { - if ( !isNaN(parseInt(maxTime.hour)) && !isNaN(parseInt(maxTime.minute)) && hour >= maxTime.hour && minute > maxTime.minute ) enabled = false; - if ( !isNaN(parseInt(minTime.hour)) && !isNaN(parseInt(minTime.minute)) && hour <= minTime.hour && minute < minTime.minute ) enabled = false; - } - - if (enabled) { - html = '' + - '' + - displayText + - ''; - } - else { - - html = '' + - '' + - displayText + - '' + - ''; - } - return html; - }, - - - /* Detach a timepicker from its control. - @param target element - the target input field or division or span */ - _destroyTimepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - $.removeData(target, PROP_NAME); - if (nodeName == 'input') { - inst.append.remove(); - inst.trigger.remove(); - $target.removeClass(this.markerClassName) - .unbind('focus.timepicker', this._showTimepicker) - .unbind('click.timepicker', this._adjustZIndex); - } else if (nodeName == 'div' || nodeName == 'span') - $target.removeClass(this.markerClassName).empty(); - }, - - /* Enable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _enableTimepicker: function(target) { - var $target = $(target), - target_id = $target.attr('id'), - inst = $.data(target, PROP_NAME); - - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = false; - var button = this._get(inst, 'button'); - $(button).removeClass('ui-state-disabled').disabled = false; - inst.trigger.filter('button'). - each(function() { this.disabled = false; }).end(); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().removeClass('ui-state-disabled'); - inline.find('button').each( - function() { this.disabled = false } - ) - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target_id ? null : value); }); // delete entry - }, - - /* Disable the time picker to a jQuery selection. - @param target element - the target input field or division or span */ - _disableTimepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - var button = this._get(inst, 'button'); - - $(button).addClass('ui-state-disabled').disabled = true; - target.disabled = true; - - inst.trigger.filter('button'). - each(function() { this.disabled = true; }).end(); - - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().addClass('ui-state-disabled'); - inline.find('button').each( - function() { this.disabled = true } - ) - - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - this._disabledInputs[this._disabledInputs.length] = $target.attr('id'); - }, - - /* Is the first field in a jQuery collection disabled as a timepicker? - @param target_id element - the target input field or division or span - @return boolean - true if disabled, false if enabled */ - _isDisabledTimepicker: function (target_id) { - if ( ! target_id) { return false; } - for (var i = 0; i < this._disabledInputs.length; i++) { - if (this._disabledInputs[i] == target_id) { return true; } - } - return false; - }, - - /* Check positioning to remain on screen. */ - _checkOffset: function (inst, offset, isFixed) { - var tpWidth = inst.tpDiv.outerWidth(); - var tpHeight = inst.tpDiv.outerHeight(); - var inputWidth = inst.input ? inst.input.outerWidth() : 0; - var inputHeight = inst.input ? inst.input.outerHeight() : 0; - var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft(); - var viewHeight = document.documentElement.clientHeight + $(document).scrollTop(); - - offset.left -= (this._get(inst, 'isRTL') ? (tpWidth - inputWidth) : 0); - offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; - offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; - - // now check if timepicker is showing outside window viewport - move to a better place if so. - offset.left -= Math.min(offset.left, (offset.left + tpWidth > viewWidth && viewWidth > tpWidth) ? - Math.abs(offset.left + tpWidth - viewWidth) : 0); - offset.top -= Math.min(offset.top, (offset.top + tpHeight > viewHeight && viewHeight > tpHeight) ? - Math.abs(tpHeight + inputHeight) : 0); - - return offset; - }, - - /* Find an object's position on the screen. */ - _findPos: function (obj) { - var inst = this._getInst(obj); - var isRTL = this._get(inst, 'isRTL'); - while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { - obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; - } - var position = $(obj).offset(); - return [position.left, position.top]; - }, - - /* Retrieve the size of left and top borders for an element. - @param elem (jQuery object) the element of interest - @return (number[2]) the left and top borders */ - _getBorders: function (elem) { - var convert = function (value) { - return { thin: 1, medium: 2, thick: 3}[value] || value; - }; - return [parseFloat(convert(elem.css('border-left-width'))), - parseFloat(convert(elem.css('border-top-width')))]; - }, - - - /* Close time picker if clicked elsewhere. */ - _checkExternalClick: function (event) { - if (!$.timepicker._curInst) { return; } - var $target = $(event.target); - if ($target[0].id != $.timepicker._mainDivId && - $target.parents('#' + $.timepicker._mainDivId).length == 0 && - !$target.hasClass($.timepicker.markerClassName) && - !$target.hasClass($.timepicker._triggerClass) && - $.timepicker._timepickerShowing && !($.timepicker._inDialog && $.blockUI)) - $.timepicker._hideTimepicker(); - }, - - /* Hide the time picker from view. - @param input element - the input field attached to the time picker */ - _hideTimepicker: function (input) { - var inst = this._curInst; - if (!inst || (input && inst != $.data(input, PROP_NAME))) { return; } - if (this._timepickerShowing) { - var showAnim = this._get(inst, 'showAnim'); - var duration = this._get(inst, 'duration'); - var postProcess = function () { - $.timepicker._tidyDialog(inst); - this._curInst = null; - }; - if ($.effects && $.effects[showAnim]) { - inst.tpDiv.hide(showAnim, $.timepicker._get(inst, 'showOptions'), duration, postProcess); - } - else { - inst.tpDiv[(showAnim == 'slideDown' ? 'slideUp' : - (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); - } - if (!showAnim) { postProcess(); } - - this._timepickerShowing = false; - - this._lastInput = null; - if (this._inDialog) { - this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); - if ($.blockUI) { - $.unblockUI(); - $('body').append(this.tpDiv); - } - } - this._inDialog = false; - - var onClose = this._get(inst, 'onClose'); - if (onClose) { - onClose.apply( - (inst.input ? inst.input[0] : null), - [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback - } - - } - }, - - - - /* Tidy up after a dialog display. */ - _tidyDialog: function (inst) { - inst.tpDiv.removeClass(this._dialogClass).unbind('.ui-timepicker'); - }, - - /* Retrieve the instance data for the target control. - @param target element - the target input field or division or span - @return object - the associated instance data - @throws error if a jQuery problem getting data */ - _getInst: function (target) { - try { - return $.data(target, PROP_NAME); - } - catch (err) { - throw 'Missing instance data for this timepicker'; - } - }, - - /* Get a setting value, defaulting if necessary. */ - _get: function (inst, name) { - return inst.settings[name] !== undefined ? - inst.settings[name] : this._defaults[name]; - }, - - /* Parse existing time and initialise time picker. */ - _setTimeFromField: function (inst) { - if (inst.input.val() == inst.lastVal) { return; } - var defaultTime = this._get(inst, 'defaultTime'); - - var timeToParse = defaultTime == 'now' ? this._getCurrentTimeRounded(inst) : defaultTime; - if ((inst.inline == false) && (inst.input.val() != '')) { timeToParse = inst.input.val() } - - if (timeToParse instanceof Date) { - inst.hours = timeToParse.getHours(); - inst.minutes = timeToParse.getMinutes(); - } else { - var timeVal = inst.lastVal = timeToParse; - if (timeToParse == '') { - inst.hours = -1; - inst.minutes = -1; - } else { - var time = this.parseTime(inst, timeVal); - inst.hours = time.hours; - inst.minutes = time.minutes; - } - } - - - $.timepicker._updateTimepicker(inst); - }, - - /* Update or retrieve the settings for an existing time picker. - @param target element - the target input field or division or span - @param name object - the new settings to update or - string - the name of the setting to change or retrieve, - when retrieving also 'all' for all instance settings or - 'defaults' for all global defaults - @param value any - the new value for the setting - (omit if above is an object or to retrieve a value) */ - _optionTimepicker: function(target, name, value) { - var inst = this._getInst(target); - if (arguments.length == 2 && typeof name == 'string') { - return (name == 'defaults' ? $.extend({}, $.timepicker._defaults) : - (inst ? (name == 'all' ? $.extend({}, inst.settings) : - this._get(inst, name)) : null)); - } - var settings = name || {}; - if (typeof name == 'string') { - settings = {}; - settings[name] = value; - } - if (inst) { - extendRemove(inst.settings, settings); - if (this._curInst == inst) { - this._hideTimepicker(); - this._updateTimepicker(inst); - } - if (inst.inline) { - this._updateTimepicker(inst); - } - } - }, - - - /* Set the time for a jQuery selection. - @param target element - the target input field or division or span - @param time String - the new time */ - _setTimeTimepicker: function(target, time) { - var inst = this._getInst(target); - if (inst) { - this._setTime(inst, time); - this._updateTimepicker(inst); - this._updateAlternate(inst, time); - } - }, - - /* Set the time directly. */ - _setTime: function(inst, time, noChange) { - var origHours = inst.hours; - var origMinutes = inst.minutes; - if (time instanceof Date) { - inst.hours = time.getHours(); - inst.minutes = time.getMinutes(); - } else { - var time = this.parseTime(inst, time); - inst.hours = time.hours; - inst.minutes = time.minutes; - } - - if ((origHours != inst.hours || origMinutes != inst.minutes) && !noChange) { - inst.input.trigger('change'); - } - this._updateTimepicker(inst); - this._updateSelectedValue(inst); - }, - - /* Return the current time, ready to be parsed, rounded to the closest minute by interval */ - _getCurrentTimeRounded: function (inst) { - var currentTime = new Date(), - currentMinutes = currentTime.getMinutes(), - minutes_options = this._get(inst, 'minutes'), - // round to closest interval - adjustedMinutes = Math.round(currentMinutes / minutes_options.interval) * minutes_options.interval; - currentTime.setMinutes(adjustedMinutes); - return currentTime; - }, - - /* - * Parse a time string into hours and minutes - */ - parseTime: function (inst, timeVal) { - var retVal = new Object(); - retVal.hours = -1; - retVal.minutes = -1; - - if(!timeVal) - return ''; - - var timeSeparator = this._get(inst, 'timeSeparator'), - amPmText = this._get(inst, 'amPmText'), - showHours = this._get(inst, 'showHours'), - showMinutes = this._get(inst, 'showMinutes'), - optionalMinutes = this._get(inst, 'optionalMinutes'), - showPeriod = (this._get(inst, 'showPeriod') == true), - p = timeVal.indexOf(timeSeparator); - - // check if time separator found - if (p != -1) { - retVal.hours = parseInt(timeVal.substr(0, p), 10); - retVal.minutes = parseInt(timeVal.substr(p + 1), 10); - } - // check for hours only - else if ( (showHours) && ( !showMinutes || optionalMinutes ) ) { - retVal.hours = parseInt(timeVal, 10); - } - // check for minutes only - else if ( ( ! showHours) && (showMinutes) ) { - retVal.minutes = parseInt(timeVal, 10); - } - - if (showHours) { - var timeValUpper = timeVal.toUpperCase(); - if ((retVal.hours < 12) && (showPeriod) && (timeValUpper.indexOf(amPmText[1].toUpperCase()) != -1)) { - retVal.hours += 12; - } - // fix for 12 AM - if ((retVal.hours == 12) && (showPeriod) && (timeValUpper.indexOf(amPmText[0].toUpperCase()) != -1)) { - retVal.hours = 0; - } - } - - return retVal; - }, - - selectNow: function(event) { - var id = $(event.target).attr("data-timepicker-instance-id"), - $target = $(id), - inst = this._getInst($target[0]); - //if (!inst || (input && inst != $.data(input, PROP_NAME))) { return; } - var currentTime = new Date(); - inst.hours = currentTime.getHours(); - inst.minutes = currentTime.getMinutes(); - this._updateSelectedValue(inst); - this._updateTimepicker(inst); - this._hideTimepicker(); - }, - - deselectTime: function(event) { - var id = $(event.target).attr("data-timepicker-instance-id"), - $target = $(id), - inst = this._getInst($target[0]); - inst.hours = -1; - inst.minutes = -1; - this._updateSelectedValue(inst); - this._hideTimepicker(); - }, - - - selectHours: function (event) { - var $td = $(event.currentTarget), - id = $td.attr("data-timepicker-instance-id"), - newHours = parseInt($td.attr("data-hour")), - fromDoubleClick = event.data.fromDoubleClick, - $target = $(id), - inst = this._getInst($target[0]), - showMinutes = (this._get(inst, 'showMinutes') == true); - - // don't select if disabled - if ( $.timepicker._isDisabledTimepicker($target.attr('id')) ) { return false } - - $td.parents('.ui-timepicker-hours:first').find('a').removeClass('ui-state-active'); - $td.children('a').addClass('ui-state-active'); - inst.hours = newHours; - - // added for onMinuteShow callback - var onMinuteShow = this._get(inst, 'onMinuteShow'), - maxTime = this._get(inst, 'maxTime'), - minTime = this._get(inst, 'minTime'); - if (onMinuteShow || !isNaN(parseInt(maxTime.minute)) || !isNaN(parseInt(minTime.minute))) { - // this will trigger a callback on selected hour to make sure selected minute is allowed. - this._updateMinuteDisplay(inst); - } - - this._updateSelectedValue(inst); - - inst._hoursClicked = true; - if ((inst._minutesClicked) || (fromDoubleClick) || (showMinutes == false)) { - $.timepicker._hideTimepicker(); - } - // return false because if used inline, prevent the url to change to a hashtag - return false; - }, - - selectMinutes: function (event) { - var $td = $(event.currentTarget), - id = $td.attr("data-timepicker-instance-id"), - newMinutes = parseInt($td.attr("data-minute")), - fromDoubleClick = event.data.fromDoubleClick, - $target = $(id), - inst = this._getInst($target[0]), - showHours = (this._get(inst, 'showHours') == true); - - // don't select if disabled - if ( $.timepicker._isDisabledTimepicker($target.attr('id')) ) { return false } - - $td.parents('.ui-timepicker-minutes:first').find('a').removeClass('ui-state-active'); - $td.children('a').addClass('ui-state-active'); - - inst.minutes = newMinutes; - this._updateSelectedValue(inst); - - inst._minutesClicked = true; - if ((inst._hoursClicked) || (fromDoubleClick) || (showHours == false)) { - $.timepicker._hideTimepicker(); - // return false because if used inline, prevent the url to change to a hashtag - return false; - } - - // return false because if used inline, prevent the url to change to a hashtag - return false; - }, - - _updateSelectedValue: function (inst) { - var newTime = this._getParsedTime(inst); - if (inst.input) { - inst.input.val(newTime); - inst.input.trigger('change'); - } - var onSelect = this._get(inst, 'onSelect'); - if (onSelect) { onSelect.apply((inst.input ? inst.input[0] : null), [newTime, inst]); } // trigger custom callback - this._updateAlternate(inst, newTime); - return newTime; - }, - - /* this function process selected time and return it parsed according to instance options */ - _getParsedTime: function(inst) { - - if (inst.hours == -1 && inst.minutes == -1) { - return ''; - } - - // default to 0 AM if hours is not valid - if ((inst.hours < inst.hours.starts) || (inst.hours > inst.hours.ends )) { inst.hours = 0; } - // default to 0 minutes if minute is not valid - if ((inst.minutes < inst.minutes.starts) || (inst.minutes > inst.minutes.ends)) { inst.minutes = 0; } - - var period = "", - showPeriod = (this._get(inst, 'showPeriod') == true), - showLeadingZero = (this._get(inst, 'showLeadingZero') == true), - showHours = (this._get(inst, 'showHours') == true), - showMinutes = (this._get(inst, 'showMinutes') == true), - optionalMinutes = (this._get(inst, 'optionalMinutes') == true), - amPmText = this._get(inst, 'amPmText'), - selectedHours = inst.hours ? inst.hours : 0, - selectedMinutes = inst.minutes ? inst.minutes : 0, - displayHours = selectedHours ? selectedHours : 0, - parsedTime = ''; - - // fix some display problem when hours or minutes are not selected yet - if (displayHours == -1) { displayHours = 0 } - if (selectedMinutes == -1) { selectedMinutes = 0 } - - if (showPeriod) { - if (inst.hours == 0) { - displayHours = 12; - } - if (inst.hours < 12) { - period = amPmText[0]; - } - else { - period = amPmText[1]; - if (displayHours > 12) { - displayHours -= 12; - } - } - } - - var h = displayHours.toString(); - if (showLeadingZero && (displayHours < 10)) { h = '0' + h; } - - var m = selectedMinutes.toString(); - if (selectedMinutes < 10) { m = '0' + m; } - - if (showHours) { - parsedTime += h; - } - if (showHours && showMinutes && (!optionalMinutes || m != 0)) { - parsedTime += this._get(inst, 'timeSeparator'); - } - if (showMinutes && (!optionalMinutes || m != 0)) { - parsedTime += m; - } - if (showHours) { - if (period.length > 0) { parsedTime += this._get(inst, 'periodSeparator') + period; } - } - - return parsedTime; - }, - - /* Update any alternate field to synchronise with the main field. */ - _updateAlternate: function(inst, newTime) { - var altField = this._get(inst, 'altField'); - if (altField) { // update alternate field too - $(altField).each(function(i,e) { - $(e).val(newTime); - }); - } - }, - - _getTimeAsDateTimepicker: function(input) { - var inst = this._getInst(input); - if (inst.hours == -1 && inst.minutes == -1) { - return ''; - } - - // default to 0 AM if hours is not valid - if ((inst.hours < inst.hours.starts) || (inst.hours > inst.hours.ends )) { inst.hours = 0; } - // default to 0 minutes if minute is not valid - if ((inst.minutes < inst.minutes.starts) || (inst.minutes > inst.minutes.ends)) { inst.minutes = 0; } - - return new Date(0, 0, 0, inst.hours, inst.minutes, 0); - }, - /* This might look unused but it's called by the $.fn.timepicker function with param getTime */ - /* added v 0.2.3 - gitHub issue #5 - Thanks edanuff */ - _getTimeTimepicker : function(input) { - var inst = this._getInst(input); - return this._getParsedTime(inst); - }, - _getHourTimepicker: function(input) { - var inst = this._getInst(input); - if ( inst == undefined) { return -1; } - return inst.hours; - }, - _getMinuteTimepicker: function(input) { - var inst= this._getInst(input); - if ( inst == undefined) { return -1; } - return inst.minutes; - } - - }); - - - - /* Invoke the timepicker functionality. - @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new timepicker functionality - @return jQuery object */ - $.fn.timepicker = function (options) { - /* Initialise the time picker. */ - if (!$.timepicker.initialized) { - $(document).mousedown($.timepicker._checkExternalClick); - $.timepicker.initialized = true; - } - - /* Append timepicker main container to body if not exist. */ - if ($("#"+$.timepicker._mainDivId).length === 0) { - $('body').append($.timepicker.tpDiv); - } - - var otherArgs = Array.prototype.slice.call(arguments, 1); - if (typeof options == 'string' && (options == 'getTime' || options == 'getTimeAsDate' || options == 'getHour' || options == 'getMinute' )) - return $.timepicker['_' + options + 'Timepicker']. - apply($.timepicker, [this[0]].concat(otherArgs)); - if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') - return $.timepicker['_' + options + 'Timepicker']. - apply($.timepicker, [this[0]].concat(otherArgs)); - return this.each(function () { - typeof options == 'string' ? - $.timepicker['_' + options + 'Timepicker']. - apply($.timepicker, [this].concat(otherArgs)) : - $.timepicker._attachTimepicker(this, options); - }); - }; - - /* jQuery extend now ignores nulls! */ - function extendRemove(target, props) { - $.extend(target, props); - for (var name in props) - if (props[name] == null || props[name] == undefined) - target[name] = props[name]; - return target; - }; - - $.timepicker = new Timepicker(); // singleton instance - $.timepicker.initialized = false; - $.timepicker.uuid = new Date().getTime(); - $.timepicker.version = "0.3.3"; - - // Workaround for #4055 - // Add another global to avoid noConflict issues with inline event handlers - window['TP_jQuery_' + tpuuid] = $; - -})(jQuery); diff --git a/js/legacy/markdown-it-checkbox.js b/js/legacy/markdown-it-checkbox.js deleted file mode 100644 index a156bc822..000000000 --- a/js/legacy/markdown-it-checkbox.js +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Original source code from https://github.com/mcecot/markdown-it-checkbox - * © 2015 Markus Cecot - * licenced under MIT - * https://github.com/mcecot/markdown-it-checkbox/blob/master/LICENSE - */ -var checkboxReplace; - -checkboxReplace = function(md, options, Token) { - "use strict"; - var arrayReplaceAt, createTokens, defaults, lastId, pattern, splitTextToken; - arrayReplaceAt = md.utils.arrayReplaceAt; - lastId = 0; - defaults = { - divWrap: false, - divClass: 'checkbox', - idPrefix: 'checkbox' - }; - options = Object.assign(defaults, options); - pattern = /(.*?)(\[(X|\s|\_|\-)\])(.*)/igm; - createTokens = function(checked, label, Token, before) { - var id, idNumeric, nodes, token; - nodes = []; - - token = new Token("text", "", 0); - token.content = before; - nodes.push(token); - - /** - *
      - */ - if (options.divWrap) { - token = new Token("checkbox_open", "div", 1); - token.attrs = [["class", options.divClass]]; - nodes.push(token); - } - - /** - * - */ - id = options.idPrefix + lastId; - idNumeric = lastId; - lastId += 1; - token = new Token("checkbox_input", "input", 0); - token.attrs = [["type", "checkbox"], ["id", id], ["data-id", idNumeric]]; - if (checked === true) { - token.attrs.push(["checked", "true"]); - } - token.attrs.push(["class", "checkbox"]); - nodes.push(token); - - /** - *
      +
      + +
      +
      Description
      @@ -97,6 +102,7 @@ import { Actions } from 'nextcloud-vue/dist/Components/Actions' import { ActionButton } from 'nextcloud-vue/dist/Components/ActionButton' import ActivityEntry from '../ActivityEntry' import Color from '../../mixins/color' +import { CollectionList } from 'nextcloud-vue-collections' export default { name: 'CardSidebar', @@ -109,7 +115,8 @@ export default { VueEasymde, Actions, ActionButton, - Avatar + Avatar, + CollectionList }, mixins: [ Color diff --git a/src/init-collections.js b/src/init-collections.js new file mode 100644 index 000000000..492b4644b --- /dev/null +++ b/src/init-collections.js @@ -0,0 +1,94 @@ +/* + * @copyright Copyright (c) 2019 Julius Härtl + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see . + * + */ + +import Vue from 'vue' + +import BoardSelector from './BoardSelector' +import CardSelector from './CardSelector' + +import './../css/collections.css' + +// eslint-disable-next-line +__webpack_nonce__ = btoa(OC.requestToken); +// eslint-disable-next-line +__webpack_public_path__ = OC.linkTo('deck', 'js/'); + +Vue.prototype.t = t +Vue.prototype.n = n +Vue.prototype.OC = OC; + +((function(OCP) { + + OCP.Collaboration.registerType('deck', { + action: () => { + return new Promise((resolve, reject) => { + const container = document.createElement('div') + container.id = 'deck-board-select' + const body = document.getElementById('body-user') + body.append(container) + const ComponentVM = new Vue({ + render: h => h(BoardSelector) + }) + ComponentVM.$mount(container) + ComponentVM.$root.$on('close', () => { + ComponentVM.$el.remove() + ComponentVM.$destroy() + reject(new Error('Board selection canceled')) + }) + ComponentVM.$root.$on('select', (id) => { + resolve(id) + ComponentVM.$el.remove() + ComponentVM.$destroy() + }) + }) + }, + typeString: t('deck', 'Link to a board'), + typeIconClass: 'icon-deck' + }) + + OCP.Collaboration.registerType('deck-card', { + action: () => { + return new Promise((resolve, reject) => { + const container = document.createElement('div') + container.id = 'deck-board-select' + const body = document.getElementById('body-user') + body.append(container) + const ComponentVM = new Vue({ + render: h => h(CardSelector) + }) + ComponentVM.$mount(container) + ComponentVM.$root.$on('close', () => { + ComponentVM.$el.remove() + ComponentVM.$destroy() + reject(new Error('Card selection canceled')) + }) + ComponentVM.$root.$on('select', (id) => { + resolve(id) + ComponentVM.$el.remove() + ComponentVM.$destroy() + }) + }) + }, + typeString: t('deck', 'Link to a card'), + typeIconClass: 'icon-deck' + }) +})(window.OCP)) diff --git a/webpack.common.js b/webpack.common.js index abc2c38cd..eb9cee08d 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -2,11 +2,14 @@ const path = require('path'); const { VueLoaderPlugin } = require('vue-loader'); module.exports = { - entry: path.join(__dirname, 'src', 'main.js'), + entry: { + deck: path.join(__dirname, 'src', 'main.js'), + collections: path.join(__dirname, 'src', 'init-collections.js'), + }, output: { - path: path.resolve(__dirname, './js'), + filename: '[name].js', + path: __dirname + '/js', publicPath: '/js/', - filename: 'deck.js', jsonpFunction: 'webpackJsonpOCADeck' }, module: { @@ -34,7 +37,7 @@ module.exports = { }, { test: /\.(png|jpg|gif|svg)$/, - loader: 'file-loader', + loader: 'url-loader', options: { name: '[name].[ext]?[hash]' }