From d03da7c7e5192bd170f657bc9ace81e457fb87e9 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Wed, 4 May 2016 11:31:11 +0200 Subject: fetch and show list of calendars --- bower.json | 4 +- css/mail.css | 8 +++ js/app.js | 4 ++ js/models/dav/calendar.js | 26 +++++++++ js/radio.js | 16 +++--- js/require_config.js | 5 ++ js/service/davservice.js | 108 +++++++++++++++++++++++++++++++++++ js/templates/calendar.html | 1 + js/templates/message-attachment.html | 3 +- js/views/app.js | 4 ++ js/views/calendarspopoverview.js | 30 ++++++++++ js/views/calendarview.js | 31 ++++++++++ js/views/messageattachment.js | 43 +++++++++++--- 13 files changed, 265 insertions(+), 18 deletions(-) create mode 100644 js/models/dav/calendar.js create mode 100644 js/service/davservice.js create mode 100644 js/templates/calendar.html create mode 100644 js/views/calendarspopoverview.js create mode 100644 js/views/calendarview.js diff --git a/bower.json b/bower.json index 8e81edf0d..1daeb3bf7 100644 --- a/bower.json +++ b/bower.json @@ -25,6 +25,8 @@ "jquery-visibility": "~1.0.11", "requirejs": "2.2.0", "text": "^2.0.14", - "underscore": "~1.8.3" + "underscore": "~1.8.3", + "davclient.js": "git@github.com:evert/davclient.js.git", + "es6-promise": "^3.2.1" } } diff --git a/css/mail.css b/css/mail.css index 8a5172a1c..cf97c2a2d 100755 --- a/css/mail.css +++ b/css/mail.css @@ -679,6 +679,14 @@ input.submit-message, .attachment-import { right: 79px; } +.attachment-import-popover { + right: -17px; + top: 56px; +} +.attachment-import-popover::after { + left: 30px; + right: initial; +} /* show icon + text for Download all button as well as when there is only one attachment */ .attachments-save-to-cloud, diff --git a/js/app.js b/js/app.js index 57cfb47dc..67371932a 100644 --- a/js/app.js +++ b/js/app.js @@ -22,6 +22,9 @@ define(function(require) { 'use strict'; + // Enable ES6 promise polyfill + require('es6-promise').polyfill(); + var $ = require('jquery'); var Backbone = require('backbone'); var Handlebars = require('handlebars'); @@ -39,6 +42,7 @@ define(function(require) { require('controller/messagecontroller'); require('service/accountservice'); require('service/attachmentservice'); + require('service/davservice'); require('service/folderservice'); require('service/messageservice'); require('notification'); diff --git a/js/models/dav/calendar.js b/js/models/dav/calendar.js new file mode 100644 index 000000000..e7f0b18bb --- /dev/null +++ b/js/models/dav/calendar.js @@ -0,0 +1,26 @@ +/** + * @author Christoph Wurst + * + * ownCloud - Mail + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +define(function(require) { + 'use strict'; + + var Backbone = require('backbone'); + + return Backbone.Model.extend({}); +}); \ No newline at end of file diff --git a/js/radio.js b/js/radio.js index f365b0ab8..306bcb009 100644 --- a/js/radio.js +++ b/js/radio.js @@ -13,22 +13,24 @@ define(function(require) { var Radio = require('backbone.radio'); - var uiChannel = Radio.channel('ui'); - var notificationChannel = Radio.channel('notification'); - var stateChannel = Radio.channel('state'); var accountChannel = Radio.channel('account'); var folderChannel = Radio.channel('folder'); + var davChannel = Radio.channel('dav'); var messageChannel = Radio.channel('message'); var navigationChannel = Radio.channel('navigation'); + var notificationChannel = Radio.channel('notification'); + var stateChannel = Radio.channel('state'); + var uiChannel = Radio.channel('ui'); var channels = { - ui: uiChannel, - notification: notificationChannel, - state: stateChannel, account: accountChannel, + dav: davChannel, folder: folderChannel, message: messageChannel, - navigation: navigationChannel + navigation: navigationChannel, + notification: notificationChannel, + state: stateChannel, + ui: uiChannel }; // Log all events to the console diff --git a/js/require_config.js b/js/require_config.js index a990956f9..d2a272f62 100644 --- a/js/require_config.js +++ b/js/require_config.js @@ -21,11 +21,16 @@ */ backbone: 'vendor/backbone/backbone', 'backbone.radio': 'vendor/backbone.radio/build/backbone.radio', + davclient: 'vendor/davclient.js/lib/client', domready: 'vendor/domReady/domReady', + 'es6-promise': 'vendor/es6-promise/es6-promise.min', handlebars: 'vendor/handlebars/handlebars', marionette: 'vendor/backbone.marionette/lib/backbone.marionette', underscore: 'vendor/underscore/underscore', text: 'vendor/text/text' + }, + davclient: { + exports: 'dav' } }); diff --git a/js/service/davservice.js b/js/service/davservice.js new file mode 100644 index 000000000..edf83e7c9 --- /dev/null +++ b/js/service/davservice.js @@ -0,0 +1,108 @@ +/** + * @author Christoph Wurst + * + * ownCloud - Mail + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +define(function(require) { + 'use strict'; + + var _ = require('underscore'); + var $ = require('jquery'); + var Backbone = require('backbone'); + var dav = require('davclient'); + var OC = require('OC'); + var Radio = require('radio'); + var Calendar = require('models/dav/calendar'); + + Radio.dav.reply('calendars', getUserCalendars); + + var client = new dav.Client({ + baseUrl: OC.linkToRemote('dav/calendars'), + xmlNamespaces: { + 'DAV:': 'd', + 'urn:ietf:params:xml:ns:caldav': 'c', + 'http://apple.com/ns/ical/': 'aapl', + 'http://owncloud.org/ns': 'oc', + 'http://calendarserver.org/ns/': 'cs' + } + }); + var props = [ + '{DAV:}displayname', + '{urn:ietf:params:xml:ns:caldav}calendar-description', + '{urn:ietf:params:xml:ns:caldav}calendar-timezone', + '{http://apple.com/ns/ical/}calendar-order', + '{http://apple.com/ns/ical/}calendar-color', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set', + '{http://owncloud.org/ns}calendar-enabled', + '{DAV:}acl', + '{DAV:}owner', + '{http://owncloud.org/ns}invite' + ]; + + function getResponseCodeFromHTTPResponse(t) { + return parseInt(t.split(' ')[1]); + } + + function getCalendarData(properties) { + var data = { + displayname: properties['{DAV:}displayname'], + color: properties['{http://apple.com/ns/ical/}calendar-color'], + order: properties['{http://apple.com/ns/ical/}calendar-order'], + components: { + vevent: false + } + }; + + var components = properties['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'] || []; + for (var i = 0; i < components.length; i++) { + var name = components[i].attributes.getNamedItem('name').textContent.toLowerCase(); + if (data.components.hasOwnProperty(name)) { + data.components[name] = true; + } + } + + return data; + } + + function getUserCalendars() { + var defer = $.Deferred(); + var url = OC.linkToRemote('dav/calendars') + '/' + OC.currentUser + '/'; + + client.propFind(url, props, 1, { + 'requesttoken': OC.requestToken + }).then(function(data) { + var calendars = new Backbone.Collection(); + + _.each(data.body, function(cal) { + if (cal.propStat.length < 1) { + return; + } + if (getResponseCodeFromHTTPResponse(cal.propStat[0].status) === 200) { + var properties = getCalendarData(cal.propStat[0].properties); + if (properties && properties.components.vevent) { + calendars.push(new Calendar(properties)); + } + } + }); + defer.resolve(calendars); + }, function() { + defer.reject(); + }); + + return defer.promise(); + } +}); diff --git a/js/templates/calendar.html b/js/templates/calendar.html new file mode 100644 index 000000000..c1e9bae6b --- /dev/null +++ b/js/templates/calendar.html @@ -0,0 +1 @@ +{{displayname}} \ No newline at end of file diff --git a/js/templates/message-attachment.html b/js/templates/message-attachment.html index 7fab1c1f1..2591d478b 100644 --- a/js/templates/message-attachment.html +++ b/js/templates/message-attachment.html @@ -8,4 +8,5 @@ {{/if}} - \ No newline at end of file + + \ No newline at end of file diff --git a/js/views/app.js b/js/views/app.js index 08a4ca699..cba1ee983 100644 --- a/js/views/app.js +++ b/js/views/app.js @@ -62,6 +62,10 @@ define(function(require) { window.addEventListener('resize', this.onWindowResize); + $(document).on('click', function(e) { + Radio.ui.trigger('document:click', e); + }); + // TODO: create marionette view and encapsulate events $(document).on('click', '#forward-button', function() { Radio.message.trigger('forward'); diff --git a/js/views/calendarspopoverview.js b/js/views/calendarspopoverview.js new file mode 100644 index 000000000..f2693cbb2 --- /dev/null +++ b/js/views/calendarspopoverview.js @@ -0,0 +1,30 @@ +/** + * @author Christoph Wurst + * + * ownCloud - Mail + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +define(function(require) { + 'use strict'; + + var Marionette = require('marionette'); + var CalendarView = require('views/calendarview'); + + return Marionette.CollectionView.extend({ + childView: CalendarView, + tagName: 'ul' + }); +}); diff --git a/js/views/calendarview.js b/js/views/calendarview.js new file mode 100644 index 000000000..9b2e3ffee --- /dev/null +++ b/js/views/calendarview.js @@ -0,0 +1,31 @@ +/** + * @author Christoph Wurst + * + * ownCloud - Mail + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +define(function(require) { + 'use strict'; + + var Marionette = require('marionette'); + var Handlebars = require('handlebars'); + var CalendarTemplate = require('text!templates/calendar.html'); + + return Marionette.ItemView.extend({ + template: Handlebars.compile(CalendarTemplate), + tagName: 'li' + }); +}); diff --git a/js/views/messageattachment.js b/js/views/messageattachment.js index 4cb80998a..944c6b072 100644 --- a/js/views/messageattachment.js +++ b/js/views/messageattachment.js @@ -25,6 +25,7 @@ define(function(require) { var Marionette = require('marionette'); var Radio = require('radio'); var MessageController = require('controller/messagecontroller'); + var CalendarsPopoverView = require('views/calendarspopoverview'); var MessageAttachmentTemplate = require('text!templates/message-attachment.html'); /** @@ -35,15 +36,26 @@ define(function(require) { ui: { 'downloadButton': '.attachment-download', 'saveToCloudButton': '.attachment-save-to-cloud', - 'importCalendarEventButton': '.attachment-import.calendar' + 'importCalendarEventButton': '.attachment-import.calendar', + 'attachmentImportPopover': '.attachment-import-popover' }, events: { - 'click': '_onDownload', + 'click': '_onClick', 'click @ui.saveToCloudButton': '_onSaveToCloud', 'click @ui.importCalendarEventButton': '_onImportCalendarEvent' }, - _onDownload: function(e) { + initialize: function() { + this.listenTo(Radio.ui, 'document:click', this._closeImportPopover); + }, + _onClick: function(e) { if (!e.isDefaultPrevented()) { + var $target = $(e.target); + if ($target.hasClass('select-calendar')) { + var url = $target.data('calendar-url'); + alert(url); + return; + } + e.preventDefault(); window.location = this.model.get('downloadUrl'); } @@ -79,21 +91,34 @@ define(function(require) { .addClass('icon-loading-small'); var url = this.model.get('downloadUrl'); - var downloading = Radio.message.request('attachment:download', url); + var downloadingAttachment = Radio.message.request('attachment:download', url); + var fetchingCalendars = Radio.dav.request('calendars'); var _this = this; - $.when(downloading).done(function(data) { - console.log(data); - }); - $.when(downloading.fail(function() { + $.when(downloadingAttachment.fail(function() { Radio.ui.trigger('error:show', t('Error while downloading calendar event')); })); - $.when(downloading).always(function() { + $.when(fetchingCalendars, downloadingAttachment).always(function() { _this.ui.importCalendarEventButton .removeClass('icon-loading-small') .addClass('icon-add'); }); + $.when(fetchingCalendars, downloadingAttachment). + done(function(calendars, ics) { + _this.ui.attachmentImportPopover.removeClass('hidden'); + var calendarsView = new CalendarsPopoverView({ + collection: calendars + }); + calendarsView.render(); + _this.ui.attachmentImportPopover.html(calendarsView.$el); + }); + }, + _closeImportPopover: function(e) { + var $target = $(e.target); + if (this.$el.find($target).length === 0) { + this.ui.attachmentImportPopover.addClass('hidden'); + } } }); -- cgit v1.2.3