Commit 9d62fdfa authored by Jacob Schatz's avatar Jacob Schatz

Merge branch 'remove-jquery-ui-datepicker' into 'master'

Removed jQuery UI datepicker

See merge request !8421
parents 882027bd 12cc9a53
...@@ -10,7 +10,6 @@ function requireAll(context) { return context.keys().map(context); } ...@@ -10,7 +10,6 @@ function requireAll(context) { return context.keys().map(context); }
window.$ = window.jQuery = require('jquery'); window.$ = window.jQuery = require('jquery');
require('jquery-ui/ui/autocomplete'); require('jquery-ui/ui/autocomplete');
require('jquery-ui/ui/datepicker');
require('jquery-ui/ui/draggable'); require('jquery-ui/ui/draggable');
require('jquery-ui/ui/effect-highlight'); require('jquery-ui/ui/effect-highlight');
require('jquery-ui/ui/sortable'); require('jquery-ui/ui/sortable');
...@@ -35,6 +34,7 @@ require('bootstrap/js/transition'); ...@@ -35,6 +34,7 @@ require('bootstrap/js/transition');
require('bootstrap/js/tooltip'); require('bootstrap/js/tooltip');
require('bootstrap/js/popover'); require('bootstrap/js/popover');
require('select2/select2.js'); require('select2/select2.js');
window.Pikaday = require('pikaday');
window._ = require('underscore'); window._ = require('underscore');
window.Dropzone = require('dropzone'); window.Dropzone = require('dropzone');
window.Sortable = require('vendor/Sortable'); window.Sortable = require('vendor/Sortable');
......
/* global Vue */ /* global Vue */
/* global dateFormat */
Vue.filter('due-date', (value) => { Vue.filter('due-date', (value) => {
const date = new Date(value); const date = new Date(value);
return $.datepicker.formatDate('M d, yy', date); return dateFormat(date, 'mmm d, yyyy');
}); });
...@@ -97,6 +97,7 @@ const ShortcutsBlob = require('./shortcuts_blob'); ...@@ -97,6 +97,7 @@ const ShortcutsBlob = require('./shortcuts_blob');
break; break;
case 'projects:milestones:new': case 'projects:milestones:new':
case 'projects:milestones:edit': case 'projects:milestones:edit':
case 'projects:milestones:update':
new ZenMode(); new ZenMode();
new gl.DueDateSelectors(); new gl.DueDateSelectors();
new gl.GLForm($('.milestone-form')); new gl.GLForm($('.milestone-form'));
......
/* eslint-disable wrap-iife, func-names, space-before-function-paren, comma-dangle, prefer-template, consistent-return, class-methods-use-this, arrow-body-style, no-unused-vars, no-underscore-dangle, no-new, max-len, no-sequences, no-unused-expressions, no-param-reassign */ /* eslint-disable wrap-iife, func-names, space-before-function-paren, comma-dangle, prefer-template, consistent-return, class-methods-use-this, arrow-body-style, no-unused-vars, no-underscore-dangle, no-new, max-len, no-sequences, no-unused-expressions, no-param-reassign */
/* global dateFormat */
/* global Pikaday */
(function(global) { (function(global) {
class DueDateSelect { class DueDateSelect {
...@@ -25,11 +27,14 @@ ...@@ -25,11 +27,14 @@
this.initGlDropdown(); this.initGlDropdown();
this.initRemoveDueDate(); this.initRemoveDueDate();
this.initDatePicker(); this.initDatePicker();
this.initStopPropagation();
} }
initGlDropdown() { initGlDropdown() {
this.$dropdown.glDropdown({ this.$dropdown.glDropdown({
opened: () => {
const calendar = this.$datePicker.data('pikaday');
calendar.show();
},
hidden: () => { hidden: () => {
this.$selectbox.hide(); this.$selectbox.hide();
this.$value.css('display', ''); this.$value.css('display', '');
...@@ -38,25 +43,37 @@ ...@@ -38,25 +43,37 @@
} }
initDatePicker() { initDatePicker() {
this.$datePicker.datepicker({ const $dueDateInput = $(`input[name='${this.fieldName}']`);
dateFormat: 'yy-mm-dd',
defaultDate: $("input[name='" + this.fieldName + "']").val(), const calendar = new Pikaday({
altField: "input[name='" + this.fieldName + "']", field: $dueDateInput.get(0),
onSelect: () => { theme: 'gitlab-theme',
format: 'YYYY-MM-DD',
onSelect: (dateText) => {
const formattedDate = dateFormat(new Date(dateText), 'yyyy-mm-dd');
$dueDateInput.val(formattedDate);
if (this.$dropdown.hasClass('js-issue-boards-due-date')) { if (this.$dropdown.hasClass('js-issue-boards-due-date')) {
gl.issueBoards.BoardsStore.detail.issue.dueDate = $(`input[name='${this.fieldName}']`).val(); gl.issueBoards.BoardsStore.detail.issue.dueDate = $dueDateInput.val();
this.updateIssueBoardIssue(); this.updateIssueBoardIssue();
} else { } else {
return this.saveDueDate(true); this.saveDueDate(true);
} }
} }
}); });
this.$datePicker.append(calendar.el);
this.$datePicker.data('pikaday', calendar);
} }
initRemoveDueDate() { initRemoveDueDate() {
this.$block.on('click', '.js-remove-due-date', (e) => { this.$block.on('click', '.js-remove-due-date', (e) => {
const calendar = this.$datePicker.data('pikaday');
e.preventDefault(); e.preventDefault();
calendar.setDate(null);
if (this.$dropdown.hasClass('js-issue-boards-due-date')) { if (this.$dropdown.hasClass('js-issue-boards-due-date')) {
gl.issueBoards.BoardsStore.detail.issue.dueDate = ''; gl.issueBoards.BoardsStore.detail.issue.dueDate = '';
this.updateIssueBoardIssue(); this.updateIssueBoardIssue();
...@@ -67,12 +84,6 @@ ...@@ -67,12 +84,6 @@
}); });
} }
initStopPropagation() {
$(document).off('click', '.ui-datepicker-header a').on('click', '.ui-datepicker-header a', (e) => {
return e.stopImmediatePropagation();
});
}
saveDueDate(isDropdown) { saveDueDate(isDropdown) {
this.parseSelectedDate(); this.parseSelectedDate();
this.prepSelectedDate(); this.prepSelectedDate();
...@@ -86,7 +97,7 @@ ...@@ -86,7 +97,7 @@
// Construct Date object manually to avoid buggy dateString support within Date constructor // Construct Date object manually to avoid buggy dateString support within Date constructor
const dateArray = this.rawSelectedDate.split('-').map(v => parseInt(v, 10)); const dateArray = this.rawSelectedDate.split('-').map(v => parseInt(v, 10));
const dateObj = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]); const dateObj = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]);
this.displayedDate = $.datepicker.formatDate('M d, yy', dateObj); this.displayedDate = dateFormat(dateObj, 'mmm d, yyyy');
} else { } else {
this.displayedDate = 'No due date'; this.displayedDate = 'No due date';
} }
...@@ -153,14 +164,24 @@ ...@@ -153,14 +164,24 @@
} }
initMilestoneDatePicker() { initMilestoneDatePicker() {
$('.datepicker').datepicker({ $('.datepicker').each(function() {
dateFormat: 'yy-mm-dd' const $datePicker = $(this);
const calendar = new Pikaday({
field: $datePicker.get(0),
theme: 'gitlab-theme',
format: 'YYYY-MM-DD',
onSelect(dateText) {
$datePicker.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
}
});
$datePicker.data('pikaday', calendar);
}); });
$('.js-clear-due-date,.js-clear-start-date').on('click', (e) => { $('.js-clear-due-date,.js-clear-start-date').on('click', (e) => {
e.preventDefault(); e.preventDefault();
const datepicker = $(e.target).siblings('.datepicker'); const calendar = $(e.target).siblings('.datepicker').data('pikaday');
$.datepicker._clearDate(datepicker); calendar.setDate(null);
}); });
} }
......
...@@ -437,7 +437,7 @@ ...@@ -437,7 +437,7 @@
} }
}; };
GitLabDropdown.prototype.opened = function() { GitLabDropdown.prototype.opened = function(e) {
var contentHtml; var contentHtml;
this.resetRows(); this.resetRows();
this.addArrowKeyEvent(); this.addArrowKeyEvent();
...@@ -457,6 +457,10 @@ ...@@ -457,6 +457,10 @@
this.positionMenuAbove(); this.positionMenuAbove();
} }
if (this.options.opened) {
this.options.opened.call(this, e);
}
return this.dropdown.trigger('shown.gl.dropdown'); return this.dropdown.trigger('shown.gl.dropdown');
}; };
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
/* global UsersSelect */ /* global UsersSelect */
/* global ZenMode */ /* global ZenMode */
/* global Autosave */ /* global Autosave */
/* global dateFormat */
/* global Pikaday */
(function() { (function() {
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
...@@ -13,7 +15,7 @@ ...@@ -13,7 +15,7 @@
IssuableForm.prototype.wipRegex = /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i; IssuableForm.prototype.wipRegex = /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i;
function IssuableForm(form) { function IssuableForm(form) {
var $issuableDueDate; var $issuableDueDate, calendar;
this.form = form; this.form = form;
this.toggleWip = bind(this.toggleWip, this); this.toggleWip = bind(this.toggleWip, this);
this.renderWipExplanation = bind(this.renderWipExplanation, this); this.renderWipExplanation = bind(this.renderWipExplanation, this);
...@@ -35,12 +37,14 @@ ...@@ -35,12 +37,14 @@
this.initMoveDropdown(); this.initMoveDropdown();
$issuableDueDate = $('#issuable-due-date'); $issuableDueDate = $('#issuable-due-date');
if ($issuableDueDate.length) { if ($issuableDueDate.length) {
$('.datepicker').datepicker({ calendar = new Pikaday({
dateFormat: 'yy-mm-dd', field: $issuableDueDate.get(0),
onSelect: function(dateText, inst) { theme: 'gitlab-theme',
return $issuableDueDate.val(dateText); format: 'YYYY-MM-DD',
onSelect: function(dateText) {
$issuableDueDate.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
} }
}).datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', $issuableDueDate.val())); });
} }
} }
......
/* global Pikaday */
/* global dateFormat */
(() => { (() => {
// Add datepickers to all `js-access-expiration-date` elements. If those elements are // Add datepickers to all `js-access-expiration-date` elements. If those elements are
// children of an element with the `clearable-input` class, and have a sibling // children of an element with the `clearable-input` class, and have a sibling
...@@ -11,21 +13,34 @@ ...@@ -11,21 +13,34 @@
} }
const inputs = $(selector); const inputs = $(selector);
inputs.datepicker({ inputs.each((i, el) => {
dateFormat: 'yy-mm-dd', const $input = $(el);
minDate: 1,
onSelect: function onSelect() { const calendar = new Pikaday({
$(this).trigger('change'); field: $input.get(0),
toggleClearInput.call(this); theme: 'gitlab-theme',
format: 'YYYY-MM-DD',
minDate: new Date(),
onSelect(dateText) {
$input.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
$input.trigger('change');
toggleClearInput.call($input);
}, },
}); });
$input.data('pikaday', calendar);
});
inputs.next('.js-clear-input').on('click', function clicked(event) { inputs.next('.js-clear-input').on('click', function clicked(event) {
event.preventDefault(); event.preventDefault();
const input = $(this).closest('.clearable-input').find(selector); const input = $(this).closest('.clearable-input').find(selector);
input.datepicker('setDate', null) const calendar = input.data('pikaday');
.trigger('change');
calendar.setDate(null);
input.trigger('change');
toggleClearInput.call(input); toggleClearInput.call(input);
}); });
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
* This is a manifest file that'll automatically include all the stylesheets available in this directory * This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope. * the top of the compiled file, but it's generally better to create a new file per style scope.
*= require jquery-ui/datepicker
*= require jquery-ui/autocomplete *= require jquery-ui/autocomplete
*= require jquery.atwho *= require jquery.atwho
*= require select2 *= require select2
...@@ -19,6 +18,8 @@ ...@@ -19,6 +18,8 @@
* directory. * directory.
*/ */
@import "../../../node_modules/pikaday/scss/pikaday";
/* /*
* GitLab UI framework * GitLab UI framework
*/ */
......
...@@ -43,3 +43,56 @@ ...@@ -43,3 +43,56 @@
float: right; float: right;
font-size: 12px; font-size: 12px;
} }
.pika-single.gitlab-theme {
.pika-label {
color: $gl-text-color-secondary;
font-size: 14px;
font-weight: normal;
}
th {
padding: 2px 0;
color: $note-disabled-comment-color;
font-weight: normal;
text-transform: lowercase;
border-top: 1px solid $calendar-border-color;
}
abbr {
cursor: default;
}
td {
border: 1px solid $calendar-border-color;
&:first-child {
border-left: 0;
}
&:last-child {
border-right: 0;
}
}
.pika-day {
border-radius: 0;
background-color: $white-light;
text-align: center;
}
.is-today {
.pika-day {
color: inherit;
font-weight: normal;
}
}
.is-selected .pika-day,
.pika-day:hover,
.is-today .pika-day:hover {
background: $gl-primary;
color: $white-light;
box-shadow: none;
}
}
...@@ -502,119 +502,16 @@ ...@@ -502,119 +502,16 @@
max-height: 230px; max-height: 230px;
} }
.ui-widget { .pika-single {
table { position: relative!important;
margin: 0; top: 0!important;
}
&.ui-datepicker-inline {
padding: 0 10px;
border: 0;
width: 100%;
}
.ui-datepicker-header {
padding: 0 8px 10px;
border: 0;
.ui-icon {
background: none;
font-size: 20px;
text-indent: 0;
&::before {
display: block;
position: relative;
top: -2px;
color: $dropdown-title-btn-color;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
}
.ui-datepicker-calendar {
.ui-state-hover,
.ui-state-active {
color: $white-light;
border: 0;
}
}
.ui-datepicker-prev,
.ui-datepicker-next {
top: 0;
height: 15px;
cursor: pointer;
&:hover {
background-color: transparent;
border: 0;
.ui-icon::before {
color: $md-link-color;
}
}
}
.ui-datepicker-prev {
left: 0;
.ui-icon::before {
content: '\f104';
text-align: left;
}
}
.ui-datepicker-next {
right: 0;
.ui-icon::before {
content: '\f105';
text-align: right;
}
}
td {
padding: 0;
border: 1px solid $calendar-border-color;
&:first-child {
border-left: 0;
}
&:last-child {
border-right: 0;
}
a {
line-height: 17px;
border: 0; border: 0;
border-radius: 0; box-shadow: none;
}
} }
.ui-datepicker-title { .pika-lendar {
color: $gl-text-color; margin-top: -5px;
font-size: 14px; margin-bottom: 0;
line-height: 1;
font-weight: normal;
}
}
th {
padding: 2px 0;
color: $note-disabled-comment-color;
font-weight: normal;
text-transform: lowercase;
border-top: 1px solid $calendar-border-color;
}
.ui-datepicker-unselectable {
background-color: $gray-light;
} }
} }
......
...@@ -2,42 +2,6 @@ ...@@ -2,42 +2,6 @@
font-family: $regular_font; font-family: $regular_font;
font-size: $font-size-base; font-size: $font-size-base;
&.ui-datepicker,
&.ui-datepicker-inline {
border: 1px solid $jq-ui-border;
padding: 10px;
width: 270px;
.ui-datepicker-header {
background: $white-light;
border-color: $jq-ui-border;
.ui-datepicker-prev,
.ui-datepicker-next {
top: 4px;
}
.ui-datepicker-prev {
left: 2px;
}
.ui-datepicker-next {
right: 2px;
}
.ui-state-hover {
background: transparent;
border: 0;
cursor: pointer;
}
}
.ui-datepicker-calendar td a {
padding: 5px;
text-align: center;
}
}
&.ui-autocomplete { &.ui-autocomplete {
border-color: $jq-ui-border; border-color: $jq-ui-border;
padding: 0; padding: 0;
...@@ -59,14 +23,4 @@ ...@@ -59,14 +23,4 @@
border: 0; border: 0;
background: transparent; background: transparent;
} }
.ui-datepicker-calendar {
.ui-state-active,
.ui-state-hover,
.ui-state-focus {
border: 1px solid $gl-primary;
background: $gl-primary;
color: $white-light;
}
}
} }
...@@ -201,10 +201,6 @@ ...@@ -201,10 +201,6 @@
color: $note-disabled-comment-color; color: $note-disabled-comment-color;
} }
.datepicker.personal-access-tokens-expires-at .ui-state-disabled span {
text-align: center;
}
.created-personal-access-token-container { .created-personal-access-token-container {
#created-personal-access-token { #created-personal-access-token {
width: 90%; width: 90%;
......
...@@ -85,11 +85,17 @@ ...@@ -85,11 +85,17 @@
:javascript :javascript
var date = $('#personal_access_token_expires_at').val(); var $dateField = $('#personal_access_token_expires_at');
var date = $dateField.val();
var datepicker = $(".datepicker").datepicker({
dateFormat: "yy-mm-dd", new Pikaday({
minDate: 0 field: $dateField.get(0),
theme: 'gitlab-theme',
format: 'YYYY-MM-DD',
minDate: new Date(),
onSelect: function(dateText) {
$dateField.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
}
}); });
$("#created-personal-access-token").click(function() { $("#created-personal-access-token").click(function() {
......
...@@ -10,6 +10,3 @@ ...@@ -10,6 +10,3 @@
.col-sm-10 .col-sm-10
= f.text_field :due_date, class: "datepicker form-control", placeholder: "Select due date" = f.text_field :due_date, class: "datepicker form-control", placeholder: "Select due date"
%a.inline.prepend-top-5.js-clear-due-date{ href: "#" } Clear due date %a.inline.prepend-top-5.js-clear-due-date{ href: "#" } Clear due date
:javascript
new gl.DueDateSelectors();
---
title: Replaced jQuery UI datepicker
merge_request:
author:
...@@ -241,7 +241,7 @@ describe 'Issue Boards', feature: true, js: true do ...@@ -241,7 +241,7 @@ describe 'Issue Boards', feature: true, js: true do
page.within('.due_date') do page.within('.due_date') do
click_link 'Edit' click_link 'Edit'
click_link Date.today.day click_button Date.today.day
wait_for_vue_resource wait_for_vue_resource
......
...@@ -78,8 +78,8 @@ describe 'Issues', feature: true do ...@@ -78,8 +78,8 @@ describe 'Issues', feature: true do
fill_in 'issue_description', with: 'bug description' fill_in 'issue_description', with: 'bug description'
find('#issuable-due-date').click find('#issuable-due-date').click
page.within '.ui-datepicker' do page.within '.pika-single' do
click_link date.day click_button date.day
end end
expect(find('#issuable-due-date').value).to eq date.to_s expect(find('#issuable-due-date').value).to eq date.to_s
...@@ -110,8 +110,8 @@ describe 'Issues', feature: true do ...@@ -110,8 +110,8 @@ describe 'Issues', feature: true do
fill_in 'issue_description', with: 'bug description' fill_in 'issue_description', with: 'bug description'
find('#issuable-due-date').click find('#issuable-due-date').click
page.within '.ui-datepicker' do page.within '.pika-single' do
click_link date.day click_button date.day
end end
expect(find('#issuable-due-date').value).to eq date.to_s expect(find('#issuable-due-date').value).to eq date.to_s
...@@ -624,8 +624,8 @@ describe 'Issues', feature: true do ...@@ -624,8 +624,8 @@ describe 'Issues', feature: true do
page.within '.due_date' do page.within '.due_date' do
click_link 'Edit' click_link 'Edit'
page.within '.ui-datepicker-calendar' do page.within '.pika-single' do
click_link date.day click_button date.day
end end
wait_for_ajax wait_for_ajax
...@@ -635,11 +635,13 @@ describe 'Issues', feature: true do ...@@ -635,11 +635,13 @@ describe 'Issues', feature: true do
end end
it 'removes due date from issue' do it 'removes due date from issue' do
date = Date.today.at_beginning_of_month + 2.days
page.within '.due_date' do page.within '.due_date' do
click_link 'Edit' click_link 'Edit'
page.within '.ui-datepicker-calendar' do page.within '.pika-single' do
first('.ui-state-default').click click_button date.day
end end
wait_for_ajax wait_for_ajax
......
...@@ -34,7 +34,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do ...@@ -34,7 +34,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
# Set date to 1st of next month # Set date to 1st of next month
find_field("Expires at").trigger('focus') find_field("Expires at").trigger('focus')
find("a[title='Next']").click find(".pika-next").click
click_on "1" click_on "1"
# Scopes # Scopes
......
...@@ -14,15 +14,16 @@ feature 'Projects > Members > Master adds member with expiration date', feature: ...@@ -14,15 +14,16 @@ feature 'Projects > Members > Master adds member with expiration date', feature:
login_as(master) login_as(master)
end end
scenario 'expiration date is displayed in the members list', js: true do scenario 'expiration date is displayed in the members list' do
travel_to Time.zone.parse('2016-08-06 08:00') do travel_to Time.zone.parse('2016-08-06 08:00') do
visit namespace_project_settings_members_path(project.namespace, project) date = 4.days.from_now
visit namespace_project_project_members_path(project.namespace, project)
page.within '.users-project-form' do page.within '.users-project-form' do
select2(new_member.id, from: '#user_ids', multiple: true) select2(new_member.id, from: '#user_ids', multiple: true)
fill_in 'expires_at', with: '2016-08-10' fill_in 'expires_at', with: date.to_s(:medium)
end
find('.users-project-form').click
click_on 'Add to project' click_on 'Add to project'
end
page.within "#project_member_#{new_member.project_members.first.id}" do page.within "#project_member_#{new_member.project_members.first.id}" do
expect(page).to have_content('Expires in 4 days') expect(page).to have_content('Expires in 4 days')
...@@ -32,11 +33,12 @@ feature 'Projects > Members > Master adds member with expiration date', feature: ...@@ -32,11 +33,12 @@ feature 'Projects > Members > Master adds member with expiration date', feature:
scenario 'change expiration date' do scenario 'change expiration date' do
travel_to Time.zone.parse('2016-08-06 08:00') do travel_to Time.zone.parse('2016-08-06 08:00') do
project.team.add_users([new_member.id], :developer, expires_at: '2016-09-06') date = 3.days.from_now
project.team.add_users([new_member.id], :developer, expires_at: Date.today.to_s(:medium))
visit namespace_project_project_members_path(project.namespace, project) visit namespace_project_project_members_path(project.namespace, project)
page.within "#project_member_#{new_member.project_members.first.id}" do page.within "#project_member_#{new_member.project_members.first.id}" do
find('.js-access-expiration-date').set '2016-08-09' find('.js-access-expiration-date').set date.to_s(:medium)
wait_for_ajax wait_for_ajax
expect(page).to have_content('Expires in 3 days') expect(page).to have_content('Expires in 3 days')
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment