commit
3c3ae18c38
@ -0,0 +1,3 @@ |
||||
<div class="date-range-picker"> |
||||
<input type="text" class="start" /><span>-</span><input type="text" class="end" /> |
||||
</div> |
@ -0,0 +1 @@ |
||||
<op-date date-value="displayPaneController.getReadValue().startDate" no-date-text="displayPaneController.getReadValue().noStartDate"></op-date> - <op-date date-value="displayPaneController.getReadValue().dueDate" no-date-text="displayPaneController.getReadValue().noEndDate"></op-date> |
@ -0,0 +1 @@ |
||||
<op-date-range-picker start-date="fieldController.writeValue.startDate" end-date="fieldController.writeValue.dueDate"></op-date-range-picker> |
@ -0,0 +1,226 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
module.exports = function(TimezoneService, ConfigurationService, |
||||
I18n, $timeout) { |
||||
var parseDate = TimezoneService.parseDate, |
||||
formattedDate = function(date) { |
||||
return TimezoneService.parseDate(date).format('L'); |
||||
}, |
||||
formattedISODate = TimezoneService.formattedISODate, |
||||
noStartDate = I18n.t('js.label_no_start_date'), |
||||
noEndDate = I18n.t('js.label_no_due_date'); |
||||
return { |
||||
restrict: 'EA', |
||||
replace: true, |
||||
scope: { |
||||
'startDate': '=', |
||||
'endDate': '=' |
||||
}, |
||||
templateUrl: '/templates/components/inplace_editor/date/date_range_picker.html', |
||||
link: function(scope, element) { |
||||
var startTimerId = 0, |
||||
endTimerId = 0, |
||||
inputStart = element.find('input.start'), |
||||
inputEnd = element.find('input.end'), |
||||
prevStartDate = '', |
||||
prevEndDate = '', |
||||
addClearButton = function (inp) { |
||||
setTimeout(function() { |
||||
var buttonPane = jQuery('.ui-datepicker-buttonpane'); |
||||
|
||||
if(buttonPane.find('.ui-datepicker-clear').length === 0) { |
||||
buttonPane.find('.ui-datepicker-clear').remove(); |
||||
} |
||||
|
||||
jQuery( '<button>', { |
||||
text: 'Clear', |
||||
click: function() { |
||||
inp.val(''); |
||||
inp.change(); |
||||
} |
||||
}) |
||||
.addClass('ui-datepicker-clear ui-state-default ui-priority-primary ui-corner-all') |
||||
.appendTo(buttonPane); |
||||
}, 1); |
||||
}, |
||||
setDate = function(input, date) { |
||||
if(date) { |
||||
input.datepicker('option', 'defaultDate', formattedDate(date)); |
||||
input.datepicker('option', 'setDate', formattedDate(date)); |
||||
input.val(formattedDate(date)); |
||||
} else { |
||||
input.datepicker('option', 'defaultDate', null); |
||||
input.datepicker('option', 'setDate', null); |
||||
input.val(''); |
||||
date = null; |
||||
} |
||||
}; |
||||
|
||||
inputStart.attr('placeholder', noStartDate); |
||||
inputEnd.attr('placeholder', noEndDate); |
||||
|
||||
inputStart.on('change', function() { |
||||
if(inputStart.val().replace(/^\s+|\s+$/g, '') === '') { |
||||
$timeout(function() { |
||||
scope.startDate = null; |
||||
}); |
||||
inputStart.val(''); |
||||
$timeout.cancel(startTimerId); |
||||
return; |
||||
} |
||||
$timeout.cancel(startTimerId); |
||||
startTimerId = $timeout(function() { |
||||
var date = inputStart.val(), |
||||
isValid = TimezoneService.isValid(date, 'DD/MM/YYYY'); |
||||
|
||||
if(isValid){ |
||||
scope.startDate = formattedISODate(date); |
||||
} |
||||
}, 1000); |
||||
}); |
||||
|
||||
inputEnd.on('change', function() { |
||||
if(inputEnd.val().replace(/^\s+|\s+$/g, '') === '') { |
||||
$timeout(function() { |
||||
scope.endDate = null; |
||||
}); |
||||
inputEnd.val(''); |
||||
$timeout.cancel(endTimerId); |
||||
return; |
||||
} |
||||
$timeout.cancel(startTimerId); |
||||
startTimerId = $timeout(function() { |
||||
var date = inputEnd.val(), |
||||
isValid = TimezoneService.isValid(date, 'DD/MM/YYYY'); |
||||
|
||||
if(isValid){ |
||||
scope.endDate = formattedISODate(date); |
||||
} |
||||
}, 1000); |
||||
}); |
||||
|
||||
inputStart.datepicker({ |
||||
firstDay: ConfigurationService.startOfWeek(), |
||||
showWeeks: true, |
||||
changeMonth: true, |
||||
numberOfMonths: 2, |
||||
showButtonPanel: true, |
||||
dateFormat: 'dd/mm/yy', |
||||
inline: true, |
||||
alterOffset: function(offset) { |
||||
var wHeight = jQuery(window).height(), |
||||
dpHeight = jQuery('#ui-datepicker-div').height(), |
||||
inputTop = inputStart.offset().top, |
||||
inputHeight = inputStart.innerHeight(); |
||||
|
||||
if((inputTop + inputHeight + dpHeight) > wHeight) { |
||||
offset.top -= inputHeight - 4; |
||||
} |
||||
return offset; |
||||
}, |
||||
beforeShow: function() { |
||||
addClearButton(inputStart); |
||||
}, |
||||
onChangeMonthYear: function() { |
||||
addClearButton(inputStart); |
||||
}, |
||||
onClose: function(selectedDate) { |
||||
if(!selectedDate || selectedDate === '' || selectedDate === prevStartDate) { |
||||
return; |
||||
} |
||||
var parsedDate = parseDate(selectedDate, 'DD/MM/YYYY'); |
||||
prevStartDate = parsedDate; |
||||
$timeout(function() { |
||||
scope.startDate = formattedISODate(parsedDate); |
||||
}); |
||||
inputEnd.datepicker('option', 'minDate', selectedDate ? selectedDate : null); |
||||
} |
||||
}); |
||||
inputEnd.datepicker({ |
||||
firstDay: ConfigurationService.startOfWeek(), |
||||
showWeeks: true, |
||||
changeMonth: true, |
||||
numberOfMonths: 2, |
||||
dateFormat: 'dd/mm/yy', |
||||
inline: true, |
||||
alterOffset: function(offset) { |
||||
var wHeight = jQuery(window).height(), |
||||
dpHeight = jQuery('#ui-datepicker-div').height(), |
||||
inputTop = inputEnd.offset().top, |
||||
inputHeight = inputEnd.innerHeight(); |
||||
|
||||
if((inputTop + inputHeight + dpHeight) > wHeight) { |
||||
offset.top -= inputHeight - 4; |
||||
} |
||||
return offset; |
||||
}, |
||||
beforeShow: function() { |
||||
addClearButton(inputEnd); |
||||
}, |
||||
onChangeMonthYear: function() { |
||||
addClearButton(inputEnd); |
||||
}, |
||||
onClose: function(selectedDate) { |
||||
if(!selectedDate || selectedDate === '' || selectedDate === prevEndDate) { |
||||
return; |
||||
} |
||||
var parsedDate = parseDate(selectedDate, 'DD/MM/YYYY'); |
||||
prevEndDate = parsedDate; |
||||
$timeout(function() { |
||||
scope.endDate = formattedISODate(parsedDate); |
||||
}); |
||||
inputStart.datepicker('option', 'maxDate', selectedDate ? selectedDate : null); |
||||
} |
||||
}); |
||||
if(scope.endDate) { |
||||
prevEndDate = formattedDate(scope.endDate); |
||||
inputStart.datepicker('option', 'maxDate', formattedDate(scope.endDate)); |
||||
} |
||||
if(scope.startDate) { |
||||
prevStartDate = formattedDate(scope.startDate); |
||||
inputEnd.datepicker('option', 'minDate', formattedDate(scope.startDate)); |
||||
} |
||||
|
||||
setDate(inputStart, scope.startDate); |
||||
setDate(inputEnd, scope.endDate); |
||||
|
||||
angular.element('.work-packages--details-content').scroll(function() { |
||||
inputStart.datepicker('hide'); |
||||
inputEnd.datepicker('hide'); |
||||
angular.element('#ui-datepicker-div').blur(); |
||||
}); |
||||
|
||||
angular.element(window).resize(function() { |
||||
inputStart.datepicker('hide'); |
||||
inputEnd.datepicker('hide'); |
||||
angular.element('#ui-datepicker-div').blur(); |
||||
}); |
||||
} |
||||
}; |
||||
}; |
@ -0,0 +1,3 @@ |
||||
<div class="date-range-picker"> |
||||
<input ng-model="editableStartDate" type="text" class="start" /><span>-</span><input ng-model="editableEndDate" type="text" class="end" /> |
||||
</div> |
@ -0,0 +1 @@ |
||||
<op-date date-value="readValue.startDate" no-date-text="readValue.noStartDate"></op-date> - <op-date date-value="readValue.dueDate" no-date-text="readValue.noEndDate"></op-date> |
@ -0,0 +1 @@ |
||||
<op-date-range-picker start-date="dataObject.startDate" end-date="dataObject.dueDate"></op-date-range-picker> |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,325 @@ |
||||
//-- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
//++
|
||||
|
||||
/* jshint ignore:start */ |
||||
|
||||
var expect = require('../../../spec_helper.js').expect, |
||||
detailsPaneHelper = require('./details-pane-helper.js'); |
||||
|
||||
|
||||
describe('details pane', function() { |
||||
var dateRangePicker; |
||||
describe('date range picker', function() { |
||||
beforeEach(function() { |
||||
detailsPaneHelper.loadPane(819, 'overview'); |
||||
dateRangePicker = element(by.css('.inplace-edit.attribute-date')); |
||||
}); |
||||
|
||||
context('read value', function() { |
||||
it('should be present on page', function(){ |
||||
expect(dateRangePicker.isDisplayed()).to.eventually.be.true; |
||||
}); |
||||
|
||||
it('shows date range', function() { |
||||
expect(dateRangePicker.getText()).to.eventually.equal('02/17/2015\n - \n04/29/2015'); |
||||
}); |
||||
}); |
||||
|
||||
context('write value', function() { |
||||
var startDate, endDate; |
||||
|
||||
beforeEach(function() { |
||||
startDate = dateRangePicker.$('input.start'); |
||||
endDate = dateRangePicker.$('input.end'); |
||||
}); |
||||
|
||||
beforeEach(function() { |
||||
dateRangePicker.$('.inplace-edit--read-value').click(); |
||||
}); |
||||
|
||||
it('opens calendar on click', function() { |
||||
startDate.click(); |
||||
expect($('.ui-datepicker').isDisplayed()).to.eventually.be.true; |
||||
}); |
||||
|
||||
it('shows date range in input', function() { |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('10/23/2014'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/27/2014'); |
||||
}); |
||||
}); |
||||
|
||||
describe('validation', function() { |
||||
it('validates valid start date', function() { |
||||
startDate.clear(); |
||||
startDate.sendKeys('10/24/2014'); |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('10/24/2014'); |
||||
}); |
||||
}); |
||||
|
||||
it('validates valid end date', function() { |
||||
endDate.clear(); |
||||
endDate.sendKeys('11/27/2014'); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('11/27/2014'); |
||||
}); |
||||
}); |
||||
|
||||
it('doesn\'t validate invalid start date', function() { |
||||
startDate.clear(); |
||||
startDate.sendKeys('13/24/2014'); |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('10/23/2014'); |
||||
}); |
||||
}); |
||||
|
||||
it('doesn\'t validate invalid end date', function() { |
||||
endDate.clear(); |
||||
endDate.sendKeys('11/40/2014'); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/27/2014'); |
||||
}); |
||||
}); |
||||
|
||||
it('validates empty start date', function() { |
||||
startDate.clear(); |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('no start date'); |
||||
}); |
||||
}); |
||||
|
||||
it('validates empty end date', function() { |
||||
endDate.clear(); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('no end date'); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('range selection', function() { |
||||
it('changes start date by clicking on calendar', function() { |
||||
startDate.click(); |
||||
element.all(by.css('a.ui-state-default')).filter(function(elem) { |
||||
return elem.getText().then(function(text) { |
||||
return text.indexOf('9') !== -1; |
||||
}); |
||||
}).then(function(filteredElements) { |
||||
filteredElements[0].click(); |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('12/09/2014'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/17/2014'); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
it('changes end date by clicking on calendar', function() { |
||||
endDate.click(); |
||||
element.all(by.css('a.ui-state-default')).filter(function(elem){ |
||||
return elem.getText().then(function(text) { |
||||
return text.indexOf('17') !== -1; |
||||
}); |
||||
}).then(function(filteredElements) { |
||||
filteredElements[0].click(); |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('09/23/2014'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/17/2014'); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('date range picker with start null date', function() { |
||||
beforeEach(function() { |
||||
detailsPaneHelper.loadPane(823, 'overview'); |
||||
dateRangePicker = element(by.css('.inplace-edit.attribute-date')); |
||||
}); |
||||
|
||||
context('read value', function() { |
||||
it('should be present on page', function(){ |
||||
expect(dateRangePicker.isDisplayed()).to.eventually.be.true; |
||||
}); |
||||
|
||||
it('shows date range', function() { |
||||
expect(dateRangePicker.getText()).to.eventually.equal('no start date\n - \n12/27/2014'); |
||||
}); |
||||
}); |
||||
|
||||
context('write value', function() { |
||||
var startDate, endDate; |
||||
|
||||
beforeEach(function() { |
||||
startDate = dateRangePicker.$('input.start'); |
||||
endDate = dateRangePicker.$('input.end'); |
||||
}); |
||||
|
||||
beforeEach(function() { |
||||
dateRangePicker.$('.inplace-edit--read-value').click(); |
||||
}); |
||||
|
||||
it('opens calendar on click', function() { |
||||
startDate.click(); |
||||
expect($('.ui-datepicker').isDisplayed()).to.eventually.be.true; |
||||
}); |
||||
|
||||
it('shows date range in input', function() { |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('no start date'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/27/2014'); |
||||
}); |
||||
}); |
||||
|
||||
describe('range selection', function() { |
||||
it('changes start date by clicking on calendar', function() { |
||||
startDate.click(); |
||||
element.all(by.css('a.ui-state-default')).filter(function(elem){ |
||||
return elem.getText().then(function(text) { |
||||
return text.indexOf('9') !== -1; |
||||
}); |
||||
}).then(function(filteredElements) { |
||||
filteredElements[0].click(); |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('12/09/2014'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/17/2014'); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
it('changes end date by clicking on calendar', function() { |
||||
endDate.click(); |
||||
element.all(by.css('a.ui-state-default')).filter(function(elem){ |
||||
return elem.getText().then(function(text) { |
||||
return text.indexOf('17') !== -1; |
||||
}); |
||||
}).then(function(filteredElements) { |
||||
filteredElements[0].click(); |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('09/23/2014'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/17/2014'); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('date range picker with due null date', function() { |
||||
beforeEach(function() { |
||||
detailsPaneHelper.loadPane(824, 'overview'); |
||||
dateRangePicker = element(by.css('.inplace-edit.attribute-date')); |
||||
}); |
||||
|
||||
context('read value', function() { |
||||
it('should be present on page', function(){ |
||||
expect(dateRangePicker.isDisplayed()).to.eventually.be.true; |
||||
}); |
||||
|
||||
it('shows date range', function() { |
||||
expect(dateRangePicker.getText()).to.eventually.equal('10/23/2014\n - \nno end date'); |
||||
}); |
||||
}); |
||||
|
||||
context('write value', function() { |
||||
var startDate, endDate; |
||||
|
||||
beforeEach(function() { |
||||
startDate = dateRangePicker.$('input.start'); |
||||
endDate = dateRangePicker.$('input.end'); |
||||
}); |
||||
|
||||
beforeEach(function() { |
||||
dateRangePicker.$('.inplace-edit--read-value').click(); |
||||
}); |
||||
|
||||
it('opens calendar on click', function() { |
||||
startDate.click(); |
||||
expect($('.ui-datepicker').isDisplayed()).to.eventually.be.true; |
||||
}); |
||||
|
||||
it('shows date range in input', function() { |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('10/23/2014'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('no end date'); |
||||
}); |
||||
}); |
||||
|
||||
describe('range selection', function() { |
||||
it('changes start date by clicking on calendar', function() { |
||||
startDate.click(); |
||||
element.all(by.css('a.ui-state-default')).filter(function(elem){ |
||||
return elem.getText().then(function(text) { |
||||
return text.indexOf('9') !== -1; |
||||
}); |
||||
}).then(function(filteredElements) { |
||||
filteredElements[0].click(); |
||||
startDate.getText(function(text) { |
||||
expect(text).to.equal('12/09/2014'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/17/2014'); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
it('changes end date by clicking on calendar', function() { |
||||
endDate.click(); |
||||
element.all(by.css('a.ui-state-default')).filter(function(elem){ |
||||
return elem.getText().then(function(text) { |
||||
return text.indexOf('17') !== -1; |
||||
}); |
||||
}).then(function(filteredElements) { |
||||
filteredElements[0].click(); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('09/23/2014'); |
||||
}); |
||||
endDate.getText(function(text) { |
||||
expect(text).to.equal('12/17/2014'); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
/* jshint ignore:end */ |
Loading…
Reference in new issue