mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
number + date fields
This commit is contained in:
parent
3753337d60
commit
8b16955cc2
9 changed files with 242 additions and 130 deletions
|
|
@ -31,6 +31,30 @@ template(name="cardCustomField-text")
|
||||||
else
|
else
|
||||||
| {{_ 'edit'}}
|
| {{_ 'edit'}}
|
||||||
|
|
||||||
|
template(name="cardCustomField-number")
|
||||||
|
if canModifyCard
|
||||||
|
+inlinedForm(classNames="js-card-customfield-number")
|
||||||
|
input(type="number" value=data.value)
|
||||||
|
.edit-controls.clearfix
|
||||||
|
button.primary(type="submit") {{_ 'save'}}
|
||||||
|
a.fa.fa-times-thin.js-close-inlined-form
|
||||||
|
else
|
||||||
|
a.js-open-inlined-form
|
||||||
|
if value
|
||||||
|
= value
|
||||||
|
else
|
||||||
|
| {{_ 'edit'}}
|
||||||
|
|
||||||
|
template(name="cardCustomField-date")
|
||||||
|
if canModifyCard
|
||||||
|
a.js-edit-date(title="{{showTitle}}" class="{{classes}}")
|
||||||
|
if value
|
||||||
|
div.card-date
|
||||||
|
time(datetime="{{showISODate}}")
|
||||||
|
| {{showDate}}
|
||||||
|
else
|
||||||
|
| {{_ 'edit'}}
|
||||||
|
|
||||||
template(name="cardCustomField-dropdown")
|
template(name="cardCustomField-dropdown")
|
||||||
if canModifyCard
|
if canModifyCard
|
||||||
+inlinedForm(classNames="js-card-customfield-dropdown")
|
+inlinedForm(classNames="js-card-customfield-dropdown")
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ Template.cardCustomFieldsPopup.events({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// cardCustomField
|
||||||
const CardCustomField = BlazeComponent.extendComponent({
|
const CardCustomField = BlazeComponent.extendComponent({
|
||||||
|
|
||||||
getTemplate() {
|
getTemplate() {
|
||||||
|
|
@ -28,6 +29,8 @@ const CardCustomField = BlazeComponent.extendComponent({
|
||||||
|
|
||||||
onCreated() {
|
onCreated() {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
self.card = Cards.findOne(Session.get('currentCard'));
|
||||||
|
self.customFieldId = this.data()._id;
|
||||||
},
|
},
|
||||||
|
|
||||||
canModifyCard() {
|
canModifyCard() {
|
||||||
|
|
@ -36,28 +39,118 @@ const CardCustomField = BlazeComponent.extendComponent({
|
||||||
});
|
});
|
||||||
CardCustomField.register('cardCustomField');
|
CardCustomField.register('cardCustomField');
|
||||||
|
|
||||||
|
// cardCustomField-text
|
||||||
(class extends CardCustomField {
|
(class extends CardCustomField {
|
||||||
|
|
||||||
onCreated() {
|
onCreated() {
|
||||||
|
super.onCreated();
|
||||||
}
|
}
|
||||||
|
|
||||||
events() {
|
events() {
|
||||||
return [{
|
return [{
|
||||||
'submit .js-card-customfield-text'(evt) {
|
'submit .js-card-customfield-text'(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
const card = Cards.findOne(Session.get('currentCard'));
|
|
||||||
const customFieldId = this.data()._id;
|
|
||||||
const value = this.currentComponent().getValue();
|
const value = this.currentComponent().getValue();
|
||||||
card.setCustomField(customFieldId,value);
|
this.card.setCustomField(this.customFieldId, value);
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
}).register('cardCustomField-text');
|
}).register('cardCustomField-text');
|
||||||
|
|
||||||
|
// cardCustomField-number
|
||||||
(class extends CardCustomField {
|
(class extends CardCustomField {
|
||||||
|
|
||||||
onCreated() {
|
onCreated() {
|
||||||
|
super.onCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
events() {
|
||||||
|
return [{
|
||||||
|
'submit .js-card-customfield-number'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
const value = parseInt(this.find('input').value);
|
||||||
|
this.card.setCustomField(this.customFieldId, value);
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
}).register('cardCustomField-number');
|
||||||
|
|
||||||
|
// cardCustomField-date
|
||||||
|
(class extends CardCustomField {
|
||||||
|
|
||||||
|
onCreated() {
|
||||||
|
super.onCreated();
|
||||||
|
const self = this;
|
||||||
|
self.date = ReactiveVar();
|
||||||
|
self.now = ReactiveVar(moment());
|
||||||
|
window.setInterval(() => {
|
||||||
|
self.now.set(moment());
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
self.autorun(() => {
|
||||||
|
self.date.set(moment(self.data().value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
showDate() {
|
||||||
|
// 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 this.date.get().calendar(null, {
|
||||||
|
sameElse: 'llll',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
showISODate() {
|
||||||
|
return this.date.get().toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
classes() {
|
||||||
|
if (this.date.get().isBefore(this.now.get(), 'minute') &&
|
||||||
|
this.now.get().isBefore(this.data().value)) {
|
||||||
|
return 'current';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
showTitle() {
|
||||||
|
return `${TAPi18n.__('card-start-on')} ${this.date.get().format('LLLL')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
events() {
|
||||||
|
return [{
|
||||||
|
'click .js-edit-date': Popup.open('cardCustomField-date'),
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
}).register('cardCustomField-date');
|
||||||
|
|
||||||
|
// cardCustomField-datePopup
|
||||||
|
(class extends DatePicker {
|
||||||
|
onCreated() {
|
||||||
|
super.onCreated();
|
||||||
|
const self = this;
|
||||||
|
self.card = Cards.findOne(Session.get('currentCard'));
|
||||||
|
self.customFieldId = this.data()._id;
|
||||||
|
this.data().value && this.date.set(moment(this.data().value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_storeDate(date) {
|
||||||
|
this.card.setCustomField(this.customFieldId, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleteDate() {
|
||||||
|
this.card.setCustomField(this.customFieldId, '');
|
||||||
|
}
|
||||||
|
}).register('cardCustomField-datePopup');
|
||||||
|
|
||||||
|
// cardCustomField-dropdown
|
||||||
|
(class extends CardCustomField {
|
||||||
|
|
||||||
|
onCreated() {
|
||||||
|
super.onCreated();
|
||||||
this._items = this.data().definition.settings.dropdownItems;
|
this._items = this.data().definition.settings.dropdownItems;
|
||||||
this.items = this._items.slice(0);
|
this.items = this._items.slice(0);
|
||||||
this.items.unshift({
|
this.items.unshift({
|
||||||
|
|
@ -77,10 +170,8 @@ CardCustomField.register('cardCustomField');
|
||||||
return [{
|
return [{
|
||||||
'submit .js-card-customfield-dropdown'(evt) {
|
'submit .js-card-customfield-dropdown'(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
const card = Cards.findOne(Session.get('currentCard'));
|
|
||||||
const customFieldId = this.data()._id;
|
|
||||||
const value = this.find('select').value;
|
const value = this.find('select').value;
|
||||||
card.setCustomField(customFieldId,value);
|
this.card.setCustomField(this.customFieldId, value);
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,3 @@
|
||||||
template(name="editCardDate")
|
|
||||||
.edit-card-date
|
|
||||||
form.edit-date
|
|
||||||
.fields
|
|
||||||
.left
|
|
||||||
label(for="date") {{_ 'date'}}
|
|
||||||
input.js-date-field#date(type="text" name="date" value=showDate placeholder=dateFormat autofocus)
|
|
||||||
.right
|
|
||||||
label(for="time") {{_ 'time'}}
|
|
||||||
input.js-time-field#time(type="text" name="time" value=showTime placeholder=timeFormat)
|
|
||||||
.js-datepicker
|
|
||||||
if error.get
|
|
||||||
.warning {{_ error.get}}
|
|
||||||
button.primary.wide.left.js-submit-date(type="submit") {{_ 'save'}}
|
|
||||||
button.js-delete-date.negate.wide.right.js-delete-date {{_ 'delete'}}
|
|
||||||
|
|
||||||
template(name="dateBadge")
|
template(name="dateBadge")
|
||||||
if canModifyCard
|
if canModifyCard
|
||||||
a.js-edit-date.card-date(title="{{showTitle}}" class="{{classes}}")
|
a.js-edit-date.card-date(title="{{showTitle}}" class="{{classes}}")
|
||||||
|
|
|
||||||
|
|
@ -1,91 +1,4 @@
|
||||||
// Edit start & due dates
|
// Edit start & due dates
|
||||||
const EditCardDate = BlazeComponent.extendComponent({
|
|
||||||
template() {
|
|
||||||
return 'editCardDate';
|
|
||||||
},
|
|
||||||
|
|
||||||
onCreated() {
|
|
||||||
this.error = new ReactiveVar('');
|
|
||||||
this.card = this.data();
|
|
||||||
this.date = new ReactiveVar(moment.invalid());
|
|
||||||
},
|
|
||||||
|
|
||||||
onRendered() {
|
|
||||||
const $picker = this.$('.js-datepicker').datepicker({
|
|
||||||
todayHighlight: true,
|
|
||||||
todayBtn: 'linked',
|
|
||||||
language: TAPi18n.getLanguage(),
|
|
||||||
}).on('changeDate', function(evt) {
|
|
||||||
this.find('#date').value = moment(evt.date).format('L');
|
|
||||||
this.error.set('');
|
|
||||||
this.find('#time').focus();
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
if (this.date.get().isValid()) {
|
|
||||||
$picker.datepicker('update', this.date.get().toDate());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
showDate() {
|
|
||||||
if (this.date.get().isValid())
|
|
||||||
return this.date.get().format('L');
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
showTime() {
|
|
||||||
if (this.date.get().isValid())
|
|
||||||
return this.date.get().format('LT');
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
dateFormat() {
|
|
||||||
return moment.localeData().longDateFormat('L');
|
|
||||||
},
|
|
||||||
timeFormat() {
|
|
||||||
return moment.localeData().longDateFormat('LT');
|
|
||||||
},
|
|
||||||
|
|
||||||
events() {
|
|
||||||
return [{
|
|
||||||
'keyup .js-date-field'() {
|
|
||||||
// parse for localized date format in strict mode
|
|
||||||
const dateMoment = moment(this.find('#date').value, 'L', true);
|
|
||||||
if (dateMoment.isValid()) {
|
|
||||||
this.error.set('');
|
|
||||||
this.$('.js-datepicker').datepicker('update', dateMoment.toDate());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'keyup .js-time-field'() {
|
|
||||||
// parse for localized time format in strict mode
|
|
||||||
const dateMoment = moment(this.find('#time').value, 'LT', true);
|
|
||||||
if (dateMoment.isValid()) {
|
|
||||||
this.error.set('');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'submit .edit-date'(evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
|
|
||||||
// if no time was given, init with 12:00
|
|
||||||
const time = evt.target.time.value || moment(new Date().setHours(12, 0, 0)).format('LT');
|
|
||||||
|
|
||||||
const dateString = `${evt.target.date.value} ${time}`;
|
|
||||||
const newDate = moment(dateString, 'L LT', true);
|
|
||||||
if (newDate.isValid()) {
|
|
||||||
this._storeDate(newDate.toDate());
|
|
||||||
Popup.close();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.error.set('invalid-date');
|
|
||||||
evt.target.date.focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-delete-date'(evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
this._deleteDate();
|
|
||||||
Popup.close();
|
|
||||||
},
|
|
||||||
}];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.dateBadge.helpers({
|
Template.dateBadge.helpers({
|
||||||
canModifyCard() {
|
canModifyCard() {
|
||||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||||
|
|
@ -93,7 +6,7 @@ Template.dateBadge.helpers({
|
||||||
});
|
});
|
||||||
|
|
||||||
// editCardStartDatePopup
|
// editCardStartDatePopup
|
||||||
(class extends EditCardDate {
|
(class extends DatePicker {
|
||||||
onCreated() {
|
onCreated() {
|
||||||
super.onCreated();
|
super.onCreated();
|
||||||
this.data().startAt && this.date.set(moment(this.data().startAt));
|
this.data().startAt && this.date.set(moment(this.data().startAt));
|
||||||
|
|
@ -109,7 +22,7 @@ Template.dateBadge.helpers({
|
||||||
}).register('editCardStartDatePopup');
|
}).register('editCardStartDatePopup');
|
||||||
|
|
||||||
// editCardDueDatePopup
|
// editCardDueDatePopup
|
||||||
(class extends EditCardDate {
|
(class extends DatePicker {
|
||||||
onCreated() {
|
onCreated() {
|
||||||
super.onCreated();
|
super.onCreated();
|
||||||
this.data().dueAt && this.date.set(moment(this.data().dueAt));
|
this.data().dueAt && this.date.set(moment(this.data().dueAt));
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,3 @@
|
||||||
.edit-card-date
|
|
||||||
.fields
|
|
||||||
.left
|
|
||||||
width: 56%
|
|
||||||
.right
|
|
||||||
width: 38%
|
|
||||||
.datepicker
|
|
||||||
width: 100%
|
|
||||||
table
|
|
||||||
width: 100%
|
|
||||||
border: none
|
|
||||||
border-spacing: 0
|
|
||||||
border-collapse: collapse
|
|
||||||
thead
|
|
||||||
background: none
|
|
||||||
td, th
|
|
||||||
box-sizing: border-box
|
|
||||||
|
|
||||||
|
|
||||||
.card-date
|
.card-date
|
||||||
display: block
|
display: block
|
||||||
border-radius: 4px
|
border-radius: 4px
|
||||||
|
|
|
||||||
15
client/components/forms/datepicker.jade
Normal file
15
client/components/forms/datepicker.jade
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
template(name="datepicker")
|
||||||
|
.datepicker-container
|
||||||
|
form.edit-date
|
||||||
|
.fields
|
||||||
|
.left
|
||||||
|
label(for="date") {{_ 'date'}}
|
||||||
|
input.js-date-field#date(type="text" name="date" value=showDate placeholder=dateFormat autofocus)
|
||||||
|
.right
|
||||||
|
label(for="time") {{_ 'time'}}
|
||||||
|
input.js-time-field#time(type="text" name="time" value=showTime placeholder=timeFormat)
|
||||||
|
.js-datepicker
|
||||||
|
if error.get
|
||||||
|
.warning {{_ error.get}}
|
||||||
|
button.primary.wide.left.js-submit-date(type="submit") {{_ 'save'}}
|
||||||
|
button.js-delete-date.negate.wide.right.js-delete-date {{_ 'delete'}}
|
||||||
17
client/components/forms/datepicker.styl
Normal file
17
client/components/forms/datepicker.styl
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
.datepicker-container
|
||||||
|
.fields
|
||||||
|
.left
|
||||||
|
width: 56%
|
||||||
|
.right
|
||||||
|
width: 38%
|
||||||
|
.datepicker
|
||||||
|
width: 100%
|
||||||
|
table
|
||||||
|
width: 100%
|
||||||
|
border: none
|
||||||
|
border-spacing: 0
|
||||||
|
border-collapse: collapse
|
||||||
|
thead
|
||||||
|
background: none
|
||||||
|
td, th
|
||||||
|
box-sizing: border-box
|
||||||
86
client/lib/datepicker.js
Normal file
86
client/lib/datepicker.js
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
DatePicker = BlazeComponent.extendComponent({
|
||||||
|
template() {
|
||||||
|
return 'datepicker';
|
||||||
|
},
|
||||||
|
|
||||||
|
onCreated() {
|
||||||
|
this.error = new ReactiveVar('');
|
||||||
|
this.card = this.data();
|
||||||
|
this.date = new ReactiveVar(moment.invalid());
|
||||||
|
},
|
||||||
|
|
||||||
|
onRendered() {
|
||||||
|
const $picker = this.$('.js-datepicker').datepicker({
|
||||||
|
todayHighlight: true,
|
||||||
|
todayBtn: 'linked',
|
||||||
|
language: TAPi18n.getLanguage(),
|
||||||
|
}).on('changeDate', function(evt) {
|
||||||
|
this.find('#date').value = moment(evt.date).format('L');
|
||||||
|
this.error.set('');
|
||||||
|
this.find('#time').focus();
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
if (this.date.get().isValid()) {
|
||||||
|
$picker.datepicker('update', this.date.get().toDate());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
showDate() {
|
||||||
|
if (this.date.get().isValid())
|
||||||
|
return this.date.get().format('L');
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
showTime() {
|
||||||
|
if (this.date.get().isValid())
|
||||||
|
return this.date.get().format('LT');
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
dateFormat() {
|
||||||
|
return moment.localeData().longDateFormat('L');
|
||||||
|
},
|
||||||
|
timeFormat() {
|
||||||
|
return moment.localeData().longDateFormat('LT');
|
||||||
|
},
|
||||||
|
|
||||||
|
events() {
|
||||||
|
return [{
|
||||||
|
'keyup .js-date-field'() {
|
||||||
|
// parse for localized date format in strict mode
|
||||||
|
const dateMoment = moment(this.find('#date').value, 'L', true);
|
||||||
|
if (dateMoment.isValid()) {
|
||||||
|
this.error.set('');
|
||||||
|
this.$('.js-datepicker').datepicker('update', dateMoment.toDate());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'keyup .js-time-field'() {
|
||||||
|
// parse for localized time format in strict mode
|
||||||
|
const dateMoment = moment(this.find('#time').value, 'LT', true);
|
||||||
|
if (dateMoment.isValid()) {
|
||||||
|
this.error.set('');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'submit .edit-date'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
|
||||||
|
// if no time was given, init with 12:00
|
||||||
|
const time = evt.target.time.value || moment(new Date().setHours(12, 0, 0)).format('LT');
|
||||||
|
|
||||||
|
const dateString = `${evt.target.date.value} ${time}`;
|
||||||
|
const newDate = moment(dateString, 'L LT', true);
|
||||||
|
if (newDate.isValid()) {
|
||||||
|
this._storeDate(newDate.toDate());
|
||||||
|
Popup.close();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.error.set('invalid-date');
|
||||||
|
evt.target.date.focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-delete-date'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
this._deleteDate();
|
||||||
|
Popup.close();
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -111,6 +111,7 @@
|
||||||
"card-start": "Start",
|
"card-start": "Start",
|
||||||
"card-start-on": "Starts on",
|
"card-start-on": "Starts on",
|
||||||
"cardAttachmentsPopup-title": "Attach From",
|
"cardAttachmentsPopup-title": "Attach From",
|
||||||
|
"cardCustomField-datePopup-title": "Change date",
|
||||||
"cardCustomFieldsPopup-title": "Edit custom fields",
|
"cardCustomFieldsPopup-title": "Edit custom fields",
|
||||||
"cardDeletePopup-title": "Delete Card?",
|
"cardDeletePopup-title": "Delete Card?",
|
||||||
"cardDetailsActionsPopup-title": "Card Actions",
|
"cardDetailsActionsPopup-title": "Card Actions",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue