From d4497d7aeb968dbb9f8c4b84fbcc0f7cc3668167 Mon Sep 17 00:00:00 2001 From: shoetten Date: Fri, 5 Feb 2016 20:23:09 +0100 Subject: Add basic start and due dates for cards. --- client/components/cards/cardDate.jade | 20 ++++ client/components/cards/cardDate.js | 193 +++++++++++++++++++++++++++++++ client/components/cards/cardDate.styl | 50 ++++++++ client/components/cards/cardDetails.jade | 13 +++ client/components/cards/cardDetails.js | 2 + client/components/cards/cardDetails.styl | 7 +- 6 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 client/components/cards/cardDate.jade create mode 100644 client/components/cards/cardDate.js create mode 100644 client/components/cards/cardDate.styl (limited to 'client/components/cards') diff --git a/client/components/cards/cardDate.jade b/client/components/cards/cardDate.jade new file mode 100644 index 00000000..ca074879 --- /dev/null +++ b/client/components/cards/cardDate.jade @@ -0,0 +1,20 @@ +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") + a.js-edit-date.card-date(title="{{showTitle}}") + time(datetime="{{showISODate}}") + | {{showDate}} diff --git a/client/components/cards/cardDate.js b/client/components/cards/cardDate.js new file mode 100644 index 00000000..4a24941d --- /dev/null +++ b/client/components/cards/cardDate.js @@ -0,0 +1,193 @@ +// 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() { + let $picker = this.$('.js-datepicker').datepicker({ + todayHighlight: true, + todayBtn: 'linked', + language: TAPi18n.getLanguage() + }).on('changeDate', function(e) { + const localDate = moment(e.date).format('L'); + date.value = localDate; + this.error.set(''); + 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'); + }, + showTime() { + if (this.date.get().isValid()) + return this.date.get().format('LT'); + }, + dateFormat() { + return moment.localeData().longDateFormat('L'); + }, + timeFormat() { + return moment.localeData().longDateFormat('LT'); + }, + + events() { + return [{ + 'keyup .js-date-field'(evt) { + // parse for localized date format in strict mode + const dateMoment = moment(date.value, 'L', true); + if (dateMoment.isValid()) { + this.error.set(''); + this.$('.js-datepicker').datepicker('update', dateMoment.toDate()); + } + }, + 'keyup .js-time-field'(evt) { + // parse for localized time format in strict mode + const dateMoment = moment(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 + var time = evt.target.time.value || moment(new Date().setHours(12,0,0)).format('LT'); + + const dateString = evt.target.date.value + ' ' + time; + const newDate = moment.utc(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(); + }, + }]; + }, +}); + +// editCardStartDatePopup +(class extends EditCardDate { + onCreated() { + super(); + if (this.data().startAt) { + this.date.set(moment.utc(this.data().startAt)); + } + } + + _storeDate(date) { + this.card.setStart(date); + } + + _deleteDate() { + this.card.unsetStart(); + } +}).register('editCardStartDatePopup'); + +// editCardDueDatePopup +(class extends EditCardDate { + onCreated() { + super(); + if (this.data().dueAt !== undefined) { + this.date.set(moment.utc(this.data().dueAt)); + } + } + + onRendered() { + super(); + if (moment.isDate(this.card.startAt)) { + this.$('.js-datepicker').datepicker('setStartDate', this.card.startAt); + } + } + + _storeDate(date) { + this.card.setDue(date); + } + + _deleteDate() { + this.card.unsetDue(); + } +}).register('editCardDueDatePopup'); + + + +// Display start & due dates +const CardDate = BlazeComponent.extendComponent({ + template() { + return 'dateBadge'; + }, + + onCreated() { + this.date = ReactiveVar(); + }, + + 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' + }); + }, + + showTitle() { + return this.date.get().format('LLLL'); + }, + + showISODate() { + return this.date.get().toISOString(); + }, +}); + +// cardStartDate +(class extends CardDate { + onCreated() { + super(); + let self = this; + this.autorun(() => { + self.date.set(moment.utc(this.data().startAt)); + }); + } + + events() { + return super.events().concat({ + 'click .js-edit-date': Popup.open('editCardStartDate'), + }); + } +}).register('cardStartDate'); + +// cardDueDate +(class extends CardDate { + onCreated() { + super(); + let self = this; + this.autorun(() => { + self.date.set(moment.utc(this.data().dueAt)); + }); + } + + events() { + return super.events().concat({ + 'click .js-edit-date': Popup.open('editCardDueDate'), + }); + } +}).register('cardDueDate'); diff --git a/client/components/cards/cardDate.styl b/client/components/cards/cardDate.styl new file mode 100644 index 00000000..e9d56f79 --- /dev/null +++ b/client/components/cards/cardDate.styl @@ -0,0 +1,50 @@ +.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 + display: block + border-radius: 4px + padding: 1px 3px; + + background-color: #dbdbdb + &:hover, &.is-active + background-color: #b3b3b3 + + &.current + background-color: #42ca00 + &:hover, &.is-active + background-color: darken(#42ca00, 15) + + &.almost-due + background-color: #fad900 + &:hover, &.is-active + background-color: darken(#fad900, 15) + + &.due + background-color: #fa3f00 + &:hover, &.is-active + background-color: darken(#fa3f00, 15) + + time + &::before + font: normal normal normal 14px/1 FontAwesome + font-size: inherit + -webkit-font-smoothing: antialiased + content: "\f017" // clock symbol + margin-right: 0.3em \ No newline at end of file diff --git a/client/components/cards/cardDetails.jade b/client/components/cards/cardDetails.jade index 734fc7e3..69725d76 100644 --- a/client/components/cards/cardDetails.jade +++ b/client/components/cards/cardDetails.jade @@ -35,6 +35,17 @@ template(name="cardDetails") a.card-label.add-label.js-add-labels(title="{{_ 'card-labels-title'}}") i.fa.fa-plus + if startAt + .card-details-item.card-details-item-start + h3.card-details-item-title {{_ 'start-at'}} + +cardStartDate + + if dueAt + .card-details-item.card-details-item-due + h3.card-details-item-title {{_ 'due-at'}} + +cardDueDate + + //- XXX We should use "editable" to avoid repetiting ourselves if currentUser.isBoardMember h3.card-details-item-title {{_ 'description'}} @@ -91,6 +102,8 @@ template(name="cardDetailsActionsPopup") li: a.js-members {{_ 'card-edit-members'}} li: a.js-labels {{_ 'card-edit-labels'}} li: a.js-attachments {{_ 'card-edit-attachments'}} + li: a.js-start-date {{_ 'editCardStartDatePopup-title'}} + li: a.js-due-date {{_ 'editCardDueDatePopup-title'}} hr ul.pop-over-list li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}} diff --git a/client/components/cards/cardDetails.js b/client/components/cards/cardDetails.js index b6f17c23..32980926 100644 --- a/client/components/cards/cardDetails.js +++ b/client/components/cards/cardDetails.js @@ -143,6 +143,8 @@ Template.cardDetailsActionsPopup.events({ 'click .js-members': Popup.open('cardMembers'), 'click .js-labels': Popup.open('cardLabels'), 'click .js-attachments': Popup.open('cardAttachments'), + 'click .js-start-date': Popup.open('editCardStartDate'), + 'click .js-due-date': Popup.open('editCardDueDate'), 'click .js-move-card': Popup.open('moveCard'), 'click .js-move-card-to-top'(evt) { evt.preventDefault(); diff --git a/client/components/cards/cardDetails.styl b/client/components/cards/cardDetails.styl index d7d29551..f209862c 100644 --- a/client/components/cards/cardDetails.styl +++ b/client/components/cards/cardDetails.styl @@ -73,8 +73,13 @@ margin: 15px 0 .card-details-item + margin-right: 0.5em + &:last-child + margin-right: 0 &.card-details-item-labels, - &.card-details-item-members + &.card-details-item-members, + &.card-details-item-start, + &.card-details-item-due width: 50% flex-shrink: 1 -- cgit v1.2.3-1-g7c22