Summary Table
| Categories |
Total Count |
| PII |
0 |
| URL |
0 |
| DNS |
0 |
| EKL |
0 |
| IP |
0 |
| PORT |
0 |
| VsID |
0 |
| CF |
0 |
| AI |
0 |
| VPD |
0 |
| PL |
0 |
| Other |
0 |
File Content
define(['angular'], function (angular) {
"use strict";
angular.module('DateControls', [])
.directive('dateControl', function ($timeout, formatter) {
return {
restrict: 'AE',
require: 'ngModel',
scope: {
ngReadonly: '=',
ngRequired: '=',
ngModel : "=",
ngDisabled : "=",
futureAllowed : "=",
fieldId : "@",
label : "@",
labelIcon : "=",
allowedDateRange : "=?",
showDay: "=?",
disableMonthSelection: "=?",
disableDaySelection: "=?",
disableErrors : "=",
additionalScreenreaderText: "@",
notificationStatusLabel : "@"
},
link: function (scope, elem, attrs, ngModelCtrl) {
var minYear,
maxYear,
inputArea = elem.find('input');
if (scope.disableMonthSelection) {
scope.disableDaySelection = true;
}
var validator = function(newVal) {
ngModelCtrl.$setValidity("pattern", isFormattedDate(newVal) || !newVal);
ngModelCtrl.$setValidity("range", isInRange(newVal) || !newVal);
ngModelCtrl.$setValidity("valid", isValidDate(newVal, scope.disableMonthSelection, scope.disableDaySelection) || !newVal);
return newVal;
};
ngModelCtrl.$parsers.push(validator);
ngModelCtrl.$formatters.push(validator);
scope.validAllowedDateRange = {};
var DEFAULT_ERROR_PRIORITY = {
"required" : {
priority: 1
},
"pattern" : {
priority: 2
},
"range" : {
priority: 3
},
"valid" : {
priority: 4
}
};
scope.errorHandling = angular.copy(DEFAULT_ERROR_PRIORITY);
scope.$watch("disableErrors", function(newVal){
if (!newVal) {
angular.element.extend(true, scope.errorHandling, DEFAULT_ERROR_PRIORITY);
} else {
for(var key in scope.errorHandling) {
if(scope.errorHandling.hasOwnProperty(key)) {
scope.errorHandling[key].priority = newVal.indexOf(key) === -1 ? DEFAULT_ERROR_PRIORITY[key].priority : -1;
}
}
}
});
scope.$watch("label", function (labelText) {
if (labelText) {
var label = getLabelText(labelText);
scope.errorHandling.required.message = label + (scope.notificationStatusLabel ? (" is required when " + scope.notificationStatusLabel + " are on.") : " field is required.");
scope.errorHandling.pattern.message = label + (scope.disableMonthSelection ? " must be formatted YYYY." : (scope.disableDaySelection ? " must be formatted MM/YYYY." : " must be formatted MM/DD/YYYY."));
scope.errorHandling.range.message = getInvalidRangeMessage(label);
scope.errorHandling.valid.message = label + " is an invalid date.";
validator(scope.ngModel);
}
});
scope.$watch("allowedDateRange", function () {
var label = getLabelText(scope.label);
scope.validAllowedDateRange.min = getMinAllowedDate();
scope.validAllowedDateRange.max = getMaxAllowedDate();
minYear = new Date(scope.validAllowedDateRange.min).getFullYear().toString();
maxYear = new Date(scope.validAllowedDateRange.max).getFullYear().toString();
scope.errorHandling.range.message = getInvalidRangeMessage(label);
validator(scope.ngModel);
}, true);
var getLabelText = function (text) {
return text.lastIndexOf(":") === text.length - 1 ? text.substr(0, text.length - 1) : text;
};
var getMinAllowedDate = function () {
return scope.allowedDateRange && scope.allowedDateRange.min && !scope.ngReadonly ? scope.allowedDateRange.min : formatter.getFormattedFrontendDate("01/01/1900");
};
var getMaxAllowedDate = function () {
return scope.allowedDateRange && scope.allowedDateRange.max && !scope.ngReadonly ? scope.allowedDateRange.max : (scope.futureAllowed ? formatter.getFormattedFrontendDate("12/31/2099") : formatter.getFormattedFrontendDate(new Date()))
};
var getInvalidRangeMessage = function (label) {
var minDate = getMinAllowedDate().toString(),
maxDate = getMaxAllowedDate().toString();
if (scope.disableMonthSelection) {
minDate = minDate.slice(5, 10);
maxDate = maxDate.slice(5, 10);
} else if (scope.disableDaySelection) {
minDate = minDate.slice(0, 2) + minDate.slice(5, 10);
maxDate = maxDate.slice(0, 2) + maxDate.slice(5, 10);
}
return label + " must be between " + minDate + " and " + maxDate + ".";
};
var tokenizeDateString = function (dateString){
var tokens;
if (dateString !== undefined && dateString !== null){
tokens = ["", "", "", "", ""];
dateString = formatNonStandardDate(dateString, scope.disableMonthSelection, scope.disableDaySelection);
var indexOfFirstBackslash = dateString.indexOf("/"),
indexOfLastBackslash = dateString.lastIndexOf("/"),
start = 0,
end = indexOfFirstBackslash;
if (end === -1) {
end = dateString.length;
} else {
tokens[1] = "/";
}
end = end - start > 2 ? 2 : end - start;
tokens[0] = dateString.substr(start, end);
start = start + end + (tokens[1] === "/" ? 1 : 0);
if (end === -1 || indexOfFirstBackslash === indexOfLastBackslash) {
end = dateString.length;
} else if (indexOfFirstBackslash !== indexOfLastBackslash){
tokens[3] = "/";
end = indexOfLastBackslash;
}
end = end - start > 2 ? 2 : end - start;
tokens[2] = dateString.substr(start, end);
tokens[4] = dateString.substr(start + end + (tokens[3] === "/" || indexOfFirstBackslash === indexOfLastBackslash ? 1 : 0), 4);
}
return tokens || ["", "", "", "", ""];
};
var prevDateTokens = tokenizeDateString(scope.ngModel),
selectionStart = inputArea[0].selectionStart,
selectionEnd = inputArea[0].selectionEnd;
scope.onChange = function() {
if (typeof scope.ngModel === "string") {
if (/^\d{0,2}\/?\d{0,2}\/?\d{0,4}$/.test(scope.ngModel)) {
var formattedDate = "",
dateTokens = tokenizeDateString(scope.ngModel),
prevDate = prevDateTokens.join(""),
previousBackslashCount = prevDate.length - prevDate.replace(/\//g, "").length,
backlashCount = scope.ngModel.length - scope.ngModel.replace(/\//g, "").length;
if(backlashCount < previousBackslashCount && !scope.disableDaySelection && scope.ngModel.substring(prevDate.lastIndexOf("/"), scope.ngModel.length) !== "" || backlashCount > 2){
formattedDate = prevDate;
} else {
formattedDate += getFormattedMonth(dateTokens[0], prevDateTokens[0]);
formattedDate += getFormattedSlash(dateTokens, prevDateTokens, 1);
formattedDate += getFormattedDay(formattedDate, dateTokens[2], prevDateTokens[2], dateTokens[0]);
formattedDate += getFormattedSlash(dateTokens, prevDateTokens, 3);
formattedDate += getFormattedYear(formattedDate, dateTokens[4], prevDateTokens[4]);
}
prevDateTokens = tokenizeDateString(formattedDate);
scope.ngModel = formattedDate;
if(prevDate === formattedDate && formattedDate !== "") {
$timeout(function(){
inputArea[0].setSelectionRange(selectionStart, selectionEnd);
});
}
} else {
scope.ngModel = prevDateTokens.join("");
}
} else {
prevDateTokens = ["", "", "", "", ""];
}
};
scope.onKeydown = function () {
selectionStart = inputArea[0].selectionStart;
selectionEnd = inputArea[0].selectionEnd;
};
scope.getDayOfWeek = function () {
var d = new Date(scope.ngModel),
weekday = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
return weekday[d.getDay()];
};
var isMonthFebruary = function (monthString) {
return parseInt(monthString) === 2;
};
var getFormattedMonth = function (newMonth, previousMonth) {
if (!scope.disableMonthSelection) {
return isMonthValid(newMonth) ? newMonth : previousMonth;
}
return "";
};
var getFormattedDay = function (formattedDate, newDay, previousDay, monthString) {
if (!scope.disableDaySelection && doesDateContainSlash(formattedDate)) {
return isDayValid(newDay, monthString) ? newDay : previousDay;
}
return "";
};
var getFormattedYear = function (formattedDate, newYear, previousYear) {
if (scope.disableMonthSelection || doesDateContainSlash(formattedDate)) {
return isYearValid(newYear) ? newYear : previousYear;
}
return "";
};
var getFormattedSlash = function (dateTokens, prevDateTokens, position) {
if (scope.disableMonthSelection || (position === 1 && scope.disableDaySelection)) {
return "";
}
if (isSlashValidOrEmpty(dateTokens, prevDateTokens, position)) {
return dateTokens[position];
}
return prevDateTokens[position];
};
var isMonthValid = function (monthString) {
return /^(0[1-9]?|1[0-2]?)?$/.test(monthString);
};
var isDayValid = function (dayString, monthString) {
return isMonthFebruary(monthString) ? /^(0[1-9]?|[12][0-9]?)?$/.test(dayString) : /^(0[1-9]?|[12][0-9]?|3[01]?)?$/.test(dayString);
};
var isYearValid = function (yearString) {
var yearLength = yearString.length,
intYear = parseInt(yearString);
return /^(1(9[0-9]{0,2})?|2(0[0-9]{0,2})?)?$/.test(yearString) && (yearLength === 0 ||
(intYear >= parseInt(minYear.substr(0, yearLength)) && intYear <= parseInt(maxYear.substr(0, yearLength))));
};
var doesDateContainSlash = function (date) {
return date.lastIndexOf("/") > -1;
};
var isSlashValidOrEmpty = function (dateTokens, prevDateTokens, position) {
return dateTokens[position] === "" && prevDateTokens[position] === "/" && dateTokens[4] === "" && dateTokens[0].length <= 3
|| dateTokens[position] === "/" && isDayValid(dateTokens[2], dateTokens[0]) && dateTokens[position-1].length === 2;
};
var isInRange = function(dateString) {
dateString = formatNonStandardDate(dateString, scope.disableMonthSelection, scope.disableDaySelection);
var selectedDate = new Date(dateString);
return !isValidDate(dateString, scope.disableMonthSelection, scope.disableDaySelection) ||
isValidDate(dateString, scope.disableMonthSelection, scope.disableDaySelection) &&
selectedDate >= new Date(scope.validAllowedDateRange.min) && selectedDate <= new Date(scope.validAllowedDateRange.max);
};
var isFormattedDate = function(dateString) {
return scope.disableMonthSelection ? /^([0-9]{4})$/.test(dateString) :
(scope.disableDaySelection ?
/^([0-9]{2})\/([0-9]{4})$/.test(dateString) :
/^([0-9]{2})\/([0-9]{2})\/([0-9]{4})$/.test(dateString));
};
},
templateUrl: 'src/ui-components/form/controls/composite/input-date-picker/date-control_template.html'
};
})
.directive('dateRangeControl', function () {
return {
restrict: 'AE',
require: 'ngModel',
scope: {
ngModel: "=",
futureAllowed : "=",
allowedDateRange : "=",
ngRequired : "=",
altTitle : "=",
altLabels: "=",
ngDisabled : "=",
excludeTitle : "=",
bothRequired : "=",
disableDaySelection : "="
},
link : function(scope, elem, attrs, ngModelCtrl) {
var DEFAULT_LABELS = {
main: "Date Range",
start: "Start Date",
end: "End Date"
};
var startAfterEndMsg = '',
bothDatesRequiredMsg = '';
if (scope.altLabels) {
scope.labels = {
main : scope.altLabels.main || DEFAULT_LABELS.main,
start : scope.altLabels.start || DEFAULT_LABELS.start,
end : scope.altLabels.end || DEFAULT_LABELS.end
};
} else {
scope.labels = angular.copy(DEFAULT_LABELS);
}
if (scope.altTitle) {
scope.labels.main = scope.altTitle || scope.labels.main;
}
// Extra logic to make the error messages make sense depending on the labels passed into directive
if (scope.labels.start.toLowerCase().indexOf('date') < 0 && scope.labels.end.toLowerCase().indexOf('date') < 0) {
startAfterEndMsg = scope.labels.start + " date must occur before " + scope.labels.end + " date.";
bothDatesRequiredMsg = "Please provide both a " + scope.labels.start + " date and " + scope.labels.end + " date to filter by Date Range.";
} else {
startAfterEndMsg = scope.labels.start + " must occur before " + scope.labels.end + ".";
bothDatesRequiredMsg = "Please provide both a " + scope.labels.start + " and " + scope.labels.end + " to filter by Date Range.";
}
scope.errorHandling = {
'startAfterEnd' : {
message: startAfterEndMsg,
priority: 1
},
'bothDatesRequired' : {
message: bothDatesRequiredMsg,
priority: 2
}
};
scope.$watchCollection("ngModel", function(newVal){
if (scope.ngModel) {
if(scope.disableDaySelection && newVal.startDate && newVal.endDate) {
var startDate = new Date(newVal.startDate.split("/")[1], (newVal.startDate.split("/")[0] - 1).toString()),
endDate = new Date(newVal.endDate.split("/")[1], (newVal.endDate.split("/")[0] - 1).toString());
} else {
var startDate = new Date(newVal.startDate),
endDate = new Date(newVal.endDate);
}
ngModelCtrl.$setValidity("startAfterEnd", !isValidDate(newVal.startDate, false, scope.disableDaySelection) || !isValidDate(newVal.endDate, false, scope.disableDaySelection) || startDate <= endDate);
if (!scope.ngRequired && scope.bothRequired) {
ngModelCtrl.$setValidity("bothDatesRequired", !isOnlyOneDatePresent(newVal.startDate, newVal.endDate));
}
}
});
var isOnlyOneDatePresent = function(start, end) {
return (start === null || start === '') && (end !== null && end !== '')
|| (end === null || end === '') && (start !== null && start !== '');
};
},
templateUrl: 'src/ui-components/form/controls/composite/input-date-picker/date-range-control_template.html'
};
});
var isValidDate = function(dateString, disableMonthSelection, disableDaySelection) {
if (typeof dateString !== "string") {
return false;
}
dateString = formatNonStandardDate(dateString, disableMonthSelection, disableDaySelection);
var tokenizingRegEx = /^([0-9]{2})\/([0-9]{2})\/([0-9]{4})$/,
dateTokens = dateString.match(tokenizingRegEx),
date = new Date(dateString);
return date.toString() !== "Invalid Date" && dateTokens !== null && (date.getMonth() + 1 === parseInt(dateTokens[1])) && (date.getDate() === parseInt(dateTokens[2])) && (date.getFullYear() === parseInt(dateTokens[3]));
};
var formatNonStandardDate = function (dateString, disableMonthSelection, disableDaySelection) {
if (typeof dateString !== "string") {
return dateString;
}
if (disableMonthSelection) {
if (dateString.indexOf("01/01/") === -1) {
return "01/01/" + dateString;
}
} else if (disableDaySelection && dateString.length > 2 && dateString.indexOf("/01") !== 2) {
return dateString.slice(0, 2) + "/01" + dateString.slice(2, dateString.length);
}
return dateString;
};
});