mirror of
https://github.com/wekan/wekan.git
synced 2026-03-13 17:06:13 +01:00
Convert cardDetails, cardCustomFields, cardDate, cardTime, cardDescription, attachments, checklists, labels, minicard, resultCard, and subtasks to use native Meteor Template pattern.
644 lines
18 KiB
JavaScript
644 lines
18 KiB
JavaScript
import { TAPi18n } from '/imports/i18n';
|
|
import { ReactiveCache } from '/imports/reactiveCache';
|
|
import {
|
|
setupDatePicker,
|
|
datePickerRendered,
|
|
datePickerHelpers,
|
|
datePickerEvents,
|
|
} from '/client/lib/datepicker';
|
|
import {
|
|
formatDateTime,
|
|
formatDate,
|
|
formatDateByUserPreference,
|
|
formatTime,
|
|
getISOWeek,
|
|
isValidDate,
|
|
isBefore,
|
|
isAfter,
|
|
isSame,
|
|
add,
|
|
subtract,
|
|
startOf,
|
|
endOf,
|
|
format,
|
|
parseDate,
|
|
now,
|
|
createDate,
|
|
fromNow,
|
|
calendar,
|
|
diff
|
|
} from '/imports/lib/dateUtils';
|
|
|
|
// --- DatePicker popups (edit date forms) ---
|
|
|
|
// editCardReceivedDatePopup
|
|
Template.editCardReceivedDatePopup.onCreated(function () {
|
|
const card = Template.currentData();
|
|
setupDatePicker(this, {
|
|
defaultTime: formatDateTime(now()),
|
|
initialDate: card.getReceived() ? card.getReceived() : undefined,
|
|
});
|
|
});
|
|
|
|
Template.editCardReceivedDatePopup.onRendered(function () {
|
|
datePickerRendered(this);
|
|
});
|
|
|
|
Template.editCardReceivedDatePopup.helpers(datePickerHelpers());
|
|
|
|
Template.editCardReceivedDatePopup.events(datePickerEvents({
|
|
storeDate(date) {
|
|
this.datePicker.card.setReceived(formatDateTime(date));
|
|
},
|
|
deleteDate() {
|
|
this.datePicker.card.unsetReceived();
|
|
},
|
|
}));
|
|
|
|
// editCardStartDatePopup
|
|
Template.editCardStartDatePopup.onCreated(function () {
|
|
const card = Template.currentData();
|
|
setupDatePicker(this, {
|
|
defaultTime: formatDateTime(now()),
|
|
initialDate: card.getStart() ? card.getStart() : undefined,
|
|
});
|
|
});
|
|
|
|
Template.editCardStartDatePopup.onRendered(function () {
|
|
datePickerRendered(this);
|
|
});
|
|
|
|
Template.editCardStartDatePopup.helpers(datePickerHelpers());
|
|
|
|
Template.editCardStartDatePopup.events(datePickerEvents({
|
|
storeDate(date) {
|
|
this.datePicker.card.setStart(formatDateTime(date));
|
|
},
|
|
deleteDate() {
|
|
this.datePicker.card.unsetStart();
|
|
},
|
|
}));
|
|
|
|
// editCardDueDatePopup
|
|
Template.editCardDueDatePopup.onCreated(function () {
|
|
const card = Template.currentData();
|
|
setupDatePicker(this, {
|
|
defaultTime: '1970-01-01 17:00:00',
|
|
initialDate: card.getDue() ? card.getDue() : undefined,
|
|
});
|
|
});
|
|
|
|
Template.editCardDueDatePopup.onRendered(function () {
|
|
datePickerRendered(this);
|
|
});
|
|
|
|
Template.editCardDueDatePopup.helpers(datePickerHelpers());
|
|
|
|
Template.editCardDueDatePopup.events(datePickerEvents({
|
|
storeDate(date) {
|
|
this.datePicker.card.setDue(formatDateTime(date));
|
|
},
|
|
deleteDate() {
|
|
this.datePicker.card.unsetDue();
|
|
},
|
|
}));
|
|
|
|
// editCardEndDatePopup
|
|
Template.editCardEndDatePopup.onCreated(function () {
|
|
const card = Template.currentData();
|
|
setupDatePicker(this, {
|
|
defaultTime: formatDateTime(now()),
|
|
initialDate: card.getEnd() ? card.getEnd() : undefined,
|
|
});
|
|
});
|
|
|
|
Template.editCardEndDatePopup.onRendered(function () {
|
|
datePickerRendered(this);
|
|
});
|
|
|
|
Template.editCardEndDatePopup.helpers(datePickerHelpers());
|
|
|
|
Template.editCardEndDatePopup.events(datePickerEvents({
|
|
storeDate(date) {
|
|
this.datePicker.card.setEnd(formatDateTime(date));
|
|
},
|
|
deleteDate() {
|
|
this.datePicker.card.unsetEnd();
|
|
},
|
|
}));
|
|
|
|
// --- Card date badge display helpers ---
|
|
|
|
// Shared onCreated logic for card date badge templates
|
|
function cardDateOnCreated(tpl) {
|
|
tpl.date = new ReactiveVar();
|
|
tpl.now = new ReactiveVar(now());
|
|
window.setInterval(() => {
|
|
tpl.now.set(now());
|
|
}, 60000);
|
|
}
|
|
|
|
// Shared helpers for card date badge templates
|
|
function cardDateHelpers(extraHelpers) {
|
|
const base = {
|
|
showWeek() {
|
|
return getISOWeek(Template.instance().date.get()).toString();
|
|
},
|
|
showWeekOfYear() {
|
|
const user = ReactiveCache.getCurrentUser();
|
|
if (!user) {
|
|
return false;
|
|
}
|
|
return user.isShowWeekOfYear();
|
|
},
|
|
showDate() {
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
return formatDateByUserPreference(Template.instance().date.get(), dateFormat, true);
|
|
},
|
|
showISODate() {
|
|
return Template.instance().date.get().toISOString();
|
|
},
|
|
};
|
|
return Object.assign(base, extraHelpers);
|
|
}
|
|
|
|
// cardReceivedDate
|
|
Template.cardReceivedDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getReceived()));
|
|
});
|
|
});
|
|
|
|
Template.cardReceivedDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
const tpl = Template.instance();
|
|
let classes = 'received-date ';
|
|
const data = Template.currentData();
|
|
const dueAt = data.getDue();
|
|
const endAt = data.getEnd();
|
|
const startAt = data.getStart();
|
|
const theDate = tpl.date.get();
|
|
|
|
if (
|
|
(startAt && isAfter(theDate, startAt)) ||
|
|
(endAt && isAfter(theDate, endAt)) ||
|
|
(dueAt && isAfter(theDate, dueAt))
|
|
) {
|
|
classes += 'overdue';
|
|
} else {
|
|
classes += 'not-due';
|
|
}
|
|
return classes;
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
const formattedDate = formatDateByUserPreference(tpl.date.get(), dateFormat, true);
|
|
return `${TAPi18n.__('card-received-on')} ${formattedDate}`;
|
|
},
|
|
}));
|
|
|
|
Template.cardReceivedDate.events({
|
|
'click .js-edit-date': Popup.open('editCardReceivedDate'),
|
|
});
|
|
|
|
// cardStartDate
|
|
Template.cardStartDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getStart()));
|
|
});
|
|
});
|
|
|
|
Template.cardStartDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
const tpl = Template.instance();
|
|
let classes = 'start-date ';
|
|
const data = Template.currentData();
|
|
const dueAt = data.getDue();
|
|
const endAt = data.getEnd();
|
|
const theDate = tpl.date.get();
|
|
const nowVal = tpl.now.get();
|
|
|
|
if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt))) {
|
|
classes += 'overdue';
|
|
} else if (isAfter(theDate, nowVal)) {
|
|
classes += 'not-due';
|
|
} else {
|
|
classes += 'current';
|
|
}
|
|
return classes;
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
const formattedDate = formatDateByUserPreference(tpl.date.get(), dateFormat, true);
|
|
return `${TAPi18n.__('card-start-on')} ${formattedDate}`;
|
|
},
|
|
}));
|
|
|
|
Template.cardStartDate.events({
|
|
'click .js-edit-date': Popup.open('editCardStartDate'),
|
|
});
|
|
|
|
// cardDueDate
|
|
Template.cardDueDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getDue()));
|
|
});
|
|
});
|
|
|
|
Template.cardDueDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
const tpl = Template.instance();
|
|
let classes = 'due-date ';
|
|
const data = Template.currentData();
|
|
const endAt = data.getEnd();
|
|
const theDate = tpl.date.get();
|
|
const nowVal = tpl.now.get();
|
|
|
|
if (endAt && isBefore(endAt, theDate)) {
|
|
classes += 'completed-early';
|
|
} else if (endAt) {
|
|
classes += 'completed';
|
|
} else {
|
|
const daysDiff = diff(theDate, nowVal, 'days');
|
|
|
|
if (daysDiff < 0) {
|
|
classes += 'overdue';
|
|
} else if (daysDiff <= 1) {
|
|
classes += 'due-soon';
|
|
} else {
|
|
classes += 'not-due';
|
|
}
|
|
}
|
|
|
|
return classes;
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
const formattedDate = formatDateByUserPreference(tpl.date.get(), dateFormat, true);
|
|
return `${TAPi18n.__('card-due-on')} ${formattedDate}`;
|
|
},
|
|
}));
|
|
|
|
Template.cardDueDate.events({
|
|
'click .js-edit-date': Popup.open('editCardDueDate'),
|
|
});
|
|
|
|
// cardEndDate
|
|
Template.cardEndDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getEnd()));
|
|
});
|
|
});
|
|
|
|
Template.cardEndDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
const tpl = Template.instance();
|
|
let classes = 'end-date ';
|
|
const data = Template.currentData();
|
|
const dueAt = data.getDue();
|
|
const theDate = tpl.date.get();
|
|
|
|
if (!dueAt) {
|
|
classes += 'completed';
|
|
} else if (isBefore(theDate, dueAt)) {
|
|
classes += 'completed-early';
|
|
} else if (isAfter(theDate, dueAt)) {
|
|
classes += 'completed-late';
|
|
} else {
|
|
classes += 'completed-on-time';
|
|
}
|
|
return classes;
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
return `${TAPi18n.__('card-end-on')} ${format(tpl.date.get(), 'LLLL')}`;
|
|
},
|
|
}));
|
|
|
|
Template.cardEndDate.events({
|
|
'click .js-edit-date': Popup.open('editCardEndDate'),
|
|
});
|
|
|
|
// cardCustomFieldDate
|
|
Template.cardCustomFieldDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().value));
|
|
});
|
|
});
|
|
|
|
Template.cardCustomFieldDate.helpers(cardDateHelpers({
|
|
showDate() {
|
|
const tpl = Template.instance();
|
|
// this will start working once mquandalle:moment
|
|
// is updated to at least moment.js 2.10.5
|
|
// until then, the date is displayed in the "L" format
|
|
return tpl.date.get().calendar(null, {
|
|
sameElse: 'llll',
|
|
});
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
const formattedDate = formatDateByUserPreference(tpl.date.get(), dateFormat, true);
|
|
return `${formattedDate}`;
|
|
},
|
|
classes() {
|
|
return 'customfield-date';
|
|
},
|
|
}));
|
|
|
|
// --- Minicard date templates ---
|
|
|
|
// minicardReceivedDate
|
|
Template.minicardReceivedDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getReceived()));
|
|
});
|
|
});
|
|
|
|
Template.minicardReceivedDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
const tpl = Template.instance();
|
|
let classes = 'received-date ';
|
|
const data = Template.currentData();
|
|
const dueAt = data.getDue();
|
|
const endAt = data.getEnd();
|
|
const startAt = data.getStart();
|
|
const theDate = tpl.date.get();
|
|
|
|
if (
|
|
(startAt && isAfter(theDate, startAt)) ||
|
|
(endAt && isAfter(theDate, endAt)) ||
|
|
(dueAt && isAfter(theDate, dueAt))
|
|
) {
|
|
classes += 'overdue';
|
|
} else {
|
|
classes += 'not-due';
|
|
}
|
|
return classes;
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
const formattedDate = formatDateByUserPreference(tpl.date.get(), dateFormat, true);
|
|
return `${TAPi18n.__('card-received-on')} ${formattedDate}`;
|
|
},
|
|
showDate() {
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
return formatDateByUserPreference(Template.instance().date.get(), dateFormat, true);
|
|
},
|
|
}));
|
|
|
|
Template.minicardReceivedDate.events({
|
|
'click .js-edit-date': Popup.open('editCardReceivedDate'),
|
|
});
|
|
|
|
// minicardStartDate
|
|
Template.minicardStartDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getStart()));
|
|
});
|
|
});
|
|
|
|
Template.minicardStartDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
const tpl = Template.instance();
|
|
let classes = 'start-date ';
|
|
const data = Template.currentData();
|
|
const dueAt = data.getDue();
|
|
const endAt = data.getEnd();
|
|
const theDate = tpl.date.get();
|
|
const nowVal = tpl.now.get();
|
|
|
|
if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt))) {
|
|
classes += 'overdue';
|
|
} else if (isAfter(theDate, nowVal)) {
|
|
classes += 'not-due';
|
|
} else {
|
|
classes += 'current';
|
|
}
|
|
return classes;
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
const formattedDate = formatDateByUserPreference(tpl.date.get(), dateFormat, true);
|
|
return `${TAPi18n.__('card-start-on')} ${formattedDate}`;
|
|
},
|
|
showDate() {
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
return formatDateByUserPreference(Template.instance().date.get(), dateFormat, true);
|
|
},
|
|
}));
|
|
|
|
Template.minicardStartDate.events({
|
|
'click .js-edit-date': Popup.open('editCardStartDate'),
|
|
});
|
|
|
|
// minicardDueDate
|
|
Template.minicardDueDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getDue()));
|
|
});
|
|
});
|
|
|
|
Template.minicardDueDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
const tpl = Template.instance();
|
|
let classes = 'due-date ';
|
|
const data = Template.currentData();
|
|
const endAt = data.getEnd();
|
|
const theDate = tpl.date.get();
|
|
const nowVal = tpl.now.get();
|
|
|
|
if (endAt && isBefore(endAt, theDate)) {
|
|
classes += 'completed-early';
|
|
} else if (endAt) {
|
|
classes += 'completed';
|
|
} else {
|
|
const daysDiff = diff(theDate, nowVal, 'days');
|
|
|
|
if (daysDiff < 0) {
|
|
classes += 'overdue';
|
|
} else if (daysDiff <= 1) {
|
|
classes += 'due-soon';
|
|
} else {
|
|
classes += 'not-due';
|
|
}
|
|
}
|
|
|
|
return classes;
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
const formattedDate = formatDateByUserPreference(tpl.date.get(), dateFormat, true);
|
|
return `${TAPi18n.__('card-due-on')} ${formattedDate}`;
|
|
},
|
|
showDate() {
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
return formatDateByUserPreference(Template.instance().date.get(), dateFormat, true);
|
|
},
|
|
}));
|
|
|
|
Template.minicardDueDate.events({
|
|
'click .js-edit-date': Popup.open('editCardDueDate'),
|
|
});
|
|
|
|
// minicardEndDate
|
|
Template.minicardEndDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getEnd()));
|
|
});
|
|
});
|
|
|
|
Template.minicardEndDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
const tpl = Template.instance();
|
|
let classes = 'end-date ';
|
|
const data = Template.currentData();
|
|
const dueAt = data.getDue();
|
|
const theDate = tpl.date.get();
|
|
|
|
if (!dueAt) {
|
|
classes += 'completed';
|
|
} else if (isBefore(theDate, dueAt)) {
|
|
classes += 'completed-early';
|
|
} else if (isAfter(theDate, dueAt)) {
|
|
classes += 'completed-late';
|
|
} else {
|
|
classes += 'completed-on-time';
|
|
}
|
|
return classes;
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
return `${TAPi18n.__('card-end-on')} ${format(tpl.date.get(), 'LLLL')}`;
|
|
},
|
|
showDate() {
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
return formatDateByUserPreference(Template.instance().date.get(), dateFormat, true);
|
|
},
|
|
}));
|
|
|
|
Template.minicardEndDate.events({
|
|
'click .js-edit-date': Popup.open('editCardEndDate'),
|
|
});
|
|
|
|
// minicardCustomFieldDate
|
|
Template.minicardCustomFieldDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().value));
|
|
});
|
|
});
|
|
|
|
Template.minicardCustomFieldDate.helpers(cardDateHelpers({
|
|
showDate() {
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
return formatDateByUserPreference(Template.instance().date.get(), dateFormat, true);
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
const formattedDate = formatDateByUserPreference(tpl.date.get(), dateFormat, true);
|
|
return `${formattedDate}`;
|
|
},
|
|
classes() {
|
|
return 'customfield-date';
|
|
},
|
|
}));
|
|
|
|
// --- Vote and Poker end date badge templates ---
|
|
|
|
// voteEndDate
|
|
Template.voteEndDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getVoteEnd()));
|
|
});
|
|
});
|
|
|
|
Template.voteEndDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
return 'end-date ';
|
|
},
|
|
showDate() {
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
return formatDateByUserPreference(Template.instance().date.get(), dateFormat, true);
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
return `${TAPi18n.__('card-end-on')} ${tpl.date.get().toLocaleString()}`;
|
|
},
|
|
}));
|
|
|
|
Template.voteEndDate.events({
|
|
'click .js-edit-date': Popup.open('editVoteEndDate'),
|
|
});
|
|
|
|
// pokerEndDate
|
|
Template.pokerEndDate.onCreated(function () {
|
|
cardDateOnCreated(this);
|
|
const self = this;
|
|
self.autorun(() => {
|
|
self.date.set(new Date(Template.currentData().getPokerEnd()));
|
|
});
|
|
});
|
|
|
|
Template.pokerEndDate.helpers(cardDateHelpers({
|
|
classes() {
|
|
return 'end-date ';
|
|
},
|
|
showDate() {
|
|
const currentUser = ReactiveCache.getCurrentUser();
|
|
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
|
|
return formatDateByUserPreference(Template.instance().date.get(), dateFormat, true);
|
|
},
|
|
showTitle() {
|
|
const tpl = Template.instance();
|
|
return `${TAPi18n.__('card-end-on')} ${format(tpl.date.get(), 'LLLL')}`;
|
|
},
|
|
}));
|
|
|
|
Template.pokerEndDate.events({
|
|
'click .js-edit-date': Popup.open('editPokerEndDate'),
|
|
});
|