Skip to content

Commit

Permalink
Merge pull request #726 from plone/thet-pickadate-defaulttime
Browse files Browse the repository at this point in the history
PickADate default time
  • Loading branch information
vangheem authored Dec 24, 2016
2 parents 07ee4ec + 40cfdb6 commit c490134
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 32 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Incompatibilities:

New:

- PickADate pattern: Add option to automatically set the time when changing the date.
It defaults to set the time to the current time.
[thet]

- Change default sort option in livesearch pattern.
[rodfersou]

Expand Down
65 changes: 62 additions & 3 deletions mockup/patterns/pickadate/pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Options:
* date(object): Date widget options described here. If false is selected date picker wont be shown. ({{selectYears: true, selectMonths: true })
* time(object): Time widget options described here. If false is selected time picker wont be shown. ({})
* autoSetTimeOnDateChange(string): Automatically set the time when a date is set. You can specify an offset with a special syntax - a stringified JSON Array in the form of "[H,M]" will set it to hour:minute. If you prepend an "+" or "-", this will added or subscracted to the current time. It does not go beyond 12:00am. ("+[0,0]").
* separator(string): Separator between date and time if both are enabled.
* (' ')
* classClearName(string): Class name of element that is generated by pattern. ('pattern-pickadate-clear')
Expand Down Expand Up @@ -114,6 +115,7 @@ define([
},
time: {},
timezone: null,
autoSetTimeOnDateChange: '+[0,0]',
classWrapperName: 'pattern-pickadate-wrapper',
classSeparatorName: 'pattern-pickadate-separator',
classDateName: 'pattern-pickadate-date',
Expand All @@ -133,14 +135,66 @@ define([
}
return value;
},
parseTimeOffset: function(timeOffset) {
var op = undefined;
if (timeOffset.indexOf('+') === 0) {
op = '+';
timeOffset = timeOffset.split('+')[1];
} else if (timeOffset.indexOf('-') === 0) {
op = '-';
timeOffset = timeOffset.split('-')[1];
}
try {
timeOffset = JSON.parse(timeOffset);
} catch (e) {
timeOffset = undefined;
}
if (timeOffset === false) {
return false;
} else if (timeOffset === true || Array.isArray(timeOffset) !== true) {
return [0,0];
}

var hours = parseInt(timeOffset[0], 10) || 0,
mins = parseInt(timeOffset[1], 10) || 0;

if (op === '+' || op === '-') {

var offset = new Date(),
curHours = offset.getHours(),
curMins = offset.getMinutes();

if (op === '+') {
hours = curHours + hours;
if (hours > 23) {
hours = 23;
}
mins = curMins + mins;
if (mins > 59) {
mins = 59;
}
} else if (op === '-') {
hours = curHours - hours;
if (hours < 0) {
hours = 0;
}
mins = curMins - mins;
if (mins < 0) {
mins = 0;
}
}
}
return [hours,mins];
},
init: function() {
var self = this,
value = self.$el.val().split(' '),
dateValue = value[0] || '',
timeValue = value[1] || '';
value = self.$el.val().split(' '),
dateValue = value[0] || '',
timeValue = value[1] || '';

self.options.date = self.isFalse(self.options.date);
self.options.time = self.isFalse(self.options.time);
self.options.autoSetTimeOnDateChange = self.parseTimeOffset(self.options.autoSetTimeOnDateChange);

if (self.options.date === false) {
timeValue = value[0];
Expand Down Expand Up @@ -168,6 +222,11 @@ define([
self.$time.attr('data-value') !== '') {
self.updateValue.call(self);
}
if (self.options.autoSetTimeOnDateChange !== false && self.$time) {
if (! self.$time.pickatime('picker').get('select')) {
self.$time.pickatime('picker').set('select', self.options.autoSetTimeOnDateChange);
}
}
}
if (e.hasOwnProperty('clear')) {
self.$el.val('');
Expand Down
174 changes: 145 additions & 29 deletions mockup/tests/pattern-pickadate-test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/* global define, describe, beforeEach, afterEach, it */
define([
'expect',
'jquery',
'sinon',
'pat-registry',
'mockup-patterns-pickadate',
'mockup-patterns-select2'
], function(expect, $, sinon, registry, PickADate, Select2) {
], function(expect, $, sinon, registry, PickADate) {
'use strict';

window.mocha.setup('bdd');
Expand All @@ -18,8 +19,8 @@ define([
describe('PickADate', function() {

beforeEach(function() {
this.$el = $('<div><input class="pat-pickadate" /></div>');
this.clock = sinon.useFakeTimers();
this.$el = $('<div><input class="pat-pickadate" data-pat-pickadate=\'{"autoSetTimeOnDateChange": "false"}\'/></div>');
this.clock = sinon.useFakeTimers(new Date(2016,12,23,15,30).getTime());
});

afterEach(function() {
Expand All @@ -40,7 +41,7 @@ define([
expect($('.pattern-pickadate-wrapper', this.$el).size()).to.equal(1);

var dateWrapper = $('.pattern-pickadate-date', self.$el).parent(),
timeWrapper = $('.pattern-pickadate-time', self.$el).parent();
timeWrapper = $('.pattern-pickadate-time', self.$el).parent();

// main element is hidden
expect(self.$el.is(':hidden')).to.be.equal(true);
Expand All @@ -61,7 +62,7 @@ define([
var self = this;
registry.scan(self.$el);
var dateWrapper = $('.pattern-pickadate-date', self.$el).parent(),
timeWrapper = $('.pattern-pickadate-time', self.$el).parent();
timeWrapper = $('.pattern-pickadate-time', self.$el).parent();

// we open date picker (calendar)
$('.pattern-pickadate-date', self.$el).click();
Expand All @@ -77,7 +78,7 @@ define([
var self = this;
registry.scan(self.$el);
var dateWrapper = $('.pattern-pickadate-date', self.$el).parent(),
timeWrapper = $('.pattern-pickadate-time', self.$el).parent();
timeWrapper = $('.pattern-pickadate-time', self.$el).parent();

// select some date
$('.pattern-pickadate-date', self.$el).click();
Expand Down Expand Up @@ -375,18 +376,18 @@ define([
describe('PickADate with timezone', function() {
it('has date, time and timezone', function() {
var self = this,
$input = $('.pat-pickadate', self.$el)
.attr('data-pat-pickadate', '{"timezone": {"data": [' +
'{"id":"Europe/Berlin","text":"Europe/Berlin"},' +
'{"id":"Europe/Vienna","text":"Europe/Vienna"}' +
']}}'
$input = $('.pat-pickadate', self.$el)
.attr('data-pat-pickadate', '{"timezone": {"data": [' +
'{"id":"Europe/Berlin","text":"Europe/Berlin"},' +
'{"id":"Europe/Vienna","text":"Europe/Vienna"}]},' +
'"autoSetTimeOnDateChange": "false"}'
);
self.$el.appendTo('body');
registry.scan($input);

// date and time should exist by default
var $timeWrapper = $('.pattern-pickadate-time-wrapper', self.$el),
$dateWrapper = $('.pattern-pickadate-date-wrapper', self.$el);
$dateWrapper = $('.pattern-pickadate-date-wrapper', self.$el);
expect($timeWrapper.size()).to.equal(1);
expect($dateWrapper.size()).to.equal(1);

Expand All @@ -412,10 +413,10 @@ define([

// set date and time and check if value of main element gets timezone
$('.pattern-pickadate-date', self.$el).click();
var $selectedDate = $dateWrapper.find('td > div').first().click();
$dateWrapper.find('td > div').first().click();
expect($input.val()).to.equal('');
$('.pattern-pickadate-time', self.$el).click();
var $selectedTime = $timeWrapper.find('li').first().next().click();
$timeWrapper.find('li').first().next().click();
expect($input.val()).to.equal($('input:last', $dateWrapper).val() + ' ' + $('input:last', $timeWrapper).val() + ' ' + 'Europe/Berlin');

// change timezone to second value and check if value of main element changes
Expand All @@ -426,12 +427,12 @@ define([

it('should take the default timezone when it is set', function() {
var self = this,
$input = $('.pat-pickadate', self.$el)
.attr('data-pat-pickadate', '{"timezone": {"default": "Europe/Vienna", "data": [' +
'{"id":"Europe/Berlin","text":"Europe/Berlin"},' +
'{"id":"Europe/Vienna","text":"Europe/Vienna"},' +
'{"id":"Europe/Madrid","text":"Europe/Madrid"}' +
']}}'
$input = $('.pat-pickadate', self.$el)
.attr('data-pat-pickadate', '{"timezone": {"default": "Europe/Vienna", "data": [' +
'{"id":"Europe/Berlin","text":"Europe/Berlin"},' +
'{"id":"Europe/Vienna","text":"Europe/Vienna"},' +
'{"id":"Europe/Madrid","text":"Europe/Madrid"}' +
']}}'
);
self.$el.appendTo('body');
registry.scan($input);
Expand All @@ -444,11 +445,11 @@ define([

it('should only set the default value when it exists in the list', function() {
var self = this,
$input = $('.pat-pickadate', self.$el)
.attr('data-pat-pickadate', '{"timezone": {"default": "Europe/Madrid", "data": [' +
'{"id":"Europe/Berlin","text":"Europe/Berlin"},' +
'{"id":"Europe/Vienna","text":"Europe/Vienna"}' +
']}}'
$input = $('.pat-pickadate', self.$el)
.attr('data-pat-pickadate', '{"timezone": {"default": "Europe/Madrid", "data": [' +
'{"id":"Europe/Berlin","text":"Europe/Berlin"},' +
'{"id":"Europe/Vienna","text":"Europe/Vienna"}' +
']}}'
);
self.$el.appendTo('body');
registry.scan($input, ['pickadate']);
Expand All @@ -461,10 +462,10 @@ define([

it('should write to default and disable the dropdown field if only one value exists', function() {
var self = this,
$input = $('.pat-pickadate', self.$el)
.attr('data-pat-pickadate', '{"timezone": {"data": [' +
'{"id":"Europe/Berlin","text":"Europe/Berlin"}' +
']}}'
$input = $('.pat-pickadate', self.$el)
.attr('data-pat-pickadate', '{"timezone": {"data": [' +
'{"id":"Europe/Berlin","text":"Europe/Berlin"}' +
']}}'
);
self.$el.appendTo('body');
registry.scan($input, ['pickadate']);
Expand All @@ -478,6 +479,121 @@ define([
expect($('.pattern-pickadate-timezone').data('select2')._enabled).to.equal(false);
expect($('.select2-container-disabled').size()).to.equal(1);
});

});

describe('automatically set the time on changing the date', function() {

it('parseTimeOffset works as expected', function() {

var pickadate = new PickADate(this.$el, {});

// test false/true
expect(pickadate.parseTimeOffset('false')).to.be.equal(false);
expect(pickadate.parseTimeOffset('true')).to.eql([0,0]);

// test setting straight to time
expect(pickadate.parseTimeOffset('[12, 34]')).to.eql([12,34]);

// test adding / substracting
expect(pickadate.parseTimeOffset('+[1, 10]')).to.eql([16,40]);
expect(pickadate.parseTimeOffset('-[1, 10]')).to.eql([14,20]);

// Test not exceeding dat/hour boundaries
expect(pickadate.parseTimeOffset('+[10, 10]')).to.eql([23,40]);
expect(pickadate.parseTimeOffset('-[16, 10]')).to.eql([0,20]);
expect(pickadate.parseTimeOffset('+[1, 40]')).to.eql([16,59]);
expect(pickadate.parseTimeOffset('-[1, 40]')).to.eql([14,0]);
expect(pickadate.parseTimeOffset('+[1000, 1000]')).to.eql([23,59]);
expect(pickadate.parseTimeOffset('-[1000, 1000]')).to.eql([0,0]);

// test complete/partly nonsense
expect(pickadate.parseTimeOffset('blabla')).to.eql([0,0]);
expect(pickadate.parseTimeOffset('[10,20]')).to.eql([10,20]);
expect(pickadate.parseTimeOffset('[10,"aha"]')).to.eql([10,0]);
expect(pickadate.parseTimeOffset('["who", 20]')).to.eql([0,20]);

});

it('sets the time when date is changed per default', function() {
var $el = $('<div><input class="pat-pickadate" />');
registry.scan($el);

var $dateWrapper = $('.pattern-pickadate-date', $el).parent();

// set date and time and check if time is also set
$('.pattern-pickadate-date', $el).click();
var $selectedDate = $dateWrapper.find('td > div').first().click();

// selected date should be saved on date picker element
expect($('.pattern-pickadate-date', $el).attr('data-value')).to.be.equal($selectedDate.attr('data-pick'));

// default time should be available on time picker element.
expect($('.pattern-pickadate-time', $el).attr('data-value')).to.be.equal('15,30');

// pickadate should be have this value set.
expect($('.pat-pickadate', $el).val()).to.contain('15:30');
});

it('sets the time to a specific value when date is changed', function() {
var $el = $('<div><input class="pat-pickadate" data-pat-pickadate=\'{"autoSetTimeOnDateChange": "[12,30]"}\'/>');
registry.scan($el);

var $dateWrapper = $('.pattern-pickadate-date', $el).parent();

// set date and time and check if time is also set
$('.pattern-pickadate-date', $el).click();
var $selectedDate = $dateWrapper.find('td > div').first().click();

// selected date should be saved on date picker element
expect($('.pattern-pickadate-date', $el).attr('data-value')).to.be.equal($selectedDate.attr('data-pick'));

// default time should be available on time picker element.
expect($('.pattern-pickadate-time', $el).attr('data-value')).to.be.equal('12,30');

// pickadate should be have this value set.
expect($('.pat-pickadate', $el).val()).to.contain('12:30');
});

it('sets the time to a positive offset of the current time when date is changed', function() {
var $el = $('<div><input class="pat-pickadate" data-pat-pickadate=\'{"autoSetTimeOnDateChange": "+[1,0]"}\'/>');
registry.scan($el);

var $dateWrapper = $('.pattern-pickadate-date', $el).parent();

// set date and time and check if time is also set
$('.pattern-pickadate-date', $el).click();
var $selectedDate = $dateWrapper.find('td > div').first().click();

// selected date should be saved on date picker element
expect($('.pattern-pickadate-date', $el).attr('data-value')).to.be.equal($selectedDate.attr('data-pick'));

// default time should be available on time picker element.
expect($('.pattern-pickadate-time', $el).attr('data-value')).to.be.equal('16,30');

// pickadate should be have this value set.
expect($('.pat-pickadate', $el).val()).to.contain('16:30');
});

it('sets the time to a negative offset of the current time when date is changed', function() {
var $el = $('<div><input class="pat-pickadate" data-pat-pickadate=\'{"autoSetTimeOnDateChange": "-[1,0]"}\'/>');
registry.scan($el);

var $dateWrapper = $('.pattern-pickadate-date', $el).parent();

// set date and time and check if time is also set
$('.pattern-pickadate-date', $el).click();
var $selectedDate = $dateWrapper.find('td > div').first().click();

// selected date should be saved on date picker element
expect($('.pattern-pickadate-date', $el).attr('data-value')).to.be.equal($selectedDate.attr('data-pick'));

// default time should be available on time picker element.
expect($('.pattern-pickadate-time', $el).attr('data-value')).to.be.equal('14,30');

// pickadate should be have this value set.
expect($('.pat-pickadate', $el).val()).to.contain('14:30');
});

});

Expand Down

0 comments on commit c490134

Please sign in to comment.