Initial commit
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var _ = require('underscore');
|
||||
var $ = require('jquery');
|
||||
var moment = require('moment');
|
||||
var template = require('./calendar-dropdown.tpl');
|
||||
|
||||
/**
|
||||
* Dropdown for a calendar selector.
|
||||
* Uses the DatePicker plugin internally to render the calendar and view behaviour.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
className: 'Dropdown',
|
||||
|
||||
// defaults, used for
|
||||
options: {
|
||||
flat: true,
|
||||
date: '2008-07-01',
|
||||
current: '2008-07-31',
|
||||
calendars: 1,
|
||||
starts: 1
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
if (!this.model) throw new Error('model is required');
|
||||
this.elder('initialize');
|
||||
this._initDefaults();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(
|
||||
template({
|
||||
initialDateStr: this.model.get('date')
|
||||
})
|
||||
);
|
||||
|
||||
$('body').append(this.el);
|
||||
this._initCalendar(); // must be called after element is added to body!
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initDefaults: function () {
|
||||
var utc = new Date().getTimezoneOffset();
|
||||
var today = moment(new Date()).utcOffset(utc).format('YYYY-MM-DD');
|
||||
this.options.current = today;
|
||||
this.options.date = today;
|
||||
},
|
||||
|
||||
// should not be called until element is located in document
|
||||
_initCalendar: function () {
|
||||
var self = this;
|
||||
this._$calendar().DatePicker(
|
||||
_.extend(this.options, this.model.attributes, {
|
||||
onChange: function (formatted) {
|
||||
self.model.set('date', formatted);
|
||||
self.$('.js-date-str').text(formatted);
|
||||
self.hide();
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
_$calendar: function () {
|
||||
return this.$('.js-calendar');
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._$calendar().DatePickerHide();
|
||||
CoreView.prototype.clean.call(this);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="DatePicker">
|
||||
<div class="js-calendar DatePicker-calendar DatePicker-calendar--simple"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,22 @@
|
||||
<form>
|
||||
<div class="DatePicker-timersFrom">
|
||||
<div class="DatePicker-timersHour">
|
||||
<label class="DatePicker-timersLabel u-upperCase"><%- _t('components.datepicker.hour') %></label>
|
||||
<div data-editors="fromHour"></div>
|
||||
</div>
|
||||
<div class="DatePicker-timersMin">
|
||||
<label class="DatePicker-timersLabel u-upperCase"><%- _t('components.datepicker.min') %></label>
|
||||
<div data-editors="fromMin"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="DatePicker-timersTo">
|
||||
<div class="DatePicker-timersHour">
|
||||
<label class="DatePicker-timersLabel u-upperCase"><%- _t('components.datepicker.hour') %></label>
|
||||
<div data-editors="toHour"></div>
|
||||
</div>
|
||||
<div class="DatePicker-timersMin">
|
||||
<label class="DatePicker-timersLabel u-upperCase"><%- _t('components.datepicker.min') %></label>
|
||||
<div data-editors="toMin"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,14 @@
|
||||
<form class="DatePicker-timers">
|
||||
<div class="DatePicker-timersField u-rSpace--xl">
|
||||
<div class="DatePicker-timersInput" data-fields="fromHour"></div>
|
||||
</div>
|
||||
<div class="DatePicker-timersField u-rSpace--xl">
|
||||
<div class="DatePicker-timersInput" data-fields="fromMin"></div>
|
||||
</div>
|
||||
<div class="DatePicker-timersField DatePicker-timersField--spaced u-rSpace--xl">
|
||||
<div class="DatePicker-timersInput" data-fields="toHour"></div>
|
||||
</div>
|
||||
<div class="DatePicker-timersField">
|
||||
<div class="DatePicker-timersInput" data-fields="toMin"></div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,262 @@
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
var _ = require('underscore');
|
||||
var moment = require('moment');
|
||||
var $ = require('jquery');
|
||||
var Utils = require('builder/helpers/utils');
|
||||
require('builder/components/form-components/index');
|
||||
require('datepicker');
|
||||
var datePickerTemplate = require('./date-picker-range-form.tpl');
|
||||
var template = require('./date-picker-range.tpl');
|
||||
|
||||
var MAX_RANGE = 30;
|
||||
var FOUR_HOURS = { amount: 4, unit: 'hours' };
|
||||
var ONE_DAY = { amount: 1, unit: 'day' };
|
||||
var ONE_WEEK = { amount: 1, unit: 'week' };
|
||||
|
||||
/**
|
||||
* Custom picer for a dates range.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
className: 'DatePicker',
|
||||
|
||||
options: {
|
||||
flat: true,
|
||||
date: ['2008-07-31', '2008-07-31'],
|
||||
current: '2008-07-31',
|
||||
calendars: 2,
|
||||
mode: 'range',
|
||||
starts: 1
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .js-dates': '_toggleCalendar',
|
||||
'click .js-fourHours': function () { this._setPreviousTime(FOUR_HOURS); },
|
||||
'click .js-oneDay': function () { this._setPreviousTime(ONE_DAY); },
|
||||
'click .js-oneWeek': function () { this._setPreviousTime(ONE_WEEK); }
|
||||
},
|
||||
|
||||
initialize: function (opts) {
|
||||
var isDisabled = (opts && opts.disabled) ? opts.disabled : false;
|
||||
|
||||
this.model = new Backbone.Model({
|
||||
fromDate: '',
|
||||
fromHour: 0,
|
||||
fromMin: 0,
|
||||
toDate: '',
|
||||
toHour: 23,
|
||||
toMin: 59,
|
||||
user_timezone: 0, // Explained as GMT+0
|
||||
disabled: isDisabled
|
||||
});
|
||||
|
||||
this.template = opts.template || template;
|
||||
|
||||
this._initBinds();
|
||||
this._setDefaultDate();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var self = this;
|
||||
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
|
||||
this.$el.append(
|
||||
this.template(
|
||||
_.extend(
|
||||
this.model.attributes,
|
||||
{
|
||||
max_days: MAX_RANGE,
|
||||
pad: Utils.pad
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
setTimeout(function () {
|
||||
self._initCalendar();
|
||||
self._hideCalendar();
|
||||
self._initTimers();
|
||||
}, 100);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.model.bind('change', this._setValues, this);
|
||||
this.model.bind('change', this._onValuesChange, this);
|
||||
$(document).bind('click', this._onDocumentClick.bind(this));
|
||||
},
|
||||
|
||||
_destroyBinds: function () {
|
||||
$(document).unbind('click', this._onDocumentClick.bind(this));
|
||||
},
|
||||
|
||||
_formattedDate: function (which) {
|
||||
var text = 'components.datepicker.' + which;
|
||||
return _t(text) + ' ' +
|
||||
'<strong>' +
|
||||
this.model.get(which + 'Date') + ' ' +
|
||||
(Utils.pad(this.model.get(which + 'Hour'), 2) + ':' + Utils.pad(this.model.get(which + 'Min'), 2)) +
|
||||
'</strong>';
|
||||
},
|
||||
|
||||
_setValues: function () {
|
||||
var text = _t('components.datepicker.dates-placeholder');
|
||||
var data = this.model.attributes;
|
||||
|
||||
if (data.fromDate && data.toDate) {
|
||||
var calendarIcon = '<i class="CDB-IconFont CDB-IconFont-calendar DatePicker-datesIcon"></i>';
|
||||
text = this._formattedDate('from') + ' ' + this._formattedDate('to') + calendarIcon;
|
||||
}
|
||||
|
||||
this.$('.DatePicker-dates').html(text);
|
||||
},
|
||||
|
||||
_setDefaultDate: function () {
|
||||
var datesUTC = this.model.get('user_timezone');
|
||||
var today = moment().utc(datesUTC);
|
||||
var previous = moment().utc(datesUTC).subtract((MAX_RANGE - 1), 'days');
|
||||
this.options.date = [previous.format('YYYY-MM-DD'), today.format('YYYY-MM-DD')];
|
||||
this.options.current = today.format('YYYY-MM-DD');
|
||||
this._setModelFromPrevious(previous);
|
||||
},
|
||||
|
||||
_initCalendar: function () {
|
||||
var selector = '.DatePicker-calendar';
|
||||
|
||||
// Can't initialize calendar if not already present in document... avoid errors being thrown
|
||||
if (!document.body.contains(this.$(selector)[0])) return;
|
||||
|
||||
this.calendar = this.$(selector).DatePicker(
|
||||
_.extend(this.options, {
|
||||
onChange: this._onDatesChange.bind(this),
|
||||
onRender: function (d) { // Disable future dates and dates < MAX_RANGE days ago
|
||||
var date = d.valueOf();
|
||||
var now = new Date();
|
||||
|
||||
var thirtyDaysAgo = new Date();
|
||||
thirtyDaysAgo.setDate(now.getDate() - MAX_RANGE);
|
||||
|
||||
return (date < thirtyDaysAgo) || (date > now) ? { disabled: true } : '';
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
_onDatesChange: function (formatted, dates) {
|
||||
// Check if selected dates have more than MAX_RANGE days
|
||||
var start = moment(formatted[0]);
|
||||
var end = moment(formatted[1]);
|
||||
|
||||
if (Math.abs(start.diff(end, 'days')) > MAX_RANGE) {
|
||||
formatted[1] = moment(formatted[0]).add('days', MAX_RANGE).format('YYYY-MM-DD');
|
||||
this.$('.DatePicker-calendar').DatePickerSetDate([formatted[0], formatted[1]]);
|
||||
}
|
||||
|
||||
this.model.set({
|
||||
fromDate: formatted[0],
|
||||
toDate: formatted[1]
|
||||
});
|
||||
},
|
||||
|
||||
_hideCalendar: function (e) {
|
||||
if (e) this.killEvent(e);
|
||||
this.$('.DatePicker-dropdown').hide();
|
||||
},
|
||||
|
||||
_toggleCalendar: function (ev) {
|
||||
if (ev) this.killEvent(ev);
|
||||
this.$('.DatePicker-dropdown').toggle();
|
||||
},
|
||||
|
||||
_setPreviousTime: function (timeSpan) {
|
||||
var previous = moment().utc(0).subtract(timeSpan.amount, timeSpan.unit);
|
||||
this._setModelFromPrevious(previous);
|
||||
this._setDatepickerFromPrevious(previous);
|
||||
this.closeCalendar();
|
||||
},
|
||||
|
||||
_setModelFromPrevious: function (previous) {
|
||||
var today = moment().utc(0);
|
||||
|
||||
this.model.set({
|
||||
fromDate: previous.format('YYYY-MM-DD'),
|
||||
fromHour: parseInt(previous.format('H'), 10),
|
||||
fromMin: parseInt(previous.format('m'), 10),
|
||||
toDate: today.format('YYYY-MM-DD'),
|
||||
toHour: parseInt(today.format('H'), 10),
|
||||
toMin: parseInt(today.format('m'), 10)
|
||||
});
|
||||
},
|
||||
|
||||
_setDatepickerFromPrevious: function (previous) {
|
||||
var today = moment().utc(0);
|
||||
this.$('.DatePicker-calendar').DatePickerSetDate([ previous.format('YYYY-MM-DD'), today.format('YYYY-MM-DD') ]);
|
||||
},
|
||||
|
||||
_initTimers: function () {
|
||||
var generateNumberType = function (min, max) {
|
||||
var title = max === 23
|
||||
? _t('components.datepicker.hour')
|
||||
: _t('components.datepicker.min');
|
||||
return {
|
||||
type: 'Number',
|
||||
title: title,
|
||||
validators: ['required', {
|
||||
type: 'interval',
|
||||
min: min,
|
||||
max: max
|
||||
}]
|
||||
};
|
||||
};
|
||||
|
||||
this.model.schema = {
|
||||
fromHour: generateNumberType(0, 23),
|
||||
fromMin: generateNumberType(0, 59),
|
||||
toHour: generateNumberType(0, 23),
|
||||
toMin: generateNumberType(0, 59)
|
||||
};
|
||||
|
||||
this._datesForm = new Backbone.Form({
|
||||
model: this.model,
|
||||
template: datePickerTemplate
|
||||
});
|
||||
|
||||
this._datesForm.bind('change', function () {
|
||||
this.commit();
|
||||
});
|
||||
this.$('.js-timers').append(this._datesForm.render().el);
|
||||
},
|
||||
|
||||
_onValuesChange: function () {
|
||||
this.trigger('changeDate', this.model.toJSON(), this);
|
||||
},
|
||||
|
||||
getDates: function () {
|
||||
return this.model.toJSON();
|
||||
},
|
||||
|
||||
closeCalendar: function () {
|
||||
this.$('.DatePicker-dropdown').hide();
|
||||
},
|
||||
|
||||
_onDocumentClick: function (e) {
|
||||
var $el = $(e.target);
|
||||
|
||||
if ($el.closest('.DatePicker').length === 0) {
|
||||
this.closeCalendar();
|
||||
}
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._datesForm && this._datesForm.remove();
|
||||
this._destroyBinds();
|
||||
this.closeCalendar();
|
||||
this.$('.DatePicker-calendar').DatePickerHide();
|
||||
CoreView.prototype.clean.call(this);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
<button <% if (disabled) { %>disabled="disabled"<% } %> class="DatePicker-dates js-dates has-icon CDB-Text CDB-Size-medium <%- disabled ? 'is-disabled' : '' %>">
|
||||
<%- _t('components.datepicker.from') %> <strong><%- fromDate %> <%- pad(fromHour,2) %>:<%- pad(fromMin,2) %></strong> <%- _t('components.datepicker.to') %> <strong><%- toDate %> <%- pad(toHour,2) %>:<%- pad(toMin,2) %></strong>
|
||||
<i class="CDB-IconFont CDB-IconFont-calendar DatePicker-datesIcon"></i>
|
||||
</button>
|
||||
<div class="DatePicker-dropdown CDB-Text">
|
||||
<div class="DatePicker-calendar"></div>
|
||||
<div class="DatePicker-timers js-timers"></div>
|
||||
<div class="DatePicker-shortcuts">
|
||||
<p class="DatePicker-shortcutsText">
|
||||
<%- _t('components.datepicker.get-last') %> <button type="button" class="Button--link js-fourHours"><%- _t('components.datepicker.hours-pluralize', { smart_count: 4 }) %></button>,
|
||||
<button type="button" class="Button--link js-oneDay"><%- _t('components.datepicker.days-pluralize', { smart_count: 1 }) %></button> <%- _t('components.datepicker.or') %>
|
||||
<button type="button" class="Button--link js-oneWeek"><%- _t('components.datepicker.weeks-pluralize', { smart_count: 1 }) %></button>
|
||||
</p>
|
||||
<p class="DatePicker-shortcutsText"><%- _t('components.datepicker.gmt-convertion') %></p>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user