Browse Source

Partial Fix: Vote and Planning Poker: Setting date and time now works
for some languages that have ascii characters in date format.

Thanks to xet7 !

Related #3837

Lauri Ojansivu 4 years ago
parent
commit
57f31d443f
1 changed files with 356 additions and 30 deletions
  1. 356 30
      client/components/cards/cardDetails.js

+ 356 - 30
client/components/cards/cardDetails.js

@@ -170,7 +170,7 @@ BlazeComponent.extendComponent({
       }).fetch();
 
       if (integrations.length > 0) {
-        integrations.forEach(integration => {
+        integrations.forEach((integration) => {
           Meteor.call(
             'outgoingWebhooks',
             integration,
@@ -336,9 +336,7 @@ BlazeComponent.extendComponent({
         },
         'submit .js-card-details-title'(event) {
           event.preventDefault();
-          const title = this.currentComponent()
-            .getValue()
-            .trim();
+          const title = this.currentComponent().getValue().trim();
           if (title) {
             this.data().setTitle(title);
           } else {
@@ -347,9 +345,7 @@ BlazeComponent.extendComponent({
         },
         'submit .js-card-details-assigner'(event) {
           event.preventDefault();
-          const assigner = this.currentComponent()
-            .getValue()
-            .trim();
+          const assigner = this.currentComponent().getValue().trim();
           if (assigner) {
             this.data().setAssignedBy(assigner);
           } else {
@@ -358,9 +354,7 @@ BlazeComponent.extendComponent({
         },
         'submit .js-card-details-requester'(event) {
           event.preventDefault();
-          const requester = this.currentComponent()
-            .getValue()
-            .trim();
+          const requester = this.currentComponent().getValue().trim();
           if (requester) {
             this.data().setRequestedBy(requester);
           } else {
@@ -576,7 +570,7 @@ Template.cardDetailsActionsPopup.events({
     const minOrder = _.min(
       this.list()
         .cards(this.swimlaneId)
-        .map(c => c.sort),
+        .map((c) => c.sort),
     );
     this.move(this.boardId, this.swimlaneId, this.listId, minOrder - 1);
   },
@@ -585,7 +579,7 @@ Template.cardDetailsActionsPopup.events({
     const maxOrder = _.max(
       this.list()
         .cards(this.swimlaneId)
-        .map(c => c.sort),
+        .map((c) => c.sort),
     );
     this.move(this.boardId, this.swimlaneId, this.listId, maxOrder + 1);
   },
@@ -604,7 +598,7 @@ Template.cardDetailsActionsPopup.events({
   },
 });
 
-Template.editCardTitleForm.onRendered(function() {
+Template.editCardTitleForm.onRendered(function () {
   autosize(this.$('.js-edit-card-title'));
 });
 
@@ -618,7 +612,7 @@ Template.editCardTitleForm.events({
   },
 });
 
-Template.editCardRequesterForm.onRendered(function() {
+Template.editCardRequesterForm.onRendered(function () {
   autosize(this.$('.js-edit-card-requester'));
 });
 
@@ -631,7 +625,7 @@ Template.editCardRequesterForm.events({
   },
 });
 
-Template.editCardAssignerForm.onRendered(function() {
+Template.editCardAssignerForm.onRendered(function () {
   autosize(this.$('.js-edit-card-assigner'));
 });
 
@@ -716,9 +710,7 @@ Template.copyCardPopup.events({
     const textarea = $('#copy-card-title');
     const title = textarea.val().trim();
     // insert new card to the bottom of new list
-    card.sort = Lists.findOne(card.listId)
-      .cards()
-      .count();
+    card.sort = Lists.findOne(card.listId).cards().count();
 
     if (title) {
       card.title = title;
@@ -749,9 +741,7 @@ Template.copyChecklistToManyCardsPopup.events({
     const textarea = $('#copy-card-title');
     const titleEntry = textarea.val().trim();
     // insert new card to the bottom of new list
-    card.sort = Lists.findOne(card.listId)
-      .cards()
-      .count();
+    card.sort = Lists.findOne(card.listId).cards().count();
 
     if (titleEntry) {
       const titleList = JSON.parse(titleEntry);
@@ -768,13 +758,13 @@ Template.copyChecklistToManyCardsPopup.events({
         Filter.addException(_id);
 
         // copy checklists
-        Checklists.find({ cardId: oldId }).forEach(ch => {
+        Checklists.find({ cardId: oldId }).forEach((ch) => {
           ch.copy(_id);
         });
 
         // copy subtasks
         const cursor = Cards.find({ parentId: oldId });
-        cursor.forEach(function() {
+        cursor.forEach(function () {
           'use strict';
           const subtask = arguments[0];
           subtask.parentId = _id;
@@ -783,7 +773,7 @@ Template.copyChecklistToManyCardsPopup.events({
         });
 
         // copy card comments
-        CardComments.find({ cardId: oldId }).forEach(cmt => {
+        CardComments.find({ cardId: oldId }).forEach((cmt) => {
           cmt.copy(_id);
         });
       }
@@ -799,7 +789,7 @@ BlazeComponent.extendComponent({
   },
 
   colors() {
-    return ALLOWED_COLORS.map(color => ({ color, name: '' }));
+    return ALLOWED_COLORS.map((color) => ({ color, name: '' }));
   },
 
   isSelected(color) {
@@ -922,7 +912,7 @@ BlazeComponent.extendComponent({
             }
           }
         },
-        'click .js-delete': Popup.afterConfirm('cardDelete', function() {
+        'click .js-delete': Popup.afterConfirm('cardDelete', function () {
           Popup.close();
           // verify that there are no linked cards
           if (Cards.find({ linkedId: this._id }).count() === 0) {
@@ -1029,6 +1019,8 @@ BlazeComponent.extendComponent({
             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()) {
             // if active vote -  store it
@@ -1039,6 +1031,159 @@ BlazeComponent.extendComponent({
               this.currentData().vote = { end: newDate.toDate() }; // set vote end temp
               Popup.back();
             }
+
+
+          */
+
+          // Try to parse different date formats of all languages.
+          // This code is same for vote and planning poker.
+          const usaDate = moment(dateString, 'L LT', true);
+          const euroAmDate = moment(dateString, 'DD.MM.YYYY LT', true);
+          const euro24hDate = moment(dateString, 'DD.MM.YYYY HH.mm', true);
+          const eurodotDate = moment(dateString, 'DD.MM.YYYY HH:mm', true);
+          const minusDate = moment(dateString, 'YYYY-MM-DD HH:mm', true);
+          const slashDate = moment(dateString, 'DD/MM/YYYY HH.mm', true);
+          const dotDate = moment(dateString, 'DD/MM/YYYY HH:mm', true);
+          const brezhonegDate = moment(dateString, 'DD/MM/YYYY h[e]mm A', true);
+          const hrvatskiDate = moment(dateString, 'DD. MM. YYYY H:mm', true);
+          const latviaDate = moment(dateString, 'YYYY.MM.DD. H:mm', true);
+          const nederlandsDate = moment(dateString, 'DD-MM-YYYY HH:mm', true);
+          // greekDate does not work: el Greek Ελληνικά ,
+          // it has date format DD/MM/YYYY h:mm MM like 20/06/2021 11:15 MM
+          // where MM is maybe some text like AM/PM ?
+          // Also some other languages that have non-ascii characters in dates
+          // do not work.
+          const greekDate = moment(dateString, 'DD/MM/YYYY h:mm A', true);
+          const macedonianDate = moment(dateString, 'D.MM.YYYY H:mm', true);
+
+          if (usaDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(usaDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: usaDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (euroAmDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(euroAmDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: euroAmDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (euro24hDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(euro24hDate.toDate());
+              this.card.setPokerEnd(euro24hDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: euro24hDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (eurodotDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(eurodotDate.toDate());
+              this.card.setPokerEnd(eurodotDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: eurodotDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (minusDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(minusDate.toDate());
+              this.card.setPokerEnd(minusDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: minusDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (slashDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(slashDate.toDate());
+              this.card.setPokerEnd(slashDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: slashDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (dotDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(dotDate.toDate());
+              this.card.setPokerEnd(dotDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: dotDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (brezhonegDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(brezhonegDate.toDate());
+              this.card.setPokerEnd(brezhonegDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: brezhonegDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (hrvatskiDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(hrvatskiDate.toDate());
+              this.card.setPokerEnd(hrvatskiDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: hrvatskiDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (latviaDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(latviaDate.toDate());
+              this.card.setPokerEnd(latviaDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: latviaDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (nederlandsDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(nederlandsDate.toDate());
+              this.card.setPokerEnd(nederlandsDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: nederlandsDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (greekDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(greekDate.toDate());
+              this.card.setPokerEnd(greekDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: greekDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (macedonianDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(macedonianDate.toDate());
+              this.card.setPokerEnd(macedonianDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: macedonianDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
           } else {
             this.error.set('invalid-date');
             evt.target.date.focus();
@@ -1087,7 +1232,7 @@ BlazeComponent.extendComponent({
           }
           Popup.close();
         },
-        'click .js-remove-poker': Popup.afterConfirm('deletePoker', () => {
+        'click .js-remove-poker': Popup.afterConfirm('deletePoker', (event) => {
           event.preventDefault();
           this.currentCard.unsetPoker();
           Popup.close();
@@ -1105,8 +1250,28 @@ BlazeComponent.extendComponent({
 (class extends DatePicker {
   onCreated() {
     super.onCreated(moment().format('YYYY-MM-DD HH:mm'));
-    this.data().getPokerEnd() && this.date.set(moment(this.data().getPokerEnd()));
+    this.data().getPokerEnd() &&
+      this.date.set(moment(this.data().getPokerEnd()));
+  }
+
+  /*
+  Tried to use dateFormat and timeFormat from client/components/lib/datepicker.js
+  to make detecting all date formats not necessary,
+  but got error "language mk does not exist".
+  Maybe client/components/lib/datepicker.jade could have hidden input field for
+  datepicker format that could be used to detect date format?
+
+  dateFormat() {
+    return moment.localeData().longDateFormat('L');
+  }
+
+  timeFormat() {
+    return moment.localeData().longDateFormat('LT');
   }
+
+  const newDate = moment(dateString, dateformat() + ' ' + timeformat(), true);
+  */
+
   events() {
     return [
       {
@@ -1119,7 +1284,16 @@ BlazeComponent.extendComponent({
             moment(new Date().setHours(12, 0, 0)).format('LT');
 
           const dateString = `${evt.target.date.value} ${time}`;
-          const newDate = moment(dateString, 'L LT', true);
+
+          /*
+          Tried to use dateFormat and timeFormat from client/components/lib/datepicker.js
+          to make detecting all date formats not necessary,
+          but got error "language mk does not exist".
+          Maybe client/components/lib/datepicker.jade could have hidden input field for
+          datepicker format that could be used to detect date format?
+
+          const newDate = moment(dateString, dateformat() + ' ' + timeformat(), true);
+
           if (newDate.isValid()) {
             // if active poker -  store it
             if (this.currentData().getPokerQuestion()) {
@@ -1129,8 +1303,160 @@ BlazeComponent.extendComponent({
               this.currentData().poker = { end: newDate.toDate() }; // set poker end temp
               Popup.back();
             }
+          */
+
+          // Try to parse different date formats of all languages.
+          // This code is same for vote and planning poker.
+          const usaDate = moment(dateString, 'L LT', true);
+          const euroAmDate = moment(dateString, 'DD.MM.YYYY LT', true);
+          const euro24hDate = moment(dateString, 'DD.MM.YYYY HH.mm', true);
+          const eurodotDate = moment(dateString, 'DD.MM.YYYY HH:mm', true);
+          const minusDate = moment(dateString, 'YYYY-MM-DD HH:mm', true);
+          const slashDate = moment(dateString, 'DD/MM/YYYY HH.mm', true);
+          const dotDate = moment(dateString, 'DD/MM/YYYY HH:mm', true);
+          const brezhonegDate = moment(dateString, 'DD/MM/YYYY h[e]mm A', true);
+          const hrvatskiDate = moment(dateString, 'DD. MM. YYYY H:mm', true);
+          const latviaDate = moment(dateString, 'YYYY.MM.DD. H:mm', true);
+          const nederlandsDate = moment(dateString, 'DD-MM-YYYY HH:mm', true);
+          // greekDate does not work: el Greek Ελληνικά ,
+          // it has date format DD/MM/YYYY h:mm MM like 20/06/2021 11:15 MM
+          // where MM is maybe some text like AM/PM ?
+          // Also some other languages that have non-ascii characters in dates
+          // do not work.
+          const greekDate = moment(dateString, 'DD/MM/YYYY h:mm A', true);
+          const macedonianDate = moment(dateString, 'D.MM.YYYY H:mm', true);
+
+          if (usaDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(usaDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: usaDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (euroAmDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(euroAmDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: euroAmDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (euro24hDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(euro24hDate.toDate());
+              this.card.setPokerEnd(euro24hDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: euro24hDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (eurodotDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(eurodotDate.toDate());
+              this.card.setPokerEnd(eurodotDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: eurodotDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (minusDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(minusDate.toDate());
+              this.card.setPokerEnd(minusDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: minusDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (slashDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(slashDate.toDate());
+              this.card.setPokerEnd(slashDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: slashDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (dotDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(dotDate.toDate());
+              this.card.setPokerEnd(dotDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: dotDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (brezhonegDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(brezhonegDate.toDate());
+              this.card.setPokerEnd(brezhonegDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: brezhonegDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (hrvatskiDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(hrvatskiDate.toDate());
+              this.card.setPokerEnd(hrvatskiDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: hrvatskiDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (latviaDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(latviaDate.toDate());
+              this.card.setPokerEnd(latviaDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: latviaDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (nederlandsDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(nederlandsDate.toDate());
+              this.card.setPokerEnd(nederlandsDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: nederlandsDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (greekDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(greekDate.toDate());
+              this.card.setPokerEnd(greekDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: greekDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
+          } else if (macedonianDate.isValid()) {
+            // if active poker -  store it
+            if (this.currentData().getPokerQuestion()) {
+              this._storeDate(macedonianDate.toDate());
+              this.card.setPokerEnd(macedonianDate.toDate());
+              Popup.close();
+            } else {
+              this.currentData().poker = { end: macedonianDate.toDate() }; // set poker end temp
+              Popup.back();
+            }
           } else {
-            this.error.set('invalid-date');
+            // this.error.set('invalid-date);
+            this.error.set('invalid-date' + ' ' + dateString);
             evt.target.date.focus();
           }
         },