From 40cfdb68f246c4f3f09899bb793a5226c0c80b7b Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Fri, 23 Dec 2016 13:59:59 -0600 Subject: [PATCH] PickADate default time PickADate pattern: Add option to automatically set the time when changing the date. It defaults to set the time to the current time. --- CHANGES.rst | 4 + mockup/patterns/pickadate/pattern.js | 65 ++++++++- mockup/tests/pattern-pickadate-test.js | 174 ++++++++++++++++++++----- 3 files changed, 211 insertions(+), 32 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 533a63928..92e9cf96f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -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] diff --git a/mockup/patterns/pickadate/pattern.js b/mockup/patterns/pickadate/pattern.js index 9002452e9..a067c38c6 100644 --- a/mockup/patterns/pickadate/pattern.js +++ b/mockup/patterns/pickadate/pattern.js @@ -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') @@ -114,6 +115,7 @@ define([ }, time: {}, timezone: null, + autoSetTimeOnDateChange: '+[0,0]', classWrapperName: 'pattern-pickadate-wrapper', classSeparatorName: 'pattern-pickadate-separator', classDateName: 'pattern-pickadate-date', @@ -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]; @@ -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(''); diff --git a/mockup/tests/pattern-pickadate-test.js b/mockup/tests/pattern-pickadate-test.js index 557956dba..ce7ce9d15 100644 --- a/mockup/tests/pattern-pickadate-test.js +++ b/mockup/tests/pattern-pickadate-test.js @@ -1,3 +1,4 @@ +/* global define, describe, beforeEach, afterEach, it */ define([ 'expect', 'jquery', @@ -5,7 +6,7 @@ define([ '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'); @@ -18,8 +19,8 @@ define([ describe('PickADate', function() { beforeEach(function() { - this.$el = $('
'); - this.clock = sinon.useFakeTimers(); + this.$el = $('
'); + this.clock = sinon.useFakeTimers(new Date(2016,12,23,15,30).getTime()); }); afterEach(function() { @@ -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); @@ -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(); @@ -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(); @@ -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); @@ -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 @@ -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); @@ -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']); @@ -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']); @@ -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 = $('
'); + 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 = $('
'); + 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 = $('
'); + 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 = $('
'); + 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'); + }); });