diff --git a/.eslintrc.json b/.eslintrc.json
index 6d0addb49..013b76d80 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -97,7 +97,7 @@
"Avatar": true,
"Avatars": true,
"BlazeComponent": false,
-
+
"CollectionHooks": false,
"ESSearchResults": false,
"FastRender": false,
@@ -105,7 +105,6 @@
"FS": false,
"getSlug": false,
"Migrations": false,
- "moment": false,
"Mousetrap": false,
"Picker": false,
"Presence": true,
diff --git a/.meteor/packages b/.meteor/packages
index e9a6af949..3211eb507 100644
--- a/.meteor/packages
+++ b/.meteor/packages
@@ -78,7 +78,6 @@ peerlibrary:blaze-components
ejson@1.1.3
logging@1.3.3
wekan-fullcalendar
-momentjs:moment@2.29.3
wekan-fontawesome
useraccounts:flow-routing-extra
diff --git a/.meteor/versions b/.meteor/versions
index 9ae1e21f4..8fa670345 100644
--- a/.meteor/versions
+++ b/.meteor/versions
@@ -71,7 +71,6 @@ minimongo@1.9.4
modern-browsers@0.1.10
modules@0.20.0
modules-runtime@0.13.1
-momentjs:moment@2.29.3
mongo@1.16.10
mongo-decimal@0.1.3
mongo-dev-server@1.1.0
@@ -142,7 +141,7 @@ wekan-accounts-lockout@1.1.0
wekan-accounts-oidc@1.0.10
wekan-accounts-sandstorm@0.9.0
wekan-fontawesome@6.4.2
-wekan-fullcalendar@3.10.5
+wekan-fullcalendar@5.11.5
wekan-ldap@0.1.0
wekan-markdown@1.0.9
wekan-oidc@1.1.0
diff --git a/client/components/activities/activities.jade b/client/components/activities/activities.jade
index 140335178..346b4a4fb 100644
--- a/client/components/activities/activities.jade
+++ b/client/components/activities/activities.jade
@@ -189,15 +189,15 @@ template(name="activity")
if(currentData.timeKey)
| {{_ activity.activityType }}
= ' '
- i(title=currentData.timeValue).activity-meta {{ moment currentData.timeValue 'LLL' }}
+ i(title=currentData.timeValue).activity-meta {{ displayDate currentData.timeValue 'LLL' }}
if (currentData.timeOldValue)
= ' '
| {{{_ "previous_as" }}}
= ' '
- i(title=currentData.timeOldValue).activity-meta {{ moment currentData.timeOldValue 'LLL' }}
+ i(title=currentData.timeOldValue).activity-meta {{ displayDate currentData.timeOldValue 'LLL' }}
= ' @'
else if(currentData.timeValue)
| {{_ activity.activityType currentData.timeValue}}
if($neq mode 'none')
- div(title=activity.createdAt).activity-meta {{ moment activity.createdAt }}
+ div(title=activity.createdAt).activity-meta {{ displayDate activity.createdAt }}
diff --git a/client/components/activities/comments.jade b/client/components/activities/comments.jade
index 1860eb4f4..cbf497a67 100644
--- a/client/components/activities/comments.jade
+++ b/client/components/activities/comments.jade
@@ -32,7 +32,7 @@ template(name="comment")
+viewer
= text
+commentReactions(reactions=reactions commentId=_id)
- span(title=createdAt).comment-meta {{ moment createdAt }}
+ span(title=createdAt).comment-meta {{ displayDate createdAt }}
if($eq currentUser._id userId)
+editOrDeleteComment
else if currentUser.isBoardAdmin
diff --git a/client/components/boards/boardArchive.jade b/client/components/boards/boardArchive.jade
index 839f183e1..76f3be0a5 100644
--- a/client/components/boards/boardArchive.jade
+++ b/client/components/boards/boardArchive.jade
@@ -15,7 +15,7 @@ template(name="archivedBoards")
i.fa.fa-undo
| {{_ 'restore-board'}}
= title
- span {{ moment archivedAt 'LLL' }}
+ span {{ displayDate archivedAt 'LLL' }}
else
li.no-items-message {{_ 'no-archived-boards'}}
diff --git a/client/components/boards/boardBody.js b/client/components/boards/boardBody.js
index 1f8919552..499a2167f 100644
--- a/client/components/boards/boardBody.js
+++ b/client/components/boards/boardBody.js
@@ -226,16 +226,22 @@ BlazeComponent.extendComponent({
}
// Observe for new popups/menus and set focus (but exclude swimlane content)
- const popupObserver = new MutationObserver(function(mutations) {
- mutations.forEach(function(mutation) {
- mutation.addedNodes.forEach(function(node) {
- if (node.nodeType === 1 &&
- (node.classList.contains('popup') || node.classList.contains('modal') || node.classList.contains('menu')) &&
- !node.closest('.js-swimlanes') &&
- !node.closest('.swimlane') &&
- !node.closest('.list') &&
- !node.closest('.minicard')) {
- setTimeout(function() { focusFirstInteractive(node); }, 10);
+ const popupObserver = new MutationObserver(function (mutations) {
+ mutations.forEach(function (mutation) {
+ mutation.addedNodes.forEach(function (node) {
+ if (
+ node.nodeType === 1 &&
+ (node.classList.contains('popup') ||
+ node.classList.contains('modal') ||
+ node.classList.contains('menu')) &&
+ !node.closest('.js-swimlanes') &&
+ !node.closest('.swimlane') &&
+ !node.closest('.list') &&
+ !node.closest('.minicard')
+ ) {
+ setTimeout(function () {
+ focusFirstInteractive(node);
+ }, 10);
}
});
});
@@ -898,30 +904,35 @@ BlazeComponent.extendComponent({
document.documentElement.lang = TAPi18n.getLanguage();
this.autorun(function () {
- $('#calendar-view').fullCalendar('refetchEvents');
+ const calendarEl = document.getElementById('calendar-view');
+ if (calendarEl && calendarEl._wekanCalendar) {
+ calendarEl._wekanCalendar.refetchEvents();
+ }
});
},
calendarOptions() {
return {
id: 'calendar-view',
- defaultView: 'month',
+ initialView: 'dayGridMonth',
editable: true,
selectable: true,
- timezone: 'local',
weekNumbers: true,
// Use non-localized AM/PM time format to avoid confusing notations like 上/下/中
// Use full 'am'/'pm' instead of single-letter 'a'/'p' for clarity
- timeFormat: 'h:mma',
- slotLabelFormat: 'h:mma',
- extraSmallTimeFormat: 'h(:mm)a',
- smallTimeFormat: 'h(:mm)a',
- mediumTimeFormat: 'h:mma',
- hourFormat: 'ha',
- noMeridiemTimeFormat: 'h:mm',
- header: {
+ eventTimeFormat: {
+ hour: 'numeric',
+ minute: '2-digit',
+ meridiem: 'short',
+ },
+ slotLabelFormat: {
+ hour: 'numeric',
+ minute: '2-digit',
+ meridiem: 'short',
+ },
+ headerToolbar: {
left: 'title today prev,next',
center:
- 'agendaDay,listDay,timelineDay agendaWeek,listWeek,timelineWeek month,listMonth',
+ 'timeGridDay,listDay timeGridWeek,listWeek dayGridMonth,listMonth',
right: '',
},
buttonText: {
@@ -939,12 +950,12 @@ BlazeComponent.extendComponent({
nowIndicator: true,
businessHours: {
// days of week. an array of zero-based day of week integers (0=Sunday)
- dow: [1, 2, 3, 4, 5], // Monday - Friday
+ daysOfWeek: [1, 2, 3, 4, 5], // Monday - Friday
start: '8:00',
end: '18:00',
},
locale: TAPi18n.getLanguage(),
- events(start, end, timezone, callback) {
+ events(fetchInfo, callback) {
const currentBoard = Utils.getCurrentBoard();
const events = [];
const pushEvent = function (card, title, start, end, extraCls) {
@@ -970,12 +981,12 @@ BlazeComponent.extendComponent({
});
};
currentBoard
- .cardsInInterval(start.toDate(), end.toDate())
+ .cardsInInterval(fetchInfo.start, fetchInfo.end)
.forEach(function (card) {
pushEvent(card);
});
currentBoard
- .cardsDueInBetween(start.toDate(), end.toDate())
+ .cardsDueInBetween(fetchInfo.start, fetchInfo.end)
.forEach(function (card) {
pushEvent(
card,
@@ -989,36 +1000,36 @@ BlazeComponent.extendComponent({
});
callback(events);
},
- eventResize(event, delta, revertFunc) {
+ eventResize(info) {
let isOk = false;
- const card = ReactiveCache.getCard(event.id);
+ const card = ReactiveCache.getCard(info.event.id);
if (card) {
- card.setEnd(event.end.toDate());
+ card.setEnd(info.event.end);
isOk = true;
}
if (!isOk) {
- revertFunc();
+ info.revert();
}
},
- eventDrop(event, delta, revertFunc) {
+ eventDrop(info) {
let isOk = false;
- const card = ReactiveCache.getCard(event.id);
+ const card = ReactiveCache.getCard(info.event.id);
if (card) {
// TODO: add a flag for allDay events
- if (!event.allDay) {
+ if (!info.event.allDay) {
// https://github.com/wekan/wekan/issues/2917#issuecomment-1236753962
- //card.setStart(event.start.toDate());
- //card.setEnd(event.end.toDate());
- card.setDue(event.start.toDate());
+ //card.setStart(info.event.start);
+ //card.setEnd(info.event.end);
+ card.setDue(info.event.start);
isOk = true;
}
}
if (!isOk) {
- revertFunc();
+ info.revert();
}
},
- select: function (startDate) {
+ select: function (selectionInfo) {
const currentBoard = Utils.getCurrentBoard();
const currentUser = ReactiveCache.getCurrentUser();
const modalElement = document.createElement('div');
@@ -1056,7 +1067,7 @@ BlazeComponent.extendComponent({
currentBoard._id,
firstList._id,
myTitle,
- startDate.toDate(),
+ selectionInfo.start,
firstSwimlane._id,
function (error, result) {
if (error) {
diff --git a/client/components/cards/cardDetails.jade b/client/components/cards/cardDetails.jade
index f3be79410..277503b29 100644
--- a/client/components/cards/cardDetails.jade
+++ b/client/components/cards/cardDetails.jade
@@ -1077,7 +1077,7 @@ template(name="cardMorePopup")
option(value="{{_id}}") {{title}}
br
| {{_ 'added'}}
- span.date(title=card.createdAt) {{ moment createdAt 'LLL' }}
+ span.date(title=card.createdAt) {{ displayDate createdAt 'LLL' }}
if currentUser.isBoardAdmin
a.js-delete(title="{{_ 'card-delete-notice'}}") {{_ 'delete'}}
diff --git a/client/components/cards/checklists.jade b/client/components/cards/checklists.jade
index 0cd70f880..c2b60837d 100644
--- a/client/components/cards/checklists.jade
+++ b/client/components/cards/checklists.jade
@@ -92,7 +92,7 @@ template(name="editChecklistItemForm")
.edit-controls.clearfix
button.primary.confirm.js-submit-edit-checklist-item-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form(title="{{_ 'close-edit-checklist-item'}}")
- span(title=createdAt) {{ moment createdAt }}
+ span(title=createdAt) {{ displayDate createdAt }}
if canModifyCard
a.js-delete-checklist-item {{_ "delete"}}...
a.js-convert-checklist-item-to-card
diff --git a/client/components/cards/subtasks.jade b/client/components/cards/subtasks.jade
index 3ea5ec5e3..f8e711c28 100644
--- a/client/components/cards/subtasks.jade
+++ b/client/components/cards/subtasks.jade
@@ -51,7 +51,7 @@ template(name="editSubtaskItemForm")
.edit-controls.clearfix
button.primary.confirm.js-submit-edit-subtask-item-form(type="submit") {{_ 'save'}}
a.js-close-inlined-form
- span(title=createdAt) {{ moment createdAt }}
+ span(title=createdAt) {{ displayDate createdAt }}
if canModifyCard
if currentUser.isBoardAdmin
a.js-delete-subtask-item {{_ "delete"}}...
diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade
index 9434ae1eb..967209374 100644
--- a/client/components/lists/listHeader.jade
+++ b/client/components/lists/listHeader.jade
@@ -16,7 +16,7 @@ template(name="listHeader")
span.cardCount {{cardsCount}}
if isMiniScreen
h2.list-header-name(
- title="{{ moment modifiedAt 'LLL' }}"
+ title="{{ displayDate modifiedAt 'LLL' }}"
class="{{#if currentUser.isBoardMember}}{{#unless currentUser.isCommentOnly}}{{#unless currentUser.isWorker}}js-open-inlined-form is-editable{{/unless}}{{/unless}}{{/if}}")
+viewer
= title
@@ -37,7 +37,7 @@ template(name="listHeader")
i.fa.fa-caret-down
div(class="{{#if collapsed}}list-rotated{{/if}}")
h2.list-header-name(
- title="{{ moment modifiedAt 'LLL' }}"
+ title="{{ displayDate modifiedAt 'LLL' }}"
class="{{#unless collapsed}}{{#if currentUser.isBoardMember}}{{#unless currentUser.isCommentOnly}}{{#unless currentUser.isWorker}}js-open-inlined-form is-editable{{/unless}}{{/unless}}{{/if}}{{/unless}}")
+viewer
= title
@@ -193,7 +193,7 @@ template(name="listMorePopup")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
input.inline-input(type="text" readonly value="{{ rootUrl }}")
| {{_ 'added'}}
- span.date(title=list.createdAt) {{ moment createdAt 'LLL' }}
+ span.date(title=list.createdAt) {{ displayDate createdAt 'LLL' }}
//unless currentUser.isWorker
//
if currentUser.isBoardAdmin
diff --git a/client/components/main/myCards.jade b/client/components/main/myCards.jade
index e2e4ffd73..7d068c43f 100644
--- a/client/components/main/myCards.jade
+++ b/client/components/main/myCards.jade
@@ -96,7 +96,7 @@ template(name="myCards")
| {{labelName board label}}
td
if card.dueAt
- | {{ moment card.dueAt 'LLL' }}
+ | {{ displayDate card.dueAt 'LLL' }}
template(name="myCardsViewChangePopup")
if currentUser
diff --git a/client/components/notifications/notification.js b/client/components/notifications/notification.js
index 77cc9fa4b..27a7ff793 100644
--- a/client/components/notifications/notification.js
+++ b/client/components/notifications/notification.js
@@ -1,4 +1,5 @@
import { ReactiveCache } from '/imports/reactiveCache';
+import { formatDateByUserPreference } from '/imports/lib/dateUtils';
Template.notification.events({
'click .read-status .materialCheckBox'() {
@@ -38,9 +39,15 @@ Template.notification.helpers({
const user = ReactiveCache.getCurrentUser();
if (!user) return '';
- const dateFormat = user.getDateFormat ? user.getDateFormat() : 'L';
- const timeFormat = user.getTimeFormat ? user.getTimeFormat() : 'LT';
+ const dateObj = new Date(activity.createdAt);
+ if (Number.isNaN(dateObj.getTime())) return '';
- return moment(activity.createdAt).format(`${dateFormat} ${timeFormat}`);
+ const dateFormat = user.getDateFormat ? user.getDateFormat() : 'YYYY-MM-DD';
+ const datePart = formatDateByUserPreference(dateObj, dateFormat, false);
+ const timePart = dateObj.toLocaleTimeString([], {
+ hour: 'numeric',
+ minute: '2-digit',
+ });
+ return `${datePart} ${timePart}`.trim();
},
});
diff --git a/client/components/settings/peopleBody.jade b/client/components/settings/peopleBody.jade
index 0234d6074..a44f07c55 100644
--- a/client/components/settings/peopleBody.jade
+++ b/client/components/settings/peopleBody.jade
@@ -190,9 +190,9 @@ template(name="orgRow")
else
td {{ orgData.orgWebsite }}
if orgData.orgIsActive
- td {{ moment orgData.createdAt 'LLL' }}
+ td {{ displayDate orgData.createdAt 'LLL' }}
else
- td {{ moment orgData.createdAt 'LLL' }}
+ td {{ displayDate orgData.createdAt 'LLL' }}
td
if orgData.orgIsActive
| {{_ 'yes'}}
@@ -224,9 +224,9 @@ template(name="teamRow")
else
td {{ teamData.teamWebsite }}
if teamData.teamIsActive
- td {{ moment teamData.createdAt 'LLL' }}
+ td {{ displayDate teamData.createdAt 'LLL' }}
else
- td {{ moment teamData.createdAt 'LLL' }}
+ td {{ displayDate teamData.createdAt 'LLL' }}
td
if teamData.teamIsActive
| {{_ 'yes'}}
@@ -284,9 +284,9 @@ template(name="peopleRow")
span.text-green.js-toggle-lock-status.emoji-icon(data-user-id=userData._id, data-is-locked="false", title="{{_ 'accounts-lockout-user-unlocked'}}")
i.fa.fa-unlock
if userData.loginDisabled
- td {{ moment userData.createdAt 'LLL' }}
+ td {{ displayDate userData.createdAt 'LLL' }}
else
- td {{ moment userData.createdAt 'LLL' }}
+ td {{ displayDate userData.createdAt 'LLL' }}
if userData.loginDisabled
td
input.selectUserChkBox(type="checkbox", disabled="disabled", id="{{userData._id}}")
diff --git a/client/components/settings/settingBody.js b/client/components/settings/settingBody.js
index 29c6976e1..8736e823c 100644
--- a/client/components/settings/settingBody.js
+++ b/client/components/settings/settingBody.js
@@ -18,9 +18,9 @@ import {
cronMigrationEtaSeconds,
cronMigrationElapsedSeconds,
cronMigrationCurrentNumber,
- cronMigrationCurrentName
+ cronMigrationCurrentName,
} from '/imports/cronMigrationClient';
-
+import { format } from '/imports/lib/dateUtils';
BlazeComponent.extendComponent({
onCreated() {
@@ -66,7 +66,6 @@ BlazeComponent.extendComponent({
}
},
-
setError(error) {
this.error.set(error);
},
@@ -82,7 +81,9 @@ BlazeComponent.extendComponent({
return this.accountSetting && this.accountSetting.get();
},
isTableVisibilityModeSetting() {
- return this.tableVisibilityModeSetting && this.tableVisibilityModeSetting.get();
+ return (
+ this.tableVisibilityModeSetting && this.tableVisibilityModeSetting.get()
+ );
},
isAnnouncementSetting() {
return this.announcementSetting && this.announcementSetting.get();
@@ -174,7 +175,7 @@ BlazeComponent.extendComponent({
const steps = cronMigrationSteps.get() || [];
return steps.map((step, idx) => ({
...step,
- index: idx + 1
+ index: idx + 1,
}));
},
@@ -237,7 +238,9 @@ BlazeComponent.extendComponent({
isUpdatingMigrationDropdown() {
const status = this.migrationStatus();
- return status && status.startsWith('Updating Select Migration dropdown menu');
+ return (
+ status && status.startsWith('Updating Select Migration dropdown menu')
+ );
},
migrationErrors() {
@@ -251,7 +254,7 @@ BlazeComponent.extendComponent({
formatDateTime(date) {
if (!date) return '';
- return moment(date).format('YYYY-MM-DD HH:mm:ss');
+ return format(date, 'YYYY-MM-DD HH:mm:ss');
},
formatDurationSeconds(seconds) {
@@ -331,18 +334,22 @@ BlazeComponent.extendComponent({
});
} else {
// Run specific migration
- Meteor.call('cron.startSpecificMigration', selectedIndex - 1, (error, result) => {
- this.setLoading(false);
- if (error) {
- alert(TAPi18n.__('migration-start-failed') + ': ' + error.reason);
- } else if (result && result.skipped) {
- cronIsMigrating.set(false);
- cronMigrationStatus.set(TAPi18n.__('migration-not-needed'));
- alert(TAPi18n.__('migration-not-needed'));
- } else {
- alert(TAPi18n.__('migration-started'));
- }
- });
+ Meteor.call(
+ 'cron.startSpecificMigration',
+ selectedIndex - 1,
+ (error, result) => {
+ this.setLoading(false);
+ if (error) {
+ alert(TAPi18n.__('migration-start-failed') + ': ' + error.reason);
+ } else if (result && result.skipped) {
+ cronIsMigrating.set(false);
+ cronMigrationStatus.set(TAPi18n.__('migration-not-needed'));
+ alert(TAPi18n.__('migration-not-needed'));
+ } else {
+ alert(TAPi18n.__('migration-started'));
+ }
+ },
+ );
}
},
@@ -490,9 +497,7 @@ BlazeComponent.extendComponent({
checkField(selector) {
const value = $(selector).val();
if (!value || value.trim() === '') {
- $(selector)
- .parents('li.smtp-form')
- .addClass('has-error');
+ $(selector).parents('li.smtp-form').addClass('has-error');
throw Error('blank field');
} else {
return value;
@@ -514,7 +519,8 @@ BlazeComponent.extendComponent({
},
toggleForgotPassword() {
this.setLoading(true);
- const forgotPasswordClosed = ReactiveCache.getCurrentSetting().disableForgotPassword;
+ const forgotPasswordClosed =
+ ReactiveCache.getCurrentSetting().disableForgotPassword;
Settings.update(ReactiveCache.getCurrentSetting()._id, {
$set: { disableForgotPassword: !forgotPasswordClosed },
});
@@ -522,7 +528,8 @@ BlazeComponent.extendComponent({
},
toggleRegistration() {
this.setLoading(true);
- const registrationClosed = ReactiveCache.getCurrentSetting().disableRegistration;
+ const registrationClosed =
+ ReactiveCache.getCurrentSetting().disableRegistration;
Settings.update(ReactiveCache.getCurrentSetting()._id, {
$set: { disableRegistration: !registrationClosed },
});
@@ -629,11 +636,11 @@ BlazeComponent.extendComponent({
.join(',')
.split(',');
const boardsToInvite = [];
- $('.js-toggle-board-choose .materialCheckBox.is-checked').each(function() {
+ $('.js-toggle-board-choose .materialCheckBox.is-checked').each(function () {
boardsToInvite.push($(this).data('id'));
});
const validEmails = [];
- emails.forEach(email => {
+ emails.forEach((email) => {
if (email && SimpleSchema.RegEx.Email.test(email.trim())) {
validEmails.push(email.trim());
}
@@ -656,12 +663,8 @@ BlazeComponent.extendComponent({
try {
const host = this.checkField('#mail-server-host');
const port = this.checkField('#mail-server-port');
- const username = $('#mail-server-username')
- .val()
- .trim();
- const password = $('#mail-server-password')
- .val()
- .trim();
+ const username = $('#mail-server-username').val().trim();
+ const password = $('#mail-server-password').val().trim();
const from = this.checkField('#mail-server-from');
const tls = $('#mail-server-tls.is-checked').length > 0;
Settings.update(ReactiveCache.getCurrentSetting()._id, {
@@ -686,21 +689,37 @@ BlazeComponent.extendComponent({
$('li').removeClass('has-error');
const productName = ($('#product-name').val() || '').trim();
- const customLoginLogoImageUrl = ($('#custom-login-logo-image-url').val() || '').trim();
- const customLoginLogoLinkUrl = ($('#custom-login-logo-link-url').val() || '').trim();
+ const customLoginLogoImageUrl = (
+ $('#custom-login-logo-image-url').val() || ''
+ ).trim();
+ const customLoginLogoLinkUrl = (
+ $('#custom-login-logo-link-url').val() || ''
+ ).trim();
const customHelpLinkUrl = ($('#custom-help-link-url').val() || '').trim();
- const textBelowCustomLoginLogo = ($('#text-below-custom-login-logo').val() || '').trim();
- const automaticLinkedUrlSchemes = ($('#automatic-linked-url-schemes').val() || '').trim();
- const customTopLeftCornerLogoImageUrl = ($('#custom-top-left-corner-logo-image-url').val() || '').trim();
- const customTopLeftCornerLogoLinkUrl = ($('#custom-top-left-corner-logo-link-url').val() || '').trim();
- const customTopLeftCornerLogoHeight = ($('#custom-top-left-corner-logo-height').val() || '').trim();
+ const textBelowCustomLoginLogo = (
+ $('#text-below-custom-login-logo').val() || ''
+ ).trim();
+ const automaticLinkedUrlSchemes = (
+ $('#automatic-linked-url-schemes').val() || ''
+ ).trim();
+ const customTopLeftCornerLogoImageUrl = (
+ $('#custom-top-left-corner-logo-image-url').val() || ''
+ ).trim();
+ const customTopLeftCornerLogoLinkUrl = (
+ $('#custom-top-left-corner-logo-link-url').val() || ''
+ ).trim();
+ const customTopLeftCornerLogoHeight = (
+ $('#custom-top-left-corner-logo-height').val() || ''
+ ).trim();
const oidcBtnText = ($('#oidcBtnTextvalue').val() || '').trim();
const mailDomainName = ($('#mailDomainNamevalue').val() || '').trim();
const legalNotice = ($('#legalNoticevalue').val() || '').trim();
const hideLogoChange = $('input[name=hideLogo]:checked').val() === 'true';
- const hideCardCounterListChange = $('input[name=hideCardCounterList]:checked').val() === 'true';
- const hideBoardMemberListChange = $('input[name=hideBoardMemberList]:checked').val() === 'true';
+ const hideCardCounterListChange =
+ $('input[name=hideCardCounterList]:checked').val() === 'true';
+ const hideBoardMemberListChange =
+ $('input[name=hideBoardMemberList]:checked').val() === 'true';
const displayAuthenticationMethod =
$('input[name=displayAuthenticationMethod]:checked').val() === 'true';
const defaultAuthenticationMethod = $('#defaultAuthenticationMethod').val();
@@ -740,7 +759,9 @@ BlazeComponent.extendComponent({
toggleSupportPage() {
this.setLoading(true);
- const supportPageEnabled = !$('.js-toggle-support .materialCheckBox').hasClass('is-checked');
+ const supportPageEnabled = !$(
+ '.js-toggle-support .materialCheckBox',
+ ).hasClass('is-checked');
$('.js-toggle-support .materialCheckBox').toggleClass('is-checked');
$('.support-content').toggleClass('hide');
Settings.update(Settings.findOne()._id, {
@@ -751,7 +772,9 @@ BlazeComponent.extendComponent({
toggleSupportPublic() {
this.setLoading(true);
- const supportPagePublic = !$('.js-toggle-support-public .materialCheckBox').hasClass('is-checked');
+ const supportPagePublic = !$(
+ '.js-toggle-support-public .materialCheckBox',
+ ).hasClass('is-checked');
$('.js-toggle-support-public .materialCheckBox').toggleClass('is-checked');
Settings.update(Settings.findOne()._id, {
$set: { supportPagePublic },
@@ -761,7 +784,9 @@ BlazeComponent.extendComponent({
toggleCustomHead() {
this.setLoading(true);
- const customHeadEnabled = !$('.js-toggle-custom-head .materialCheckBox').hasClass('is-checked');
+ const customHeadEnabled = !$(
+ '.js-toggle-custom-head .materialCheckBox',
+ ).hasClass('is-checked');
$('.js-toggle-custom-head .materialCheckBox').toggleClass('is-checked');
$('.custom-head-settings').toggleClass('hide');
Settings.update(ReactiveCache.getCurrentSetting()._id, {
@@ -772,7 +797,9 @@ BlazeComponent.extendComponent({
toggleCustomManifest() {
this.setLoading(true);
- const customManifestEnabled = !$('.js-toggle-custom-manifest .materialCheckBox').hasClass('is-checked');
+ const customManifestEnabled = !$(
+ '.js-toggle-custom-manifest .materialCheckBox',
+ ).hasClass('is-checked');
$('.js-toggle-custom-manifest .materialCheckBox').toggleClass('is-checked');
$('.custom-manifest-settings').toggleClass('hide');
Settings.update(ReactiveCache.getCurrentSetting()._id, {
@@ -829,7 +856,9 @@ BlazeComponent.extendComponent({
const errorMsg = e.message;
// If error is "unexpected non-whitespace character after JSON data"
- if (errorMsg.includes('unexpected non-whitespace character after JSON data')) {
+ if (
+ errorMsg.includes('unexpected non-whitespace character after JSON data')
+ ) {
try {
// Try to find and extract valid JSON by finding matching braces/brackets
const trimmed = content.trim();
@@ -896,8 +925,12 @@ BlazeComponent.extendComponent({
toggleCustomAssetLinks() {
this.setLoading(true);
- const customAssetLinksEnabled = !$('.js-toggle-custom-assetlinks .materialCheckBox').hasClass('is-checked');
- $('.js-toggle-custom-assetlinks .materialCheckBox').toggleClass('is-checked');
+ const customAssetLinksEnabled = !$(
+ '.js-toggle-custom-assetlinks .materialCheckBox',
+ ).hasClass('is-checked');
+ $('.js-toggle-custom-assetlinks .materialCheckBox').toggleClass(
+ 'is-checked',
+ );
$('.custom-assetlinks-settings').toggleClass('hide');
Settings.update(ReactiveCache.getCurrentSetting()._id, {
$set: { customAssetLinksEnabled },
@@ -978,8 +1011,10 @@ BlazeComponent.extendComponent({
'click button.js-save': this.saveMailServerInfo,
'click button.js-send-smtp-test-email': this.sendSMTPTestEmail,
'click a.js-toggle-hide-logo': this.toggleHideLogo,
- 'click a.js-toggle-hide-card-counter-list': this.toggleHideCardCounterList,
- 'click a.js-toggle-hide-board-member-list': this.toggleHideBoardMemberList,
+ 'click a.js-toggle-hide-card-counter-list':
+ this.toggleHideCardCounterList,
+ 'click a.js-toggle-hide-board-member-list':
+ this.toggleHideBoardMemberList,
'click button.js-save-layout': this.saveLayout,
'click a.js-toggle-support': this.toggleSupportPage,
'click a.js-toggle-support-public': this.toggleSupportPublic,
@@ -988,9 +1023,10 @@ BlazeComponent.extendComponent({
'click a.js-toggle-custom-manifest': this.toggleCustomManifest,
'click button.js-custom-head-save': this.saveCustomHeadSettings,
'click a.js-toggle-custom-assetlinks': this.toggleCustomAssetLinks,
- 'click button.js-custom-assetlinks-save': this.saveCustomAssetLinksSettings,
- 'click a.js-toggle-display-authentication-method': this
- .toggleDisplayAuthenticationMethod,
+ 'click button.js-custom-assetlinks-save':
+ this.saveCustomAssetLinksSettings,
+ 'click a.js-toggle-display-authentication-method':
+ this.toggleDisplayAuthenticationMethod,
},
];
},
@@ -1018,15 +1054,23 @@ BlazeComponent.extendComponent({
// Brute force lockout settings method moved to lockedUsersBody.js
allowEmailChange() {
- return AccountSettings.findOne('accounts-allowEmailChange')?.booleanValue || false;
+ return (
+ AccountSettings.findOne('accounts-allowEmailChange')?.booleanValue ||
+ false
+ );
},
allowUserNameChange() {
- return AccountSettings.findOne('accounts-allowUserNameChange')?.booleanValue || false;
+ return (
+ AccountSettings.findOne('accounts-allowUserNameChange')?.booleanValue ||
+ false
+ );
},
allowUserDelete() {
- return AccountSettings.findOne('accounts-allowUserDelete')?.booleanValue || false;
+ return (
+ AccountSettings.findOne('accounts-allowUserDelete')?.booleanValue || false
+ );
},
// Lockout settings helper methods moved to lockedUsersBody.js
@@ -1054,7 +1098,8 @@ BlazeComponent.extendComponent({
'click button.js-accounts-save': this.saveAccountsChange,
},
{
- 'click button.js-all-boards-hide-activities': this.allBoardsHideActivities,
+ 'click button.js-all-boards-hide-activities':
+ this.allBoardsHideActivities,
},
];
},
@@ -1069,7 +1114,9 @@ BlazeComponent.extendComponent({
});
},
allowPrivateOnly() {
- return TableVisibilityModeSettings.findOne('tableVisibilityMode-allowPrivateOnly').booleanValue;
+ return TableVisibilityModeSettings.findOne(
+ 'tableVisibilityMode-allowPrivateOnly',
+ ).booleanValue;
},
allBoardsHideActivities() {
Meteor.call('setAllBoardsHideActivities', (err, ret) => {
@@ -1091,10 +1138,12 @@ BlazeComponent.extendComponent({
events() {
return [
{
- 'click button.js-tableVisibilityMode-save': this.saveTableVisibilityChange,
+ 'click button.js-tableVisibilityMode-save':
+ this.saveTableVisibilityChange,
},
{
- 'click button.js-all-boards-hide-activities': this.allBoardsHideActivities,
+ 'click button.js-all-boards-hide-activities':
+ this.allBoardsHideActivities,
},
];
},
@@ -1114,9 +1163,7 @@ BlazeComponent.extendComponent({
},
saveMessage() {
- const message = $('#admin-announcement')
- .val()
- .trim();
+ const message = $('#admin-announcement').val().trim();
Announcements.update(Announcements.findOne()._id, {
$set: { body: message },
});
@@ -1162,18 +1209,14 @@ BlazeComponent.extendComponent({
saveAccessibility() {
this.setLoading(true);
- const title = $('#admin-accessibility-title')
- .val()
- .trim();
- const content = $('#admin-accessibility-content')
- .val()
- .trim();
+ const title = $('#admin-accessibility-title').val().trim();
+ const content = $('#admin-accessibility-content').val().trim();
try {
AccessibilitySettings.update(AccessibilitySettings.findOne()._id, {
$set: {
title: title,
- body: content
+ body: content,
},
});
} catch (e) {
@@ -1209,7 +1252,7 @@ BlazeComponent.extendComponent({
},
}).register('accessibilitySettings');
-Template.selectAuthenticationMethod.onCreated(function() {
+Template.selectAuthenticationMethod.onCreated(function () {
this.authenticationMethods = new ReactiveVar([]);
Meteor.call('getAuthenticationsEnabled', (_, result) => {
@@ -1220,8 +1263,8 @@ Template.selectAuthenticationMethod.onCreated(function() {
{ value: 'password' },
// Gets only the authentication methods availables
...Object.entries(result)
- .filter(e => e[1])
- .map(e => ({ value: e[0] })),
+ .filter((e) => e[1])
+ .map((e) => ({ value: e[0] })),
]);
}
});
@@ -1244,4 +1287,3 @@ Template.selectSpinnerName.helpers({
return Template.instance().data.spinnerName === match;
},
});
-
diff --git a/client/components/sidebar/sidebarArchives.jade b/client/components/sidebar/sidebarArchives.jade
index 0cad38dac..287533e09 100644
--- a/client/components/sidebar/sidebarArchives.jade
+++ b/client/components/sidebar/sidebarArchives.jade
@@ -20,7 +20,7 @@ template(name="archivesSidebar")
p.quiet
if this.archivedAt
| {{_ 'archived-at' }}
- | | {{ moment this.archivedAt 'LLL' }}
+ | | {{ displayDate this.archivedAt 'LLL' }}
br
a.js-restore-card {{_ 'restore'}}
if currentUser.isBoardAdmin
@@ -51,7 +51,7 @@ template(name="archivesSidebar")
p.quiet
if this.archivedAt
| {{_ 'archived-at' }}
- | | {{ moment this.archivedAt 'LLL' }}
+ | | {{ displayDate this.archivedAt 'LLL' }}
br
a.js-restore-list {{_ 'restore'}}
if currentUser.isBoardAdmin
@@ -80,7 +80,7 @@ template(name="archivesSidebar")
p.quiet
if this.archivedAt
| {{_ 'archived-at' }}
- | | {{ moment this.archivedAt 'LLL' }}
+ | | {{ displayDate this.archivedAt 'LLL' }}
br
a.js-restore-swimlane {{_ 'restore'}}
if currentUser.isBoardAdmin
diff --git a/client/config/blazeHelpers.js b/client/config/blazeHelpers.js
index beef694fa..6d74b658e 100644
--- a/client/config/blazeHelpers.js
+++ b/client/config/blazeHelpers.js
@@ -7,25 +7,25 @@ import {
} from '/imports/lib/customHeadDefaults';
import { Blaze } from 'meteor/blaze';
import { Session } from 'meteor/session';
-import {
- formatDateTime,
- formatDate,
- formatTime,
- getISOWeek,
- isValidDate,
- isBefore,
- isAfter,
- isSame,
- add,
- subtract,
- startOf,
- endOf,
- format,
- parseDate,
- now,
- createDate,
- fromNow,
- calendar
+import {
+ formatDateTime,
+ formatDate,
+ formatTime,
+ getISOWeek,
+ isValidDate,
+ isBefore,
+ isAfter,
+ isSame,
+ add,
+ subtract,
+ startOf,
+ endOf,
+ format,
+ parseDate,
+ now,
+ createDate,
+ fromNow,
+ calendar,
} from '/imports/lib/dateUtils';
Blaze.registerHelper('currentBoard', () => {
@@ -85,7 +85,7 @@ Blaze.registerHelper('currentUser', () => {
return ret;
});
-Blaze.registerHelper('getUser', userId => ReactiveCache.getUser(userId));
+Blaze.registerHelper('getUser', (userId) => ReactiveCache.getUser(userId));
Blaze.registerHelper('concat', (...args) => args.slice(0, -1).join(''));
@@ -101,23 +101,17 @@ Blaze.registerHelper('isTouchScreenOrShowDesktopDragHandles', () =>
Utils.isTouchScreenOrShowDesktopDragHandles(),
);
-Blaze.registerHelper('moment', (...args) => {
+Blaze.registerHelper('displayDate', (...args) => {
args.pop(); // hash
const [date, formatStr] = args;
return format(new Date(date), formatStr ?? 'LLLL');
});
-Blaze.registerHelper('canModifyCard', () =>
- Utils.canModifyCard(),
-);
+Blaze.registerHelper('canModifyCard', () => Utils.canModifyCard());
-Blaze.registerHelper('canMoveCard', () =>
- Utils.canMoveCard(),
-);
+Blaze.registerHelper('canMoveCard', () => Utils.canMoveCard());
-Blaze.registerHelper('canModifyBoard', () =>
- Utils.canModifyBoard(),
-);
+Blaze.registerHelper('canModifyBoard', () => Utils.canModifyBoard());
Blaze.registerHelper('add', (a, b) => a + b);
diff --git a/imports/lib/dateUtils.js b/imports/lib/dateUtils.js
index a36ee469d..46df69382 100644
--- a/imports/lib/dateUtils.js
+++ b/imports/lib/dateUtils.js
@@ -43,7 +43,11 @@ export function formatDate(date) {
* @param {boolean} includeTime - Whether to include time (HH:MM)
* @returns {string} Formatted date string
*/
-export function formatDateByUserPreference(date, format = 'YYYY-MM-DD', includeTime = true) {
+export function formatDateByUserPreference(
+ date,
+ format = 'YYYY-MM-DD',
+ includeTime = true,
+) {
const d = new Date(date);
if (isNaN(d.getTime())) return '';
@@ -108,7 +112,7 @@ export function getISOWeek(date) {
const firstThursday = target.valueOf();
target.setMonth(0, 1);
if (target.getDay() !== 4) {
- target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ target.setMonth(0, 1 + ((4 - target.getDay() + 7) % 7));
}
return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
@@ -141,16 +145,31 @@ export function isBefore(date1, date2, unit = 'millisecond') {
case 'year':
return d1.getFullYear() < d2.getFullYear();
case 'month':
- return d1.getFullYear() < d2.getFullYear() ||
- (d1.getFullYear() === d2.getFullYear() && d1.getMonth() < d2.getMonth());
+ return (
+ d1.getFullYear() < d2.getFullYear() ||
+ (d1.getFullYear() === d2.getFullYear() && d1.getMonth() < d2.getMonth())
+ );
case 'day':
- return d1.getFullYear() < d2.getFullYear() ||
- (d1.getFullYear() === d2.getFullYear() && d1.getMonth() < d2.getMonth()) ||
- (d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() < d2.getDate());
+ return (
+ d1.getFullYear() < d2.getFullYear() ||
+ (d1.getFullYear() === d2.getFullYear() &&
+ d1.getMonth() < d2.getMonth()) ||
+ (d1.getFullYear() === d2.getFullYear() &&
+ d1.getMonth() === d2.getMonth() &&
+ d1.getDate() < d2.getDate())
+ );
case 'hour':
- return d1.getTime() < d2.getTime() && Math.floor(d1.getTime() / (1000 * 60 * 60)) < Math.floor(d2.getTime() / (1000 * 60 * 60));
+ return (
+ d1.getTime() < d2.getTime() &&
+ Math.floor(d1.getTime() / (1000 * 60 * 60)) <
+ Math.floor(d2.getTime() / (1000 * 60 * 60))
+ );
case 'minute':
- return d1.getTime() < d2.getTime() && Math.floor(d1.getTime() / (1000 * 60)) < Math.floor(d2.getTime() / (1000 * 60));
+ return (
+ d1.getTime() < d2.getTime() &&
+ Math.floor(d1.getTime() / (1000 * 60)) <
+ Math.floor(d2.getTime() / (1000 * 60))
+ );
default:
return d1.getTime() < d2.getTime();
}
@@ -184,13 +203,25 @@ export function isSame(date1, date2, unit = 'millisecond') {
case 'year':
return d1.getFullYear() === d2.getFullYear();
case 'month':
- return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth();
+ return (
+ d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth()
+ );
case 'day':
- return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate();
+ return (
+ d1.getFullYear() === d2.getFullYear() &&
+ d1.getMonth() === d2.getMonth() &&
+ d1.getDate() === d2.getDate()
+ );
case 'hour':
- return Math.floor(d1.getTime() / (1000 * 60 * 60)) === Math.floor(d2.getTime() / (1000 * 60 * 60));
+ return (
+ Math.floor(d1.getTime() / (1000 * 60 * 60)) ===
+ Math.floor(d2.getTime() / (1000 * 60 * 60))
+ );
case 'minute':
- return Math.floor(d1.getTime() / (1000 * 60)) === Math.floor(d2.getTime() / (1000 * 60));
+ return (
+ Math.floor(d1.getTime() / (1000 * 60)) ===
+ Math.floor(d2.getTime() / (1000 * 60))
+ );
default:
return d1.getTime() === d2.getTime();
}
@@ -350,6 +381,8 @@ export function format(date, format = 'L') {
return `${year}-${month}-${day}`;
case 'YYYY-MM-DD HH:mm':
return `${year}-${month}-${day} ${hours}:${minutes}`;
+ case 'YYYY-MM-DD HH:mm:ss':
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
case 'HH:mm':
return `${hours}:${minutes}`;
default:
@@ -384,7 +417,7 @@ export function parseDate(dateString, formats = [], strict = true) {
'DD/MM/YYYY HH:mm',
'DD/MM/YYYY',
'DD-MM-YYYY HH:mm',
- 'DD-MM-YYYY'
+ 'DD-MM-YYYY',
];
const allFormats = [...formats, ...commonFormats];
@@ -408,12 +441,12 @@ export function parseDate(dateString, formats = [], strict = true) {
function parseWithFormat(dateString, format) {
// Simple format parsing - can be extended as needed
const formatMap = {
- 'YYYY': '\\d{4}',
- 'MM': '\\d{2}',
- 'DD': '\\d{2}',
- 'HH': '\\d{2}',
- 'mm': '\\d{2}',
- 'ss': '\\d{2}'
+ YYYY: '\\d{4}',
+ MM: '\\d{2}',
+ DD: '\\d{2}',
+ HH: '\\d{2}',
+ mm: '\\d{2}',
+ ss: '\\d{2}',
};
let regex = format;
@@ -425,11 +458,21 @@ function parseWithFormat(dateString, format) {
if (!match) return null;
const groups = match.slice(1);
- let year, month, day, hour = 0, minute = 0, second = 0;
+ let year,
+ month,
+ day,
+ hour = 0,
+ minute = 0,
+ second = 0;
let groupIndex = 0;
for (let i = 0; i < format.length; i++) {
- if (format[i] === 'Y' && format[i + 1] === 'Y' && format[i + 2] === 'Y' && format[i + 3] === 'Y') {
+ if (
+ format[i] === 'Y' &&
+ format[i + 1] === 'Y' &&
+ format[i + 2] === 'Y' &&
+ format[i + 3] === 'Y'
+ ) {
year = parseInt(groups[groupIndex++]);
i += 3;
} else if (format[i] === 'M' && format[i + 1] === 'M') {
@@ -501,11 +544,15 @@ export function fromNow(date, now = new Date()) {
const diffYears = Math.floor(diffDays / 365);
if (diffSeconds < 60) return 'a few seconds ago';
- if (diffMinutes < 60) return `${diffMinutes} minute${diffMinutes !== 1 ? 's' : ''} ago`;
- if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;
+ if (diffMinutes < 60)
+ return `${diffMinutes} minute${diffMinutes !== 1 ? 's' : ''} ago`;
+ if (diffHours < 24)
+ return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;
if (diffDays < 7) return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`;
- if (diffWeeks < 4) return `${diffWeeks} week${diffWeeks !== 1 ? 's' : ''} ago`;
- if (diffMonths < 12) return `${diffMonths} month${diffMonths !== 1 ? 's' : ''} ago`;
+ if (diffWeeks < 4)
+ return `${diffWeeks} week${diffWeeks !== 1 ? 's' : ''} ago`;
+ if (diffMonths < 12)
+ return `${diffMonths} month${diffMonths !== 1 ? 's' : ''} ago`;
return `${diffYears} year${diffYears !== 1 ? 's' : ''} ago`;
}
diff --git a/package-lock.json b/package-lock.json
index eda9a5d7b..2eb1fb617 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -176,12 +176,12 @@
"integrity": "sha512-DAz2ZDtUn7dd0Zol1wdKkhSG4U+OwlDcGzeu1t8XwWh9SKtfTaIaMYTqTvJfAg2B3ilIHp2k64c5mqOiRq5lWQ=="
},
"@wekanteam/exceljs": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@wekanteam/exceljs/-/exceljs-4.6.0.tgz",
- "integrity": "sha512-R5var++3oPGTbfPrswOuQQEP8XsookaErND1vHkVkpnCuirCAcmEiLLdcakAJHFQVwxDANpN4lYzS1qSXSXCPg==",
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/@wekanteam/exceljs/-/exceljs-4.5.1.tgz",
+ "integrity": "sha512-qEWJKSjExu7YJ07YSp3BVj8UvVz1hQR7yh18XdxOn7Wu41wXjbcFpXuMr8GNtj11mE33z5xdUyADcrKLJVfVLQ==",
"requires": {
"archiver": "^5.0.0",
- "dayjs": "^1.8.34",
+ "dayjs": "^1.11.19",
"fast-csv": "^4.3.1",
"jszip": "^3.10.1",
"readable-stream": "^3.6.0",
@@ -2235,9 +2235,9 @@
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
},
"minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz",
+ "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==",
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -2489,9 +2489,9 @@
}
},
"minimatch": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "version": "5.1.7",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.7.tgz",
+ "integrity": "sha512-FjiwU9HaHW6YB3H4a1sFudnv93lvydNjz2lmyUXR6IwKhGI+bgL3SOZrBGn6kvvX2pJvhEkGSGjyTHN47O4rqA==",
"requires": {
"brace-expansion": "^2.0.1"
}
diff --git a/packages/wekan-fullcalendar/package.js b/packages/wekan-fullcalendar/package.js
index 38e8d64fc..d0f922f2c 100644
--- a/packages/wekan-fullcalendar/package.js
+++ b/packages/wekan-fullcalendar/package.js
@@ -1,21 +1,30 @@
Package.describe({
- name: 'wekan-fullcalendar',
- summary: "Full-sized drag & drop event calendar (jQuery plugin)",
- version: "3.10.5",
- git: "https://github.com/fullcalendar/fullcalendar.git"
+ name: 'wekan-fullcalendar',
+ summary: 'Full-sized drag & drop event calendar (jQuery plugin)',
+ version: '5.11.5',
+ git: 'https://github.com/fullcalendar/fullcalendar.git',
+});
+
+Npm.depends({
+ '@fullcalendar/core': '5.11.5',
+ '@fullcalendar/daygrid': '5.11.5',
+ '@fullcalendar/interaction': '5.11.5',
+ '@fullcalendar/list': '5.11.5',
+ '@fullcalendar/timegrid': '5.11.5',
});
Package.onUse(function(api) {
- api.use([
- 'momentjs:moment',
- 'templating'
- ], 'client');
- api.addFiles([
- 'template.html',
- 'template.js',
- 'fullcalendar/fullcalendar.js',
- 'fullcalendar/fullcalendar.css',
- 'fullcalendar/locale-all.js',
- 'fullcalendar/gcal.js',
- ], 'client');
+ api.versionsFrom(['2.16', '3.0']);
+ api.use(['ecmascript', 'templating', 'tracker'], 'client');
+ api.addFiles(
+ [
+ '.npm/package/node_modules/@fullcalendar/common/main.min.css',
+ '.npm/package/node_modules/@fullcalendar/daygrid/main.min.css',
+ '.npm/package/node_modules/@fullcalendar/timegrid/main.min.css',
+ '.npm/package/node_modules/@fullcalendar/list/main.min.css',
+ 'template.html',
+ 'template.js',
+ ],
+ 'client',
+ );
});
diff --git a/packages/wekan-fullcalendar/template.js b/packages/wekan-fullcalendar/template.js
index a41d21d3d..069aa748c 100644
--- a/packages/wekan-fullcalendar/template.js
+++ b/packages/wekan-fullcalendar/template.js
@@ -1,11 +1,86 @@
-window.moment = moment;
+import { Template } from 'meteor/templating';
+import { Tracker } from 'meteor/tracker';
-Template.fullcalendar.rendered = function() {
- var div = this.$(this.firstNode);
- if(this.data != null) {
- //jquery takes care of undefined values, no need to check here
- div.attr('id', this.data.id);
- div.addClass(this.data.class);
+const FullCalendarCore = require('@fullcalendar/core/main.cjs.js');
+const FullCalendarDayGrid = require('@fullcalendar/daygrid/main.cjs.js');
+const FullCalendarInteraction = require('@fullcalendar/interaction/main.cjs.js');
+const FullCalendarList = require('@fullcalendar/list/main.cjs.js');
+const FullCalendarTimeGrid = require('@fullcalendar/timegrid/main.cjs.js');
+const FullCalendarLocalesAll = require('@fullcalendar/core/locales-all.js');
+
+Template.fullcalendar.onRendered(function () {
+ const container = this.find('div');
+
+ this.autorunHandle = Tracker.autorun(() => {
+ const data = Template.currentData() || {};
+ let preservedViewType = null;
+ let preservedDate = null;
+
+ if (!container) {
+ return;
}
- div.fullCalendar(this.data);
-};
+
+ container.id = data.id || '';
+ container.className = data.class || '';
+
+ const options = { ...data };
+ delete options.id;
+ delete options.class;
+ if (options.defaultView && !options.initialView) {
+ options.initialView = options.defaultView;
+ }
+ delete options.defaultView;
+ if (options.header && !options.headerToolbar) {
+ options.headerToolbar = options.header;
+ }
+ delete options.header;
+
+ if (!options.locales && FullCalendarLocalesAll && FullCalendarLocalesAll.default) {
+ options.locales = FullCalendarLocalesAll.default;
+ }
+
+ if (this.calendar) {
+ // Keep the user's current view/date when reactive data updates.
+ if (this.calendar.view && this.calendar.view.type) {
+ preservedViewType = this.calendar.view.type;
+ }
+ if (this.calendar.getDate) {
+ preservedDate = this.calendar.getDate();
+ }
+ this.calendar.destroy();
+ this.calendar = null;
+ }
+
+ if (preservedViewType && !options.initialView) {
+ options.initialView = preservedViewType;
+ }
+ if (preservedDate && !options.initialDate) {
+ options.initialDate = preservedDate;
+ }
+
+ this.calendar = new FullCalendarCore.Calendar(container, {
+ plugins: [
+ FullCalendarDayGrid.default,
+ FullCalendarInteraction.default,
+ FullCalendarList.default,
+ FullCalendarTimeGrid.default,
+ ],
+ ...options,
+ });
+
+ // Allow callers to manually access and refetch without jQuery plugin API.
+ container._wekanCalendar = this.calendar;
+ this.calendar.render();
+ });
+});
+
+Template.fullcalendar.onDestroyed(function () {
+ if (this.autorunHandle) {
+ this.autorunHandle.stop();
+ this.autorunHandle = null;
+ }
+ if (this.calendar) {
+ this.calendar.destroy();
+ this.calendar = null;
+ }
+});