summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRémy Coutable <remy@rymai.me>2016-10-17 12:51:09 +0000
committerRémy Coutable <remy@rymai.me>2016-10-17 14:53:10 +0200
commit7bd0b8ec4ae57b4fcbdff5c54f5fb3e32b9dc9ee (patch)
treef56f211b0d9aa576c294d1066b4adbe4c1852879
parent08a9e8057675161c7ccf78b7307cc63827f12693 (diff)
downloadgitlab-ce-7bd0b8ec4ae57b4fcbdff5c54f5fb3e32b9dc9ee.tar.gz
Merge branch 'safari-is-baNaNas' into 'master'
Fix Safari displaying NaN for selected due date ## What does this MR do? 1. Stops using `Date.parse` to parse selected due dates. 2. Refactors DueDateSelectors to be more maintainable and readable ## Are there points in the code the reviewer needs to double check? **To review the actual fix, look here:** https://gitlab.com/gitlab-org/gitlab-ce/commit/4ad43ac3a12902d7ea01dc09f8a361b01c21a0ee. It would be difficult to pick out from the overall diff. ## Why was this MR needed? In Safari, the due date selector was displaying 'NaN' when a date is selected, which was being returned by `Date.parse`. Because `Date.parse` is implemented differently across browsers it's generally recommended to favor implicit Date parsing with the `Date` constructor. For more background on this, [see MDN on Date.parse](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/parse). Also, the code for DueDateSelector was pretty messy, and its logic was very tightly coupled, so I refactored it. None of the basic logic changed, I just broke it up into smaller pieces and made it more OO. Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/22984 See merge request !6797 Signed-off-by: Rémy Coutable <remy@rymai.me>
-rw-r--r--CHANGELOG1
-rw-r--r--app/assets/javascripts/dispatcher.js2
-rw-r--r--app/assets/javascripts/due_date_select.js107
-rw-r--r--app/assets/javascripts/due_date_select.js.es6161
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
5 files changed, 164 insertions, 109 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 7abf3bed61b..e4b28d3722f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@ v 8.12.7
- Fix Long commit messages overflow viewport in file tree. !6573
- Use gitlab-markup gem instead of github-markup to fix `.rst` file rendering. !6659
- Prevent flash alert text from being obscured when container is fluid. !6694
+ - Fix due date being displayed as NaN in Safari. !6797
- Fix JS bug with select2 because of missing `data-field` attribute in select box. !6812
- Do not alter 'force_remove_source_branch' options on MergeRequest unless specified. !6817
- Fix GFM autocomplete setup being called several times. !6840
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index ddf11ecf34c..8fe909abc0e 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -45,7 +45,7 @@
case 'projects:milestones:new':
case 'projects:milestones:edit':
new ZenMode();
- new DueDateSelect();
+ new gl.DueDateSelectors();
new GLForm($('.milestone-form'));
break;
case 'groups:milestones:new':
diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js
deleted file mode 100644
index bf68b7e3a9b..00000000000
--- a/app/assets/javascripts/due_date_select.js
+++ /dev/null
@@ -1,107 +0,0 @@
-(function() {
- this.DueDateSelect = (function() {
- function DueDateSelect() {
- var $datePicker, $dueDate, $loading;
- // Milestone edit/new form
- $datePicker = $('.datepicker');
- if ($datePicker.length) {
- $dueDate = $('#milestone_due_date');
- $datePicker.datepicker({
- dateFormat: 'yy-mm-dd',
- onSelect: function(dateText, inst) {
- return $dueDate.val(dateText);
- }
- }).datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', $dueDate.val()));
- }
- $('.js-clear-due-date').on('click', function(e) {
- e.preventDefault();
- return $.datepicker._clearDate($datePicker);
- });
- // Issuable sidebar
- $loading = $('.js-issuable-update .due_date').find('.block-loading').hide();
- $('.js-due-date-select').each(function(i, dropdown) {
- var $block, $dropdown, $dropdownParent, $selectbox, $sidebarValue, $value, $valueContent, abilityName, addDueDate, fieldName, issueUpdateURL;
- $dropdown = $(dropdown);
- $dropdownParent = $dropdown.closest('.dropdown');
- $datePicker = $dropdownParent.find('.js-due-date-calendar');
- $block = $dropdown.closest('.block');
- $selectbox = $dropdown.closest('.selectbox');
- $value = $block.find('.value');
- $valueContent = $block.find('.value-content');
- $sidebarValue = $('.js-due-date-sidebar-value', $block);
- fieldName = $dropdown.data('field-name');
- abilityName = $dropdown.data('ability-name');
- issueUpdateURL = $dropdown.data('issue-update');
- $dropdown.glDropdown({
- hidden: function() {
- $selectbox.hide();
- return $value.css('display', '');
- }
- });
- addDueDate = function(isDropdown) {
- var data, date, mediumDate, value;
- // Create the post date
- value = $("input[name='" + fieldName + "']").val();
- if (value !== '') {
- date = new Date(value.replace(new RegExp('-', 'g'), ','));
- mediumDate = $.datepicker.formatDate('M d, yy', date);
- } else {
- mediumDate = 'No due date';
- }
- data = {};
- data[abilityName] = {};
- data[abilityName].due_date = value;
- return $.ajax({
- type: 'PUT',
- url: issueUpdateURL,
- data: data,
- dataType: 'json',
- beforeSend: function() {
- var cssClass;
- $loading.fadeIn();
- if (isDropdown) {
- $dropdown.trigger('loading.gl.dropdown');
- $selectbox.hide();
- }
- $value.css('display', '');
- cssClass = Date.parse(mediumDate) ? 'bold' : 'no-value';
- $valueContent.html("<span class='" + cssClass + "'>" + mediumDate + "</span>");
- $sidebarValue.html(mediumDate);
- if (value !== '') {
- return $('.js-remove-due-date-holder').removeClass('hidden');
- } else {
- return $('.js-remove-due-date-holder').addClass('hidden');
- }
- }
- }).done(function(data) {
- if (isDropdown) {
- $dropdown.trigger('loaded.gl.dropdown');
- $dropdown.dropdown('toggle');
- }
- return $loading.fadeOut();
- });
- };
- $block.on('click', '.js-remove-due-date', function(e) {
- e.preventDefault();
- $("input[name='" + fieldName + "']").val('');
- return addDueDate(false);
- });
- return $datePicker.datepicker({
- dateFormat: 'yy-mm-dd',
- defaultDate: $("input[name='" + fieldName + "']").val(),
- altField: "input[name='" + fieldName + "']",
- onSelect: function() {
- return addDueDate(true);
- }
- });
- });
- $(document).off('click', '.ui-datepicker-header a').on('click', '.ui-datepicker-header a', function(e) {
- return e.stopImmediatePropagation();
- });
- }
-
- return DueDateSelect;
-
- })();
-
-}).call(this);
diff --git a/app/assets/javascripts/due_date_select.js.es6 b/app/assets/javascripts/due_date_select.js.es6
new file mode 100644
index 00000000000..41925fcc8e3
--- /dev/null
+++ b/app/assets/javascripts/due_date_select.js.es6
@@ -0,0 +1,161 @@
+(function(global) {
+ class DueDateSelect {
+ constructor({ $dropdown, $loading } = {}) {
+ const $dropdownParent = $dropdown.closest('.dropdown');
+ const $block = $dropdown.closest('.block');
+ this.$loading = $loading;
+ this.$dropdown = $dropdown;
+ this.$dropdownParent = $dropdownParent;
+ this.$datePicker = $dropdownParent.find('.js-due-date-calendar');
+ this.$block = $block;
+ this.$selectbox = $dropdown.closest('.selectbox');
+ this.$value = $block.find('.value');
+ this.$valueContent = $block.find('.value-content');
+ this.$sidebarValue = $('.js-due-date-sidebar-value', $block);
+ this.fieldName = $dropdown.data('field-name'),
+ this.abilityName = $dropdown.data('ability-name'),
+ this.issueUpdateURL = $dropdown.data('issue-update')
+
+ this.rawSelectedDate = null;
+ this.displayedDate = null;
+ this.datePayload = null;
+
+ this.initGlDropdown();
+ this.initRemoveDueDate();
+ this.initDatePicker();
+ this.initStopPropagation();
+ }
+
+ initGlDropdown() {
+ this.$dropdown.glDropdown({
+ hidden: () => {
+ this.$selectbox.hide();
+ this.$value.css('display', '');
+ }
+ });
+ }
+
+ initDatePicker() {
+ this.$datePicker.datepicker({
+ dateFormat: 'yy-mm-dd',
+ defaultDate: $("input[name='" + this.fieldName + "']").val(),
+ altField: "input[name='" + this.fieldName + "']",
+ onSelect: () => {
+ return this.saveDueDate(true);
+ }
+ });
+ }
+
+ initRemoveDueDate() {
+ this.$block.on('click', '.js-remove-due-date', (e) => {
+ e.preventDefault();
+ $("input[name='" + this.fieldName + "']").val('');
+ return this.saveDueDate(false);
+ });
+ }
+
+ initStopPropagation() {
+ $(document).off('click', '.ui-datepicker-header a').on('click', '.ui-datepicker-header a', (e) => {
+ return e.stopImmediatePropagation();
+ });
+ }
+
+ saveDueDate(isDropdown) {
+ this.parseSelectedDate();
+ this.prepSelectedDate();
+ this.submitSelectedDate(isDropdown);
+ }
+
+ parseSelectedDate() {
+ this.rawSelectedDate = $("input[name='" + this.fieldName + "']").val();
+ if (this.rawSelectedDate.length) {
+ let dateObj = new Date(this.rawSelectedDate);
+ this.displayedDate = $.datepicker.formatDate('M d, yy', dateObj);
+ } else {
+ this.displayedDate = 'No due date';
+ }
+ }
+
+ prepSelectedDate() {
+ const datePayload = {};
+ datePayload[this.abilityName] = {};
+ datePayload[this.abilityName].due_date = this.rawSelectedDate;
+ this.datePayload = datePayload;
+ }
+
+ submitSelectedDate(isDropdown) {
+ return $.ajax({
+ type: 'PUT',
+ url: this.issueUpdateURL,
+ data: this.datePayload,
+ dataType: 'json',
+ beforeSend: () => {
+ const selectedDateValue = this.datePayload[this.abilityName].due_date;
+ const displayedDateStyle = this.displayedDate !== 'No due date' ? 'bold' : 'no-value';
+
+ this.$loading.fadeIn();
+
+ if (isDropdown) {
+ this.$dropdown.trigger('loading.gl.dropdown');
+ this.$selectbox.hide();
+ }
+
+ this.$value.css('display', '');
+ this.$valueContent.html(`<span class='${displayedDateStyle}'>${this.displayedDate}</span>`);
+ this.$sidebarValue.html(this.displayedDate);
+
+ return selectedDateValue.length ?
+ $('.js-remove-due-date-holder').removeClass('hidden') :
+ $('.js-remove-due-date-holder').addClass('hidden');
+
+ }
+ }).done((data) => {
+ if (isDropdown) {
+ this.$dropdown.trigger('loaded.gl.dropdown');
+ this.$dropdown.dropdown('toggle');
+ }
+ return this.$loading.fadeOut();
+ });
+ }
+ }
+
+ class DueDateSelectors {
+ constructor() {
+ this.initMilestoneDueDate();
+ this.initIssuableSelect();
+ }
+
+ initMilestoneDueDate() {
+ const $datePicker = $('.datepicker');
+
+ if ($datePicker.length) {
+ const $dueDate = $('#milestone_due_date');
+ $datePicker.datepicker({
+ dateFormat: 'yy-mm-dd',
+ onSelect: (dateText, inst) => {
+ $dueDate.val(dateText);
+ }
+ }).datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', $dueDate.val()));
+ }
+ $('.js-clear-due-date').on('click', (e) => {
+ e.preventDefault();
+ $.datepicker._clearDate($datePicker);
+ });
+ }
+
+ initIssuableSelect() {
+ const $loading = $('.js-issuable-update .due_date').find('.block-loading').hide();
+
+ $('.js-due-date-select').each((i, dropdown) => {
+ const $dropdown = $(dropdown);
+ new DueDateSelect({
+ $dropdown,
+ $loading
+ });
+ });
+ }
+ }
+
+ global.DueDateSelectors = DueDateSelectors;
+
+})(window.gl || (window.gl = {}));
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 0464ebddc11..6f0fa41a43f 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -170,5 +170,5 @@
new LabelsSelect();
new IssuableContext('#{escape_javascript(current_user.to_json(only: [:username, :id, :name]))}');
new Subscription('.subscription')
- new DueDateSelect();
+ new gl.DueDateSelectors();
sidebar = new Sidebar();