Merge pull request #2533 from jlmitch5/schDatePicker

use bootstrap date picker and fix for locales
This commit is contained in:
jlmitch5
2016-06-21 13:51:47 -04:00
committed by GitHub
8 changed files with 161 additions and 113 deletions

View File

@@ -1,13 +1,13 @@
/*************************************************************************** /***************************************************************************
* angular-scheruler.js * angular-scheruler.js
* *
* Copyright (c) 2014 Ansible, Inc. * Copyright (c) 2014 Ansible, Inc.
* *
* Maintainers: * Maintainers:
* *
* Chris Houseknecht * Chris Houseknecht
* @chouseknecht * @chouseknecht
* chouse@ansible.com * chouse@ansible.com
* *
*/ */
@@ -23,7 +23,7 @@ angular.module('underscore',[])
angular.module('AngularScheduler', ['underscore']) angular.module('AngularScheduler', ['underscore'])
.constant('AngularScheduler.partials', '/lib/') .constant('AngularScheduler.partials', '/lib/')
.constant('AngularScheduler.useTimezone', false) .constant('AngularScheduler.useTimezone', false)
.constant('AngularScheduler.showUTCField', false) .constant('AngularScheduler.showUTCField', false)
@@ -96,6 +96,11 @@ angular.module('AngularScheduler', ['underscore'])
} }
}; };
// change the utc time with the new start date
scope.$watch('schedulerStartDt', function() {
scope.scheduleTimeChange(scope.processSchedulerEndDt);
});
scope.resetError = function(variable) { scope.resetError = function(variable) {
scope[variable] = false; scope[variable] = false;
}; };
@@ -193,24 +198,24 @@ angular.module('AngularScheduler', ['underscore'])
} }
return CreateObject(scope, requireFutureStartTime); return CreateObject(scope, requireFutureStartTime);
}; };
}]) }])
/** /**
Return an AngularScheduler object we can use to get the RRule result from user input, check if Return an AngularScheduler object we can use to get the RRule result from user input, check if
user input is valid, reset the form, etc. All the things we need to access and manipulate the user input is valid, reset the form, etc. All the things we need to access and manipulate the
scheduler widget scheduler widget
*/ */
.factory('CreateObject', ['AngularScheduler.useTimezone', '$filter', 'GetRule', 'Inject', 'InjectDetail', 'SetDefaults', '$timezones', 'SetRule', 'InRange', .factory('CreateObject', ['AngularScheduler.useTimezone', '$filter', 'GetRule', 'Inject', 'InjectDetail', 'SetDefaults', '$timezones', 'SetRule', 'InRange',
function(useTimezone, $filter, GetRule, Inject, InjectDetail, SetDefaults, $timezones, SetRule, InRange) { function(useTimezone, $filter, GetRule, Inject, InjectDetail, SetDefaults, $timezones, SetRule, InRange) {
return function(scope, requireFutureST) { return function(scope, requireFutureST) {
var fn = function() { var fn = function() {
this.scope = scope; this.scope = scope;
this.useTimezone = useTimezone; this.useTimezone = useTimezone;
this.requireFutureStartTime = requireFutureST; this.requireFutureStartTime = requireFutureST;
// Evaluate user intput and build options for passing to rrule // Evaluate user intput and build options for passing to rrule
this.getOptions = function() { this.getOptions = function() {
var options = {}; var options = {};
@@ -223,9 +228,9 @@ angular.module('AngularScheduler', ['underscore'])
if (this.scope.schedulerEnd.value === 'on') { if (this.scope.schedulerEnd.value === 'on') {
options.endDate = scope.schedulerEndDt.replace(/(\d{2})\/(\d{2})\/(\d{4})/, function(match, p1, p2, p3) { options.endDate = scope.schedulerEndDt.replace(/(\d{2})\/(\d{2})\/(\d{4})/, function(match, p1, p2, p3) {
return p3 + '-' + p1 + '-' + p2; return p3 + '-' + p1 + '-' + p2;
}) + 'T' + }) + 'T' +
$filter('schZeroPad')(this.scope.schedulerEndHour,2) + ':' + $filter('schZeroPad')(this.scope.schedulerEndHour,2) + ':' +
$filter('schZeroPad')(this.scope.schedulerEndMinute,2) + ':' + $filter('schZeroPad')(this.scope.schedulerEndMinute,2) + ':' +
$filter('schZeroPad')(this.scope.schedulerEndSecond,2)+ 'Z'; $filter('schZeroPad')(this.scope.schedulerEndSecond,2)+ 'Z';
} }
if (this.scope.schedulerFrequency.value === 'weekly') { if (this.scope.schedulerFrequency.value === 'weekly') {
@@ -264,7 +269,7 @@ angular.module('AngularScheduler', ['underscore'])
this.scope.scheduler_occurrenceCount_error = false; this.scope.scheduler_occurrenceCount_error = false;
this.scope.scheduler_monthDay_error = false; this.scope.scheduler_monthDay_error = false;
this.scope.scheduler_yearlyMonthDay_error = false; this.scope.scheduler_yearlyMonthDay_error = false;
if (this.scope.scheduler_form && this.scope.scheduler_form.schedulerEndDt) { if (this.scope.scheduler_form && this.scope.scheduler_form.schedulerEndDt) {
this.scope.scheduler_form.schedulerEndDt.$setValidity('custom-error', true); this.scope.scheduler_form.schedulerEndDt.$setValidity('custom-error', true);
this.scope.scheduler_form.schedulerEndDt.$setPristine(); this.scope.scheduler_form.schedulerEndDt.$setPristine();
@@ -319,7 +324,7 @@ angular.module('AngularScheduler', ['underscore'])
this.scope.scheduler_occurrenceCount_error = true; this.scope.scheduler_occurrenceCount_error = true;
validity = false; validity = false;
} }
if (this.scope.schedulerFrequency.value === 'weekly' && this.scope.weekDays.length === 0) { if (this.scope.schedulerFrequency.value === 'weekly' && this.scope.weekDays.length === 0) {
this.scope.scheduler_weekDays_error = true; this.scope.scheduler_weekDays_error = true;
validity = false; validity = false;
@@ -367,7 +372,7 @@ angular.module('AngularScheduler', ['underscore'])
$filter('schZeroPad')(now.getHours(),2) + ':' + $filter('schZeroPad')(now.getHours(),2) + ':' +
$filter('schZeroPad')(now.getMinutes(),2) + ':' + $filter('schZeroPad')(now.getMinutes(),2) + ':' +
$filter('schZeroPad')(now.getSeconds(),2) + '.000Z'; $filter('schZeroPad')(now.getSeconds(),2) + '.000Z';
adjNow = $timezones.toUTC(dateStr, this.scope.schedulerTimeZone.name); //Adjust to the selected TZ adjNow = $timezones.toUTC(dateStr, this.scope.schedulerTimeZone.name); //Adjust to the selected TZ
timeNow = adjNow.getTime(); timeNow = adjNow.getTime();
} }
else { else {
@@ -434,7 +439,7 @@ angular.module('AngularScheduler', ['underscore'])
this.scope.schedulerName = name; this.scope.schedulerName = name;
}; };
// Read in the HTML partial, compile and inject it into the DOM. // Read in the HTML partial, compile and inject it into the DOM.
// Pass in the target element's id attribute value or an angular.element() // Pass in the target element's id attribute value or an angular.element()
// object. // object.
this.inject = function(element, showButtons) { this.inject = function(element, showButtons) {
@@ -491,7 +496,7 @@ angular.module('AngularScheduler', ['underscore'])
.factory('Inject', ['AngularScheduler.partials', '$compile', '$http', '$log', function(scheduler_partial, $compile, $http) { .factory('Inject', ['AngularScheduler.partials', '$compile', '$http', '$log', function(scheduler_partial, $compile, $http) {
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
target = params.target, target = params.target,
buttons = params.buttons; buttons = params.buttons;
@@ -521,7 +526,7 @@ angular.module('AngularScheduler', ['underscore'])
.factory('InjectDetail', ['AngularScheduler.partials', '$compile', '$http', '$log', function(scheduler_partial, $compile, $http) { .factory('InjectDetail', ['AngularScheduler.partials', '$compile', '$http', '$log', function(scheduler_partial, $compile, $http) {
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
target = params.target, target = params.target,
showRRule = params.showRRule; showRRule = params.showRRule;
@@ -551,11 +556,11 @@ angular.module('AngularScheduler', ['underscore'])
.factory('GetRule', ['$log', function($log) { .factory('GetRule', ['$log', function($log) {
return function(params) { return function(params) {
// Convert user inputs to an rrule. Returns rrule object using https://github.com/jkbr/rrule // Convert user inputs to an rrule. Returns rrule object using https://github.com/jkbr/rrule
// **list of 'valid values' found below in LoadLookupValues // **list of 'valid values' found below in LoadLookupValues
var startDate = params.startDate, // date object or string in yyyy-MM-ddTHH:mm:ss.sssZ format var startDate = params.startDate, // date object or string in yyyy-MM-ddTHH:mm:ss.sssZ format
frequency = params.frequency, // string, optional, valid value from frequencyOptions frequency = params.frequency, // string, optional, valid value from frequencyOptions
interval = params.interval, // integer, optional interval = params.interval, // integer, optional
occurrenceCount = params.occurrenceCount, //integer, optional occurrenceCount = params.occurrenceCount, //integer, optional
endDate = params.endDate, // date object or string in yyyy-MM-dd format, optional endDate = params.endDate, // date object or string in yyyy-MM-dd format, optional
// ignored if occurrenceCount provided // ignored if occurrenceCount provided
@@ -564,7 +569,7 @@ angular.module('AngularScheduler', ['underscore'])
weekDays = params.weekDays, // integer, optional, valid value from weekdays weekDays = params.weekDays, // integer, optional, valid value from weekdays
setOccurrence = params.setOccurrence, // integer, optional, valid value from occurrences setOccurrence = params.setOccurrence, // integer, optional, valid value from occurrences
options = {}, i; options = {}, i;
if (angular.isDate(startDate)) { if (angular.isDate(startDate)) {
options.dtstart = startDate; options.dtstart = startDate;
} }
@@ -580,7 +585,7 @@ angular.module('AngularScheduler', ['underscore'])
if (frequency && frequency !== 'none') { if (frequency && frequency !== 'none') {
options.freq = RRule[frequency.toUpperCase()]; options.freq = RRule[frequency.toUpperCase()];
options.interval = interval; options.interval = interval;
if (weekDays && typeof weekDays === 'string') { if (weekDays && typeof weekDays === 'string') {
options.byweekday = RRule[weekDays.toUpperCase()]; options.byweekday = RRule[weekDays.toUpperCase()];
} }
@@ -636,7 +641,7 @@ angular.module('AngularScheduler', ['underscore'])
return function(rule, scope) { return function(rule, scope) {
var set, result = '', i, var set, result = '', i,
setStartDate = false; setStartDate = false;
// Search the set of RRule keys for a particular key, returning its value // Search the set of RRule keys for a particular key, returning its value
function getValue(set, key) { function getValue(set, key) {
var pair = _.find(set, function(x) { var pair = _.find(set, function(x) {
@@ -837,7 +842,7 @@ angular.module('AngularScheduler', ['underscore'])
} }
} }
} }
function isValid() { function isValid() {
// Check what was put into scope vars, and see if anything is // Check what was put into scope vars, and see if anything is
// missing or not quite right. // missing or not quite right.
@@ -923,7 +928,7 @@ angular.module('AngularScheduler', ['underscore'])
.factory('LoadLookupValues', [ function() { .factory('LoadLookupValues', [ function() {
return function(scope) { return function(scope) {
scope.frequencyOptions = [ scope.frequencyOptions = [
{ name: 'None (run once)', value: 'none', intervalLabel: '' }, { name: 'None (run once)', value: 'none', intervalLabel: '' },
{ name: 'Minute', value: 'minutely', intervalLabel: 'minutes' }, { name: 'Minute', value: 'minutely', intervalLabel: 'minutes' },
@@ -978,7 +983,7 @@ angular.module('AngularScheduler', ['underscore'])
}; };
}]) }])
// $filter('schZeroPad')(n, pad) -- or -- {{ n | afZeroPad:pad }} // $filter('schZeroPad')(n, pad) -- or -- {{ n | afZeroPad:pad }}
.filter('schZeroPad', [ function() { .filter('schZeroPad', [ function() {
return function (n, pad) { return function (n, pad) {
@@ -1034,7 +1039,7 @@ angular.module('AngularScheduler', ['underscore'])
}; };
}]) }])
// Custom directives // Custom directives
.directive('schSpinner', ['$filter', function($filter) { .directive('schSpinner', ['$filter', function($filter) {
return { return {
require: 'ngModel', require: 'ngModel',
@@ -1072,7 +1077,7 @@ angular.module('AngularScheduler', ['underscore'])
} }
} }
}); });
$(element).on("click", function () { $(element).on("click", function () {
$(element).select(); $(element).select();
}); });

View File

@@ -42,26 +42,9 @@
(mm/dd/yyyy) (mm/dd/yyyy)
</span> </span>
</label> </label>
<div class="input-group Form-inputGroup"> <div class="input-group Form-inputGroup SchedulerForm-inputGroup--date">
<input type="text" <scheduler-date-picker date="schedulerStartDt">
class="form-control input-sm </scheduler-date-picker>
Form-textInput"
name="schedulerStartDt"
id="schedulerStartDt"
ng-model="schedulerStartDt"
sch-date-picker
placeholder="mm/dd/yyyy"
required
ng-change="scheduleTimeChange()" >
<span class="input-group-btn">
<button
class="btn btn-default btn-sm
Form-inputButton Form-lookupButton"
type="button"
ng-click="showCalendar('schedulerStartDt')">
<i class="fa fa-calendar"></i>
</button>
</span>
</div> </div>
<div class="error" <div class="error"
ng-show="scheduler_form_schedulerStartDt_error" ng-show="scheduler_form_schedulerStartDt_error"
@@ -508,26 +491,9 @@
(mm/dd/yyyy) (mm/dd/yyyy)
</span> </span>
</label> </label>
<div class="input-group Form-inputGroup"> <div class="input-group Form-inputGroup SchedulerForm-inputGroup--date">
<input type="text" <scheduler-date-picker date="$parent.schedulerEndDt">
name="schedulerEndDt" </scheduler-date-picker>
id="schedulerEndDt"
class="form-control input-sm
Form-textInput"
ng-model="$parent.schedulerEndDt"
sch-date-picker
data-min-today="true"
placeholder="mm/dd/yyyy"
ng-change="$parent.resetError('scheduler_endDt_error')">
<span class="input-group-btn">
<button class="btn btn-default btn-sm
Form-inputButton Form-lookupButton"
type="button"
ng-click="showCalendar('schedulerEndDt')"
>
<i class="fa fa-calendar"></i>
</button>
</span>
</div> </div>
<div class="error" <div class="error"
ng-show="$parent.scheduler_endDt_error"> ng-show="$parent.scheduler_endDt_error">

View File

@@ -8,12 +8,14 @@ import controller from './scheduler.controller';
import addController from './schedulerAdd.controller'; import addController from './schedulerAdd.controller';
import editController from './schedulerEdit.controller'; import editController from './schedulerEdit.controller';
import {templateUrl} from '../shared/template-url/template-url.factory'; import {templateUrl} from '../shared/template-url/template-url.factory';
import schedulerDatePicker from './schedulerDatePicker.directive';
export default export default
angular.module('scheduler', []) angular.module('scheduler', [])
.controller('schedulerController', controller) .controller('schedulerController', controller)
.controller('schedulerAddController', addController) .controller('schedulerAddController', addController)
.controller('schedulerEditController', editController) .controller('schedulerEditController', editController)
.directive('schedulerDatePicker', schedulerDatePicker)
.run(['$stateExtender', function($stateExtender) { .run(['$stateExtender', function($stateExtender) {
$stateExtender.addState({ $stateExtender.addState({
name: 'jobTemplateSchedules', name: 'jobTemplateSchedules',

View File

@@ -23,11 +23,7 @@ export default [
ClearScope(); ClearScope();
$scope.schedulerStartDT = 'test';
var base, id, url,parentObject, title; var base, id, url,parentObject, title;
$scope.schedulerStartDT = 'test';
base = $location.path().replace(/^\//, '').split('/')[0]; base = $location.path().replace(/^\//, '').split('/')[0];
if (base === 'management_jobs') { if (base === 'management_jobs') {

View File

@@ -0,0 +1,92 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
/* jshint unused: vars */
export default
[ 'moment',
'templateUrl',
function(moment, templateUrl) {
return {
restrict: 'E',
scope: {
date: '=',
minDate: '=',
autoUpdate: '=?',
inputClass: '&'
},
templateUrl: templateUrl('system-tracking/date-picker/date-picker'),
link: function(scope, element, attrs) {
// We need to make sure this _never_ recurses, which sometimes happens
// with two-way binding.
var mustUpdateValue = true;
scope.autoUpdate = scope.autoUpdate === false ? false : true;
// convert the passed current date into the correct moment locale
scope.$watch('date', function(newValue) {
if (newValue) {
mustUpdateValue = false;
scope.dateValueMoment = moment(newValue, ['MM/DD/YYYY'], moment.locale());
scope.dateValue = scope.dateValueMoment.format('L');
}
}, true);
// as the date picker value changes, convert back to
// the english date to pass back into the scheduler lib
scope.$watch('dateValue', function(newValue) {
scope.dateValueMoment = moment(newValue, ['L'], moment.locale());
scope.date = scope.dateValueMoment.locale('en').format('L');
mustUpdateValue = true;
});
var localeData =
moment.localeData();
var dateFormat = momentFormatToDPFormat(localeData._longDateFormat.L);
var localeKey = momentLocaleToDPLocale(moment.locale());
element.find(".DatePicker").addClass("input-prepend date");
element.find(".DatePicker").find(".DatePicker-icon").addClass("add-on");
$(".date").systemTrackingDP({
autoclose: true,
language: localeKey,
format: dateFormat
});
function momentLocaleToDPLocale(localeKey) {
var parts = localeKey.split('-');
if (parts.length === 2) {
var lastPart = parts[1].toUpperCase();
return [parts[0], lastPart].join('-');
} else {
return localeKey;
}
}
function momentFormatToDPFormat(momentFormat) {
var resultFormat = momentFormat;
function lowerCase(str) {
return str.toLowerCase();
}
resultFormat = resultFormat.replace(/D{1,2}/, lowerCase);
if (/MMM/.test(resultFormat)) {
resultFormat = resultFormat.replace('MMM', 'M');
} else {
resultFormat = resultFormat.replace(/M{1,2}/, 'm');
}
resultFormat = resultFormat.replace(/Y{2,4}/, lowerCase);
return resultFormat;
}
}
};
}
];

View File

@@ -0,0 +1,9 @@
<div class="DatePicker">
<button class="DatePicker-icon"><i class="fa fa-calendar"></i></button>
<input
class="DatePicker-input"
type="text"
readonly
ng-model="dateValue"
ng-class="inputClass()">
</div>

View File

@@ -6,6 +6,18 @@
padding-right: 0px; padding-right: 0px;
} }
.SchedulerForm-inputGroup--date {
width: 100%;
}
#SchedulerFormTarget .DatePicker {
max-height: 31px;
}
#SchedulerFormTarget .DatePicker-icon {
padding-top: 4px;
}
@media (min-width: 901px) { @media (min-width: 901px) {
.SchedulerForm-formGroup { .SchedulerForm-formGroup {
flex: 0 0 auto; flex: 0 0 auto;

View File

@@ -42,26 +42,9 @@
(mm/dd/yyyy) (mm/dd/yyyy)
</span> </span>
</label> </label>
<div class="input-group Form-inputGroup"> <div class="input-group Form-inputGroup SchedulerForm-inputGroup--date">
<input type="text" <scheduler-date-picker date="schedulerStartDt">
class="form-control input-sm </scheduler-date-picker>
Form-textInput"
name="schedulerStartDt"
id="schedulerStartDt"
ng-model="schedulerStartDt"
sch-date-picker
placeholder="mm/dd/yyyy"
required
ng-change="scheduleTimeChange(processSchedulerEndDt)" >
<span class="input-group-btn">
<button
class="btn btn-default btn-sm
Form-inputButton Form-lookupButton"
type="button"
ng-click="showCalendar('schedulerStartDt')">
<i class="fa fa-calendar"></i>
</button>
</span>
</div> </div>
<div class="error" <div class="error"
ng-show="scheduler_form_schedulerStartDt_error" ng-show="scheduler_form_schedulerStartDt_error"
@@ -490,26 +473,9 @@
(mm/dd/yyyy) (mm/dd/yyyy)
</span> </span>
</label> </label>
<div class="input-group Form-inputGroup"> <div class="input-group Form-inputGroup SchedulerForm-inputGroup--date">
<input type="text" <scheduler-date-picker date="$parent.schedulerEndDt">
name="schedulerEndDt" </scheduler-date-picker>
id="schedulerEndDt"
class="form-control input-sm
Form-textInput"
ng-model="$parent.schedulerEndDt"
sch-date-picker
data-min-today="true"
placeholder="mm/dd/yyyy"
ng-change="$parent.resetError('scheduler_endDt_error')">
<span class="input-group-btn">
<button class="btn btn-default btn-sm
Form-inputButton Form-lookupButton"
type="button"
ng-click="showCalendar('schedulerEndDt')"
>
<i class="fa fa-calendar"></i>
</button>
</span>
</div> </div>
<div class="error" <div class="error"
ng-show="$parent.scheduler_endDt_error"> ng-show="$parent.scheduler_endDt_error">