From 19ad5d90e84c39c7e0510da5494a48117d9824c0 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 6 Apr 2021 14:03:51 +0200 Subject: [PATCH] Offline calendars --- www/calendar/inner.js | 51 +++++++++++++++++++++++++++----- www/calendar/main.js | 3 +- www/common/outer/async-store.js | 3 +- www/common/outer/calendar.js | 24 +++++++++++---- www/common/outer/sharedfolder.js | 2 +- 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/www/calendar/inner.js b/www/calendar/inner.js index 698e60035..16d6c95dd 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -56,7 +56,7 @@ Messages.calendar_today = "Today"; Messages.calendar_deleteConfirm = "Are you sure you want to delete this calendar from your account?"; 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 calendar selected!"; +Messages.calendar_errorNoCalendar = "No editable calendar selected!"; var onCalendarsUpdate = Util.mkEvent(); @@ -125,7 +125,7 @@ Messages.calendar_errorNoCalendar = "No calendar selected!"; var getCalendars = function () { return Object.keys(APP.calendars).map(function (id) { var c = APP.calendars[id]; - if (c.hidden) { return; } + if (c.hidden || c.restricted) { return; } var md = Util.find(c, ['content', 'metadata']); if (!md) { return void console.error('Ignore calendar without metadata'); } return { @@ -142,12 +142,15 @@ Messages.calendar_errorNoCalendar = "No calendar selected!"; var s = []; Object.keys(APP.calendars).forEach(function (id) { var c = APP.calendars[id]; - if (c.hidden) { return; } + if (c.hidden || c.restricted) { return; } var data = c.content || {}; Object.keys(data.content || {}).forEach(function (uid) { var obj = data.content[uid]; obj.title = Util.fixHTML(obj.title || ""); obj.location = Util.fixHTML(obj.location || ""); + if (c.readOnly) { + obj.isReadOnly = true; + } s.push(data.content[uid]); }); }); @@ -347,6 +350,7 @@ Messages.calendar_errorNoCalendar = "No calendar selected!"; return UIElements.createDropdown(dropdownConfig)[0]; }; var makeCalendarEntry = function (id, teamId) { + // XXX handle RESTRICTED calendars (data.restricted) var data = APP.calendars[id]; var edit; if (!data.readOnly) { @@ -523,6 +527,15 @@ Messages.calendar_errorNoCalendar = "No calendar selected!"; }); }); + cal.on('clickSchedule', function (event) { + var id = event.calendar && event.calendar.id; + if (!id || !APP.calendars[id]) { + APP.lastClicked = false; + return; + } + APP.lastClicked = id; + }); + renderCalendar(); }; @@ -593,7 +606,20 @@ Messages.calendar_errorNoCalendar = "No calendar selected!"; $el.find('input').attr('autocomplete', 'off'); $el.find('.tui-full-calendar-dropdown-button').addClass('btn btn-secondary'); $el.find('.tui-full-calendar-popup-close').addClass('btn btn-cancel fa fa-times cp-calendar-close').empty(); - if ($el.find('.tui-full-calendar-hide.tui-full-calendar-dropdown').length) { + + var calendars = APP.calendars || {}; + var show = false; + $el.find('.tui-full-calendar-dropdown-menu li').each(function (i, li) { + var $li = $(li); + var id = $li.attr('data-calendar-id'); + var c = calendars[id]; + if (!c || c.readOnly) { + return void $li.remove(); + } + // If at least one calendar is editable, show the popup + show = true; + }); + if ($el.find('.tui-full-calendar-hide.tui-full-calendar-dropdown').length || !show) { $el.hide(); UI.warn(Messages.calendar_errorNoCalendar); return; @@ -604,14 +630,24 @@ Messages.calendar_errorNoCalendar = "No calendar selected!"; $el.find('.tui-full-calendar-dropdown-menu').addClass('cp-forcehide'); } }; + var onCalendarEditPopup = function (el) { + // TODO + }; var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { var node; for (var i = 0; i < mutation.addedNodes.length; i++) { var node = mutation.addedNodes[i]; - if (node.classList && node.classList.contains('tui-full-calendar-popup')) { - onCalendarPopup(node); - } + try { + if (node.classList && node.classList.contains('tui-full-calendar-popup') + && node.parentNode.classList.contains('tui-view-26')) { + onCalendarPopup(node); + } + if (node.classList && node.classList.contains('tui-full-calendar-popup') + && node.parentNode.classList.contains('tui-view-29')) { + onCalendarEditPopup(node); + } + } catch (e) {} } }); }); @@ -637,7 +673,6 @@ Messages.calendar_errorNoCalendar = "No calendar selected!"; }); return; } - console.error('subscribed'); // XXX build UI makeCalendar(); UI.removeLoadingScreen(); diff --git a/www/calendar/main.js b/www/calendar/main.js index 476152b1e..bf1d9712d 100644 --- a/www/calendar/main.js +++ b/www/calendar/main.js @@ -26,7 +26,8 @@ define([ //addRpc: addRpc, //addData: addData, //owned: true, - noRealtime: true + noRealtime: true, + cache: true, }); }); }); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 2a494e112..5b381c8ec 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1494,7 +1494,7 @@ define([ } }; // Teams support offline/cache mode - if (obj.type === "team") { return void todo(); } + if (['team', 'calendar'].indexOf(obj.type) !== -1) { return void todo(); } // If we're in "noDrive" mode if (!store.proxy) { return void todo(); } // Other modules should wait for the ready event @@ -2652,6 +2652,7 @@ define([ }, true); }).nThen(function (waitFor) { loadUniversal(Team, 'team', waitFor, clientId); + loadUniversal(Calendar, 'calendar', waitFor); }).nThen(function () { cb(); }); diff --git a/www/common/outer/calendar.js b/www/common/outer/calendar.js index 9c36aa1c7..db4c0b654 100644 --- a/www/common/outer/calendar.js +++ b/www/common/outer/calendar.js @@ -3,12 +3,13 @@ define([ '/common/common-hash.js', '/common/common-constants.js', '/common/common-realtime.js', + '/common/outer/cache-store.js', '/customize/messages.js', '/bower_components/nthen/index.js', '/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad/chainpad.dist.js', -], function (Util, Hash, Constants, Realtime, Messages, nThen, Listmap, Crypto, ChainPad) { +], function (Util, Hash, Constants, Realtime, Cache, Messages, nThen, Listmap, Crypto, ChainPad) { var Calendar = {}; @@ -103,8 +104,9 @@ ctx.calendars[channel] = { ctx.emit('UPDATE', { teams: c.stores, id: c.channel, - readOnly: c.readOnly, + readOnly: c.readOnly || (!c.ready && c.cacheready), deleted: !c.stores.length, + restricted: c.restricted, owned: false, // XXX XXX destroy content: Util.clone(c.proxy) }, ctx.clients); @@ -178,14 +180,16 @@ ctx.calendars[channel] = { var config = { data: {}, - network: ctx.store.network, // XXX offline + network: ctx.store.network || ctx.store.networkPromise, // XXX offline channel: secret.channel, crypto: crypto, owners: [edPublic], ChainPad: ChainPad, validateKey: secret.keys.validateKey || undefined, userName: 'calendar', - classic: true + Cache: Cache, + classic: true, + onRejected: ctx.Store && ctx.Store.onRejected }; console.error(channel, config); @@ -213,7 +217,12 @@ ctx.calendars[channel] = { }); }; - lm.proxy.on('ready', function () { + lm.proxy.on('cacheready', function () { + if (!proxy.metadata) { return; } + c.cacheready = true; + setTimeout(update); + if (cb) { cb(null, lm.proxy); } + }).on('ready', function () { c.ready = true; if (!proxy.metadata) { if (!cfg.isNew) { @@ -240,6 +249,9 @@ ctx.calendars[channel] = { if (info.error === "EDELETED" ) { return void onDeleted(); } + if (info.error === "ERESTRICTED" ) { + c.restricted = true; + } cb(info); }); }); @@ -274,7 +286,7 @@ ctx.calendars[channel] = { Object.keys(ctx.calendars).forEach(function (channel) { var c = ctx.calendars[channel] || {}; console.log(channel, c); - if (!c.ready) { return; } + if (!c.ready && !c.cacheready) { return; } sendUpdate(ctx, c); }); }; diff --git a/www/common/outer/sharedfolder.js b/www/common/outer/sharedfolder.js index 188fb2e40..3bc39546c 100644 --- a/www/common/outer/sharedfolder.js +++ b/www/common/outer/sharedfolder.js @@ -186,7 +186,7 @@ define([ ChainPad: ChainPad, classic: true, network: network, - Cache: Cache, // ICE shared-folder cache + Cache: Cache, // shared-folder cache metadata: { validateKey: secret.keys.validateKey || undefined, owners: owners