diff --git a/www/calendar/app-calendar.less b/www/calendar/app-calendar.less
index 38aee3973..69be43ab6 100644
--- a/www/calendar/app-calendar.less
+++ b/www/calendar/app-calendar.less
@@ -1,6 +1,7 @@
@import (reference) '../../customize/src/less2/include/framework.less';
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
@import (reference) '../../customize/src/less2/include/tools.less';
+@import (reference) '../../customize/src/less2/include/avatar.less';
&.cp-app-calendar {
@@ -104,6 +105,22 @@
}
.cp-calendar-list {
+ .cp-calendar-team {
+ height: 30px;
+ .avatar_main(30px);
+ .cp-avatar {
+ margin-right: 10px;
+ }
+ .cp-name {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin: 5px 0;
+ }
.cp-calendar-entry {
display: flex;
align-items: center;
diff --git a/www/calendar/inner.js b/www/calendar/inner.js
index 660b8f2a1..f51fc240a 100644
--- a/www/calendar/inner.js
+++ b/www/calendar/inner.js
@@ -16,6 +16,10 @@ define([
'/customize/application_config.js',
'/lib/calendar/tui-calendar.min.js',
+ '/common/inner/share.js',
+ '/common/inner/access.js',
+ '/common/inner/properties.js',
+
'/common/jscolor.js',
'css!/lib/calendar/tui-calendar.min.css',
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
@@ -36,7 +40,8 @@ define([
h,
Messages,
AppConfig,
- Calendar
+ Calendar,
+ Share, Access, Properties
)
{
var APP = window.APP = {
@@ -57,6 +62,7 @@ Messages.calendar_deleteConfirm = "Are you sure you want to delete this calendar
Messages.calendar_deleteTeamConfirm = "Are you sure you want to delete this calendar from this team?";
Messages.calendar_deleteOwned = " It will still be visible for the users it has been shared with.";
Messages.calendar_errorNoCalendar = "No editable calendar selected!";
+Messages.calendar_myCalendars = "My calendars";
var onCalendarsUpdate = Util.mkEvent();
@@ -310,6 +316,36 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
action: function (e) {
e.stopPropagation();
editCalendar(id);
+ return true;
+ }
+ }, {
+ tag: 'a',
+ attributes: {
+ 'class': 'fa fa-shhare-alt',
+ },
+ content: h('span', Messages.shareButton),
+ action: function (e) {
+ e.stopPropagation();
+ var friends = common.getFriends();
+ var cal = APP.calendars[id];
+ var title = Util.find(cal, ['content', 'metadata', 'title']);
+ var color = Util.find(cal, ['content', 'metadata', 'color']);
+ Share.getShareModal(common, {
+ teamId: teamId === 1 ? undefined : teamId,
+ origin: APP.origin,
+ pathname: "/calendar/",
+ friends: friends,
+ title: title,
+ password: cal.password, // XXX support passwords
+ calendar: {
+ title: title,
+ color: color,
+ channel: id,
+ },
+ common: common,
+ hashes: cal.hashes
+ });
+ return true;
}
}, {
tag: 'a',
@@ -361,7 +397,9 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
var md = Util.find(data, ['content', 'metadata']);
if (!md) { return; }
var active = data.hidden ? '' : '.cp-active';
- var calendar = h('div.cp-calendar-entry'+active, [
+ var calendar = h('div.cp-calendar-entry'+active, {
+ 'data-uid': id
+ }, [
h('span.cp-calendar-color', {
style: 'background-color: '+md.color+';'
}),
@@ -370,7 +408,12 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
]);
$(calendar).click(function () {
data.hidden = !data.hidden;
- $(calendar).toggleClass('cp-active', !data.hidden);
+ if (APP.$calendars) {
+ APP.$calendars.find('[data-uid="'+id+'"]').toggleClass('cp-active', !data.hidden);
+ } else {
+ $(calendar).toggleClass('cp-active', !data.hidden);
+ }
+
renderCalendar();
});
if (APP.$calendars) { APP.$calendars.append(calendar); }
@@ -436,10 +479,35 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
var $calendars = APP.$calendars = $(calendars).appendTo($container);
onCalendarsUpdate.reg(function () {
$calendars.empty();
- Object.keys(APP.calendars || {}).forEach(function (id) {
- var cal = APP.calendars[id];
- if (!cal) { return; }
- (cal.teams || []).forEach(function (teamId) {
+ var metadataMgr = common.getMetadataMgr();
+ var privateData = metadataMgr.getPrivateData();
+ var filter = function (teamId) {
+ return Object.keys(APP.calendars || {}).filter(function (id) {
+ var cal = APP.calendars[id] || {};
+ var teams = cal.teams || [];
+ return teams.indexOf(teamId || 1) !== -1;
+ });
+ };
+ var myCalendars = filter(1);
+ if (myCalendars.length) {
+ APP.$calendars.append(h('div.cp-calendar-team', [
+ h('span', Messages.calendar_myCalendars)
+ ]));
+ }
+ myCalendars.forEach(function (id) {
+ makeCalendarEntry(id, 1);
+ });
+ Object.keys(privateData.teams).forEach(function (teamId) {
+ var calendars = filter(teamId);
+ if (!calendars.length) { return; }
+ var team = privateData.teams[teamId];
+ var avatar = h('span.cp-avatar');
+ common.displayAvatar($(avatar), team.avatar, team.displayName);
+ APP.$calendars.append(h('div.cp-calendar-team', [
+ avatar,
+ h('span.cp-name', {title: team.name}, team.name)
+ ]));
+ calendars.forEach(function (id) {
makeCalendarEntry(id, teamId);
});
});
diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js
index 92ecb4b4e..6c6c51c26 100644
--- a/www/common/common-ui-elements.js
+++ b/www/common/common-ui-elements.js
@@ -1350,13 +1350,20 @@ define([
var $innerblock = $('
', {'class': 'cp-dropdown-content'});
if (config.left) { $innerblock.addClass('cp-dropdown-left'); }
+ var hide = function () {
+ window.setTimeout(function () { $innerblock.hide(); }, 0);
+ };
+
config.options.forEach(function (o) {
if (!isValidOption(o)) { return; }
if (isElement(o)) { return $innerblock.append($(o)); }
var $el = $('<' + o.tag + '>', o.attributes || {}).html(o.content || '');
$el.appendTo($innerblock);
if (typeof(o.action) === 'function') {
- $el.click(o.action);
+ $el.click(function (e) {
+ var close = o.action(e);
+ if (close) { hide(); }
+ });
}
});
@@ -1376,10 +1383,6 @@ define([
}
};
- var hide = function () {
- window.setTimeout(function () { $innerblock.hide(); }, 0);
- };
-
var show = function () {
var wh = $(window).height();
var button = $button[0].getBoundingClientRect();
diff --git a/www/common/inner/share.js b/www/common/inner/share.js
index 614fc23e7..f47fe5add 100644
--- a/www/common/inner/share.js
+++ b/www/common/inner/share.js
@@ -111,6 +111,7 @@ define([
password: config.password,
isTemplate: config.isTemplate,
name: myName,
+ isCalendar: Boolean(config.calendar),
title: title
}, {
viewed: team && team.id,
@@ -122,6 +123,19 @@ define([
}
// If it's a team with edit right, add the pad directly
if (!team) { return; }
+ if (config.calendar) {
+ var calendarModule = common.makeUniversal('calendar');
+ var calendarData = config.calendar;
+ calendarData.href = href;
+ calendarData.teamId = team.id;
+ calendarModule.execCommand('ADD', calendarData, function (obj) {
+ if (obj && obj.error) {
+ console.error(obj.error);
+ return void UI.warn(Messages.error);
+ }
+ });
+ return;
+ }
sframeChan.query('Q_STORE_IN_TEAM', {
href: href,
password: config.password,
diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js
index 6ce036e53..5c7f3623c 100644
--- a/www/common/outer/async-store.js
+++ b/www/common/outer/async-store.js
@@ -2670,6 +2670,7 @@ define([
}, true);
}).nThen(function (waitFor) {
loadUniversal(Team, 'team', waitFor, clientId);
+ }).nThen(function (waitFor) {
loadUniversal(Calendar, 'calendar', waitFor);
}).nThen(function () {
cb();
diff --git a/www/common/outer/calendar.js b/www/common/outer/calendar.js
index a5d4b91a6..cc17ca674 100644
--- a/www/common/outer/calendar.js
+++ b/www/common/outer/calendar.js
@@ -102,7 +102,8 @@ ctx.calendars[channel] = {
deleted: !c.stores.length,
restricted: c.restricted,
owned: ctx.Store.isOwned(c.owners),
- content: Util.clone(c.proxy)
+ content: Util.clone(c.proxy),
+ hashes: c.hashes
}, ctx.clients);
};
@@ -127,14 +128,21 @@ ctx.calendars[channel] = {
if (!channel) { return; }
var c = ctx.calendars[channel];
+
+ var update = function () {
+ sendUpdate(ctx, c);
+ };
+
if (c) {
- if (c.stores && c.stores.indexOf(teamId) !== -1) { return; }
if (c.readOnly && data.href) {
// XXX UPGRADE
+ // c.hashes.editHash =
// XXX different cases if already ready or not?
}
+ if (c.stores && c.stores.indexOf(teamId) !== -1) { return void cb(); }
c.stores.push(teamId);
- return;
+ update();
+ return void cb();
}
// Multiple teams can have the same calendar. Make sure we remember the list of stores
@@ -143,12 +151,8 @@ ctx.calendars[channel] = {
ready: false,
channel: channel,
readOnly: !data.href,
- stores: [teamId]
- };
-
- var update = function () {
- console.log(ctx.clients);
- sendUpdate(ctx, c);
+ stores: [teamId],
+ hashes: {}
};
@@ -156,6 +160,11 @@ ctx.calendars[channel] = {
var secret = Hash.getSecrets('calendar', parsed.hash);
var crypto = Crypto.createEncryptor(secret.keys);
+ c.hashes.viewHash = Hash.getViewHashFromKeys(secret);
+ if (data.href) {
+ c.hashes.editHash = Hash.getEditHashFromKeys(secret);
+ }
+
c.proxy = {
metadata: {
color: data.color,
@@ -290,6 +299,14 @@ ctx.calendars[channel] = {
// Personal drive
findFromStore(ctx.store);
+
+ var teams = ctx.store.modules.team && ctx.store.modules.team.getTeamsData();
+ if (!teams) { return; }
+ Object.keys(teams).forEach(function (id) {
+ var store = getStore(ctx, id);
+ console.log(store);
+ findFromStore(store);
+ });
};
@@ -308,6 +325,44 @@ ctx.calendars[channel] = {
});
};
+ var addCalendar = function (ctx, data, cId, cb) {
+ var store = getStore(ctx, data.teamId);
+ if (!store) { return void cb({error: "NO_STORE"}); }
+ // Check team edit rights: viewers in teams don't have rpc
+ if (!store.rpc) { return void cb({error: "EFORBIDDEN"}); }
+
+ var c = store.proxy.calendars = store.proxy.calendars || {};
+ var parsed = Hash.parsePadUrl(data.href);
+ var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
+
+ var cal = {
+ href: Hash.getEditHashFromKeys(secret),
+ roHref: Hash.getViewHashFromKeys(secret),
+ color: data.color,
+ title: data.title,
+ channel: data.channel
+ };
+ cal.color = data.color;
+ cal.title = data.title;
+ openChannel(ctx, {
+ storeId: store.id || 1,
+ data: cal,
+ isNew: true
+ }, function (err) {
+ if (err) {
+ // Can't open this channel, don't store it
+ console.error(err);
+ return void cb({error: err.error})
+ }
+ // Add the calendar and call back
+ c[cal.channel] = cal;
+ var pin = store.pin || ctx.pinPads;
+ pin([cal.channel], function (res) {
+ if (res && res.error) { console.error(res.error); }
+ });
+ ctx.Store.onSync(store.id, cb);
+ });
+ };
var createCalendar = function (ctx, data, cId, cb) {
var store = getStore(ctx, data.teamId);
if (!store) { return void cb({error: "NO_STORE"}); }
@@ -322,7 +377,7 @@ ctx.calendars[channel] = {
storeId: store.id || 1,
data: cal,
isNew: true
- }, function (err, proxy) {
+ }, function (err) {
if (err) {
// Can't open this channel, don't store it
console.error(err);
@@ -460,6 +515,10 @@ ctx.calendars[channel] = {
if (cmd === 'SUBSCRIBE') {
return void subscribe(ctx, data, clientId, cb);
}
+ if (cmd === 'ADD') {
+ if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); }
+ return void addCalendar(ctx, data, clientId, cb);
+ }
if (cmd === 'CREATE') {
if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); }
return void createCalendar(ctx, data, clientId, cb);