Basic calendar app
parent
d853466ad2
commit
bbd35d0307
@ -0,0 +1,66 @@
|
||||
@import (reference) '../../customize/src/less2/include/framework.less';
|
||||
|
||||
&.cp-app-calendar {
|
||||
|
||||
.framework_min_main();
|
||||
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
#cp-calendar {
|
||||
.tui-full-calendar-layout {
|
||||
background-color: @cp_sidebar-right-bg !important;
|
||||
color: @cryptpad_text_col;
|
||||
}
|
||||
.tui-full-calendar-timegrid-gridline, .tui-full-calendar-time-date {
|
||||
border-color: @cp_calendar-border !important;
|
||||
}
|
||||
.tui-full-calendar-splitter, .tui-full-calendar-left, .tui-full-calendar-dayname-container, .tui-full-calendar-weekday-grid-line {
|
||||
border-color: @cp_calendar-border !important;
|
||||
|
||||
}
|
||||
.tui-full-calendar-popup-container {
|
||||
background: @cp_flatpickr-bg;
|
||||
color: @cryptpad_text_col;
|
||||
}
|
||||
.tui-full-calendar-popup-section-item {
|
||||
height: auto;
|
||||
&:not(button) {
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding-left: 0;
|
||||
input { flex: 1; }
|
||||
}
|
||||
}
|
||||
.tui-full-calendar-popup-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.tui-full-calendar-section-date-dash {
|
||||
height: auto;
|
||||
}
|
||||
.tui-full-calendar-section-title, .tui-full-calendar-section-location {
|
||||
width: 100%;
|
||||
}
|
||||
.tui-full-calendar-dropdown-menu {
|
||||
top: 38px;
|
||||
background-color: @cp_dropdown-bg;
|
||||
color: @cp_dropdown-fg;
|
||||
}
|
||||
.tui-full-calendar-section-state, #tui-full-calendar-schedule-private {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cp-calendar-close {
|
||||
height: auto;
|
||||
line-height: initial;
|
||||
border: 1px solid;
|
||||
&:not(:hover) {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CryptPad</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<iframe-placeholder>
|
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="cp-app-noscroll">
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<script async data-bootload="/calendar/inner.js" data-main="/common/sframe-boot.js?ver=1.7" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
<style>
|
||||
.loading-hidden { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="cp-app-calendar">
|
||||
<div id="cp-toolbar" class="cp-toolbar-container"></div>
|
||||
<div id="cp-container"></div>
|
||||
<noscript>
|
||||
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
|
||||
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
|
||||
</noscript>
|
||||
</body>
|
||||
|
@ -0,0 +1,231 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/bower_components/chainpad-crypto/crypto.js',
|
||||
'/common/toolbar.js',
|
||||
'/bower_components/nthen/index.js',
|
||||
'/common/sframe-common.js',
|
||||
'/common/common-util.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-interface.js',
|
||||
'/common/common-ui-elements.js',
|
||||
'/common/common-realtime.js',
|
||||
'/common/clipboard.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/hyperscript.js',
|
||||
'/customize/messages.js',
|
||||
'/customize/application_config.js',
|
||||
'/lib/calendar/tui-calendar.min.js',
|
||||
|
||||
'css!/lib/calendar/tui-calendar.min.css',
|
||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
'less!/calendar/app-calendar.less',
|
||||
], function (
|
||||
$,
|
||||
Crypto,
|
||||
Toolbar,
|
||||
nThen,
|
||||
SFCommon,
|
||||
Util,
|
||||
Hash,
|
||||
UI,
|
||||
UIElements,
|
||||
Realtime,
|
||||
Clipboard,
|
||||
MT,
|
||||
h,
|
||||
Messages,
|
||||
AppConfig,
|
||||
Calendar
|
||||
)
|
||||
{
|
||||
var APP = window.APP = {
|
||||
};
|
||||
console.log(Calendar);
|
||||
|
||||
|
||||
var common;
|
||||
var sframeChan;
|
||||
|
||||
Messages.calendar = "Calendar"; // XXX
|
||||
|
||||
var updateCalendar = function (data) {
|
||||
console.log(data);
|
||||
|
||||
};
|
||||
|
||||
var templates = {
|
||||
popupSave: function () {
|
||||
return Messages.settings_save;
|
||||
}
|
||||
};
|
||||
|
||||
var makeCalendar = function (ctx) {
|
||||
var $container = $('#cp-container');
|
||||
$container.append([
|
||||
h('div#menu', [
|
||||
h('span#renderRange.render-range')
|
||||
]),
|
||||
h('div#cp-calendar')
|
||||
]);
|
||||
|
||||
var cal = new Calendar('#cp-calendar', {
|
||||
defaultView: 'week', // weekly view option
|
||||
useCreationPopup: true,
|
||||
useDetailPopup: true,
|
||||
usageStatistics: false,
|
||||
calendars: [{
|
||||
id: '1',
|
||||
name: 'My Calendar',
|
||||
color: '#ffffff',
|
||||
bgColor: '#9e5fff',
|
||||
dragBgColor: '#9e5fff',
|
||||
borderColor: '#9e5fff'
|
||||
}, {
|
||||
id: '2',
|
||||
name: 'Company',
|
||||
color: '#00a9ff',
|
||||
bgColor: '#00a9ff',
|
||||
dragBgColor: '#00a9ff',
|
||||
borderColor: '#00a9ff'
|
||||
}]
|
||||
});
|
||||
cal.on('beforeCreateSchedule', function(event) {
|
||||
var startTime = event.start;
|
||||
var endTime = event.end;
|
||||
var isAllDay = event.isAllDay;
|
||||
var guide = event.guide;
|
||||
var triggerEventName = event.triggerEventName;
|
||||
|
||||
// XXX Recurrence (later)
|
||||
// On creation, select a recurrence rule (daily / weekly / monthly / more weird rules)
|
||||
// then mark it under recurrence rule with a uid (the same for all the recurring events)
|
||||
// ie: recurrenceRule: DAILY|{uid}
|
||||
// Use template to hide "recurrenceRule" from the detailPopup or at least to use
|
||||
// a non technical value
|
||||
|
||||
var schedule = {
|
||||
id: Util.uid(),
|
||||
calendarId: event.calendarId,
|
||||
title: Util.fixHTML(event.title),
|
||||
category: "time",
|
||||
location: Util.fixHTML(event.location),
|
||||
start: event.start,
|
||||
end: event.end,
|
||||
};
|
||||
|
||||
/*
|
||||
if (triggerEventName === 'click') {
|
||||
// open writing simple schedule popup
|
||||
schedule = {
|
||||
};
|
||||
} else if (triggerEventName === 'dblclick') {
|
||||
// open writing detail schedule popup
|
||||
schedule = {
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
cal.createSchedules([schedule]);
|
||||
});
|
||||
};
|
||||
|
||||
var createToolbar = function () {
|
||||
var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle', 'notifications'];
|
||||
var configTb = {
|
||||
displayed: displayed,
|
||||
sfCommon: common,
|
||||
$container: APP.$toolbar,
|
||||
pageTitle: Messages.calendar,
|
||||
metadataMgr: common.getMetadataMgr(),
|
||||
};
|
||||
APP.toolbar = Toolbar.create(configTb);
|
||||
APP.toolbar.$rightside.hide();
|
||||
};
|
||||
|
||||
var onEvent = function (obj) {
|
||||
var ev = obj.ev;
|
||||
var data = obj.data;
|
||||
if (ev === 'UPDATE') {
|
||||
console.log('Update');
|
||||
updateCalendar(data);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
nThen(function (waitFor) {
|
||||
$(waitFor(UI.addLoadingScreen));
|
||||
SFCommon.create(waitFor(function (c) { APP.common = common = c; }));
|
||||
}).nThen(function (waitFor) {
|
||||
APP.$toolbar = $('#cp-toolbar');
|
||||
sframeChan = common.getSframeChannel();
|
||||
sframeChan.onReady(waitFor());
|
||||
}).nThen(function (/*waitFor*/) {
|
||||
createToolbar();
|
||||
|
||||
// Fix flatpickr selection
|
||||
var MutationObserver = window.MutationObserver;
|
||||
var onFlatPickr = function (el) {
|
||||
// Don't close event creation popup when clicking on flatpickr
|
||||
$(el).mousedown(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
};
|
||||
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('flatpickr-calendar')) {
|
||||
onFlatPickr(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe($('body')[0], {
|
||||
childList: true,
|
||||
subtree: false
|
||||
});
|
||||
|
||||
// Customize creation/update popup
|
||||
var onCalendarPopup = function (el) {
|
||||
var $el = $(el);
|
||||
$el.find('.tui-full-calendar-confirm').addClass('btn btn-primary');
|
||||
$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();
|
||||
console.log(el);
|
||||
};
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe($('body')[0], {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
APP.module = common.makeUniversal('calendar', {
|
||||
onEvent: onEvent
|
||||
});
|
||||
APP.module.execCommand('SUBSCRIBE', null, function () {
|
||||
console.error('subscribed');
|
||||
// XXX build UI
|
||||
makeCalendar();
|
||||
UI.removeLoadingScreen();
|
||||
});
|
||||
|
||||
var metadataMgr = common.getMetadataMgr();
|
||||
var privateData = metadataMgr.getPrivateData();
|
||||
|
||||
APP.origin = privateData.origin;
|
||||
|
||||
|
||||
});
|
||||
});
|
@ -0,0 +1,32 @@
|
||||
// Load #1, load as little as possible because we are in a race to get the loading screen up.
|
||||
define([
|
||||
'/bower_components/nthen/index.js',
|
||||
'/api/config',
|
||||
'/common/dom-ready.js',
|
||||
'/common/sframe-common-outer.js',
|
||||
], function (nThen, ApiConfig, DomReady, SFCommonO) {
|
||||
|
||||
// Loaded in load #2
|
||||
nThen(function (waitFor) {
|
||||
DomReady.onReady(waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
SFCommonO.initIframe(waitFor);
|
||||
}).nThen(function (/*waitFor*/) {
|
||||
var getSecrets = function (Cryptpad, Utils, cb) {
|
||||
// XXX open calendar from URL
|
||||
};
|
||||
var addData = function (meta, Cryptpad, user) {
|
||||
// XXX flag when opening URL
|
||||
meta.isOwnProfile = !window.location.hash ||
|
||||
window.location.hash.slice(1) === user.profile;
|
||||
};
|
||||
SFCommonO.start({
|
||||
//getSecrets: getSecrets,
|
||||
//noHash: true, // Don't add the hash in the URL if it doesn't already exist
|
||||
//addRpc: addRpc,
|
||||
//addData: addData,
|
||||
//owned: true,
|
||||
noRealtime: true
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,261 @@
|
||||
define([
|
||||
'/common/common-util.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-constants.js',
|
||||
'/common/common-realtime.js',
|
||||
'/customize/messages.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, Listmap, Crypto, ChainPad) {
|
||||
var Calendar = {};
|
||||
|
||||
|
||||
/* TODO
|
||||
* Calendar
|
||||
{
|
||||
href,
|
||||
roHref,
|
||||
channel, (pinning)
|
||||
title, (when created from the UI, own calendar has no title)
|
||||
color
|
||||
}
|
||||
|
||||
|
||||
* Own drive
|
||||
{
|
||||
calendars: {
|
||||
own: calendar,
|
||||
extra: {
|
||||
uid: calendar,
|
||||
uid: calendar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
* Team drive
|
||||
{
|
||||
calendars: {
|
||||
own: calendar,
|
||||
extra: {
|
||||
uid: calendar,
|
||||
uid: calendar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
* Calendars are listmap
|
||||
{
|
||||
content: {},
|
||||
metadata: {
|
||||
title: "pewpewpew"
|
||||
}
|
||||
}
|
||||
|
||||
ctx.calendars[channel] = {
|
||||
lm: lm,
|
||||
proxy: lm.proxy?
|
||||
stores: [teamId, teamId, 1]
|
||||
}
|
||||
|
||||
* calendar app can subscribe to this module
|
||||
* when a listmap changes, push an update for this calendar to subscribed tabs
|
||||
* Ability to open a calendar not stored in the stores but from its URL directly
|
||||
* No "userlist" visible in the UI
|
||||
* No framework
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
var makeCalendar = function () {
|
||||
var hash = Hash.createRandomHash('calendar');
|
||||
var secret = Hash.getSecrets('calendar', hash);
|
||||
var roHash = Hash.getViewHashFromKeys(secret);
|
||||
var href = Hash.hashToHref(hash, 'calendar');
|
||||
var roHref = Hash.hashToHref(roHash, 'calendar');
|
||||
return {
|
||||
href: href,
|
||||
roHref: roHref,
|
||||
channel: secret.channel,
|
||||
};
|
||||
};
|
||||
var initializeCalendars = function (ctx, cb) {
|
||||
var proxy = ctx.store.proxy;
|
||||
var calendars = proxy.calendars = proxy.calendars || {};
|
||||
if (!calendars.own) {
|
||||
var own = calendars.own = makeCalendar(true);
|
||||
own.color = ctx.Store.getUserColor();
|
||||
}
|
||||
setTimeout(cb);
|
||||
// XXX for each team, if we have edit rights, create the team calendar?
|
||||
// XXX or maybe do it from the team app?
|
||||
};
|
||||
|
||||
var sendUpdate = function (ctx, c) {
|
||||
ctx.emit('UPDATE', {
|
||||
teams: c.stores,
|
||||
id: c.channel,
|
||||
readOnly: c.readOnly,
|
||||
data: Util.clone(c.proxy)
|
||||
}, ctx.clients);
|
||||
};
|
||||
|
||||
var openChannel = function (ctx, cfg) {
|
||||
var teamId = cfg.storeId;
|
||||
var data = cfg.data;
|
||||
var channel = data.channel;
|
||||
if (!channel) { return; }
|
||||
|
||||
var c = ctx.calendars[channel];
|
||||
if (c) {
|
||||
if (c.stores && c.stores.indexOf(teamId) !== -1) { return; }
|
||||
if (c.readOnly && data.href) {
|
||||
// XXX UPGRADE
|
||||
// XXX different cases if already ready or not?
|
||||
}
|
||||
c.stores.push(teamId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Multiple teams can have the same calendar. Make sure we remember the list of stores
|
||||
// that know it so that we don't close the calendar when leaving/deleting a team.
|
||||
c = ctx.calendars[channel] = {
|
||||
ready: false,
|
||||
channel: channel,
|
||||
readOnly: !data.href,
|
||||
stores: [teamId]
|
||||
};
|
||||
|
||||
var update = function () {
|
||||
console.log(ctx.clients);
|
||||
sendUpdate(ctx, c);
|
||||
};
|
||||
|
||||
|
||||
var parsed = Hash.parsePadUrl(data.href || data.roHref);
|
||||
var secret = Hash.getSecrets('calendar', parsed.hash);
|
||||
var crypto = Crypto.createEncryptor(secret.keys);
|
||||
|
||||
// Set the owners as the first store opening it. We don't know yet if it's a new or
|
||||
// existing calendar. "owners' will be ignored if the calendar already exists.
|
||||
var edPublic;
|
||||
if (teamId === 1) {
|
||||
edPublic = ctx.store.proxy.edPublic;
|
||||
} else {
|
||||
var teams = ctx.store.modules.team && ctx.store.modules.team.getTeamsData();
|
||||
var team = teams && teams[teamId];
|
||||
edPublic = team ? team.edPublic : undefined;
|
||||
}
|
||||
|
||||
var config = {
|
||||
data: {},
|
||||
network: ctx.store.network, // XXX offline
|
||||
channel: secret.channel,
|
||||
crypto: crypto,
|
||||
owners: [edPublic],
|
||||
ChainPad: ChainPad,
|
||||
validateKey: secret.keys.validateKey || undefined,
|
||||
userName: 'calendar',
|
||||
classic: true
|
||||
};
|
||||
|
||||
console.error(channel, config);
|
||||
var lm = Listmap.create(config);
|
||||
c.lm = lm;
|
||||
c.proxy = lm.proxy;
|
||||
|
||||
lm.proxy.on('ready', function () {
|
||||
c.ready = true;
|
||||
console.warn('READY', channel);
|
||||
setTimeout(update);
|
||||
}).on('change', [], function () {
|
||||
setTimeout(update);
|
||||
});
|
||||
};
|
||||
var openChannels = function (ctx) {
|
||||
var findFromStore = function (store) {
|
||||
var c = store.proxy.calendars;
|
||||
if (!c) { return; }
|
||||
if (c.own) {
|
||||
openChannel(ctx, {
|
||||
storeId: store.id || 1,
|
||||
data: c.own
|
||||
});
|
||||
}
|
||||
if (c.extra) {
|
||||
Object.keys(c.extra).forEach(function (channel) {
|
||||
openChannel(ctx, {
|
||||
storeId: store.id || 1,
|
||||
data: c.extra[channel]
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Personal drive
|
||||
findFromStore(ctx.store);
|
||||
};
|
||||
|
||||
|
||||
var subscribe = function (ctx, data, cId, cb) {
|
||||
// Subscribe to new notifications
|
||||
var idx = ctx.clients.indexOf(cId);
|
||||
if (idx === -1) {
|
||||
ctx.clients.push(cId);
|
||||
}
|
||||
cb();
|
||||
Object.keys(ctx.calendars).forEach(function (channel) {
|
||||
var c = ctx.calendars[channel] || {};
|
||||
console.log(channel, c);
|
||||
if (!c.ready) { return; }
|
||||
sendUpdate(ctx, c);
|
||||
});
|
||||
};
|
||||
|
||||
var removeClient = function (ctx, cId) {
|
||||
var idx = ctx.clients.indexOf(cId);
|
||||
ctx.clients.splice(idx, 1);
|
||||
};
|
||||
|
||||
Calendar.init = function (cfg, waitFor, emit) {
|
||||
var calendar = {};
|
||||
var store = cfg.store;
|
||||
if (!store.loggedIn || !store.proxy.edPublic) { return; } // XXX logged in only?
|
||||
var ctx = {
|
||||
store: store,
|
||||
Store: cfg.Store,
|
||||
pinPads: cfg.pinPads,
|
||||
updateMetadata: cfg.updateMetadata,
|
||||
emit: emit,
|
||||
onReady: Util.mkEvent(true),
|
||||
calendars: {},
|
||||
clients: [],
|
||||
};
|
||||
|
||||
initializeCalendars(ctx, waitFor(function (err) {
|
||||
if (err) { return; }
|
||||
openChannels(ctx);
|
||||
}));
|
||||
|
||||
calendar.removeClient = function (clientId) {
|
||||
removeClient(ctx, clientId);
|
||||
};
|
||||
calendar.execCommand = function (clientId, obj, cb) {
|
||||
var cmd = obj.cmd;
|
||||
var data = obj.data;
|
||||
if (cmd === 'SUBSCRIBE') {
|
||||
return void subscribe(ctx, data, clientId, cb);
|
||||
}
|
||||
};
|
||||
|
||||
return calendar;
|
||||
};
|
||||
|
||||
return Calendar;
|
||||
});
|
||||
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/lib/datepicker/flatpickr.js',
|
||||
|
||||
'css!/lib/datepicker/flatpickr.min.css',
|
||||
], function ($, Flatpickr) {
|
||||
var createRangePicker = function (cfg) {
|
||||
var start = cfg.startpicker;
|
||||
var end = cfg.endpicker;
|
||||
console.log(cfg);
|
||||
console.error(start, end);
|
||||
|
||||
var e = $(end.input)[0];
|
||||
var endPickr = Flatpickr(e, {
|
||||
enableTime: true,
|
||||
minDate: start.date
|
||||
});
|
||||
endPickr.setDate(end.date);
|
||||
|
||||
var s = $(start.input)[0];
|
||||
var startPickr = Flatpickr(s, {
|
||||
enableTime: true,
|
||||
onChange: function () {
|
||||
endPickr.set('minDate', startPickr.parseDate(s.value));
|
||||
}
|
||||
});
|
||||
startPickr.setDate(start.date);
|
||||
|
||||
var getStartDate = function () {
|
||||
setTimeout(function () { $(startPickr.calendarContainer).remove(); });
|
||||
return startPickr.parseDate(s.value);
|
||||
};
|
||||
var getEndDate = function () {
|
||||
setTimeout(function () { $(endPickr.calendarContainer).remove(); });
|
||||
return endPickr.parseDate(e.value);
|
||||
};
|
||||
|
||||
return {
|
||||
getStartDate: getStartDate,
|
||||
getEndDate: getEndDate,
|
||||
};
|
||||
};
|
||||
return {
|
||||
createRangePicker: createRangePicker
|
||||
};
|
||||
});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue