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('InputCalendarDatePicker', [])
.directive('dateControl', function($compile, $parse, $document, $position, $timeout, $filter, dateFilter, dateParser, formatter) {
return {
restrict: 'AE',
require: 'ngModel',
scope: {
ngReadonly: '=',
ngRequired: '=',
ngModel : "=",
ngDisabled : "=",
futureAllowed : "=",
fieldId : "@",
label : "@",
labelIcon : "=",
allowedDateRange : "=?",
hideDay: "=?",
disableMonthSelection: "=?",
disableDaySelection: "=?",
disableErrors : "=",
additionalScreenreaderText: "@",
notificationStatusLabel : "@",
isSubLabel : '@'
},
link: function (scope, element, attrs, ngModel) {

scope.ngRequired ? scope.dateLabel = "Required: " + scope.label : scope.dateLabel = scope.label;
scope.dateLabel += ": ";
scope.disableMonthSelection ? scope.dateLabel += 'Y Y Y Y' : (scope.disableDaySelection ? scope.dateLabel += 'M M / Y Y Y Y' : scope.dateLabel += 'M M / D D / Y Y Y Y');
scope.additionalScreenreaderText ? scope.dateLabel += scope.additionalScreenreaderText + ": " : scope.dateLabel += ": ";

scope.isFocused = false;

scope.showButtonBar = false;
scope.minDate = getMinAllowedDate(scope, formatter);
scope.maxDate = getMaxAllowedDate(scope, formatter);

var calendarPopupElement = angular.element('<div accessible-datepicker-alt-popup-wrap><div calendar-date-picker></div></div>');
calendarPopupElement.attr({
'ng-model': 'date',
'ng-change': 'setInputDateFromCalendar()'
});


var calendarDatePickerElement = angular.element(calendarPopupElement.children()[0]);
calendarDatePickerElement.attr( 'format-year', 'yyyy' );
calendarDatePickerElement.attr( 'starting-day', 0 );
calendarDatePickerElement.attr( 'show-weeks', false );
calendarDatePickerElement.attr( 'min-mode', scope.disableMonthSelection ? "year" : (scope.disableDaySelection ? "month" : "day") );
calendarDatePickerElement.attr( 'min-date', "minDate" );
calendarDatePickerElement.attr( 'max-date', "maxDate" );

scope.openCalendarPopup = function($event) {
angular.forEach(angular.element('ul[accessible-datepicker-alt-popup-wrap]'), function(calendarPopup) {
angular.element(calendarPopup).scope().close();
});

$event.preventDefault();
$event.stopPropagation();
scope.isOpen = !scope.isOpen;
};

var keydown = function(evt) {
scope.keydown(evt);
};
element.bind('keydown', keydown);
scope.keydown = function(evt) {
if (evt.which === 27) {
evt.preventDefault();
evt.stopPropagation();
scope.close();
} else if (evt.which === 9) {
scope.close();
}
};

scope.$watch('isOpen', function(value) {
if (value) {
scope.$broadcast('datepicker.focus');
scope.position = $position.position(element);
scope.position.top = scope.position.height;

$document.bind('touchstart click', documentClickBind);
} else {
$document.unbind('touchstart click', documentClickBind);
}
});

var documentClickBind = function(event) {
if (scope.isOpen && (event.target !== angular.element(element[0]).find('input')[0] && $popup.find(event.target).length === 0)) {
scope.$apply(function() {
scope.isOpen = false;
});
}
};

scope.close = function() {
scope.isOpen = false;
element[0].focus();
};

var $popup = $compile(calendarPopupElement)(scope);
element.after($popup);

scope.$on('$destroy', function() {
$popup.remove();
element.unbind('keydown', keydown);
$document.unbind('click', documentClickBind);
});

var formatInputDateFromCalendar = function (rawDate) {
var dateFormat = 'MM/dd/yyyy';

if (scope.disableMonthSelection) {
dateFormat = 'yyyy';
}
else if (scope.disableDaySelection) {
dateFormat = 'MM/yyyy';
}

return $filter('date')(rawDate, dateFormat);
};

scope.setInputDateFromCalendar = function(dt) {
if (angular.isDefined(dt)) {
scope.date = dt;
}

scope.date = formatInputDateFromCalendar(scope.date);
prevDateTokens = tokenizeDateString(scope.date);

ngModel.$setViewValue(scope.date);
ngModel.$render();

scope.isOpen = false;
element[0].focus();
};

element.bind('input change keyup', function() {
scope.$apply(function() {
scope.date = getFormattedModelDate(ngModel.$modelValue);
if (ngModel.$modelValue === "") {
prevDateTokens = ["", "", "", "", ""];
}
});
});

// Outer change
ngModel.$render = function() {
element.val(getFormattedViewValue(ngModel.$viewValue));
scope.date = getFormattedModelDate(ngModel.$modelValue);
};

var getFormattedViewValue = function(viewValue) {
var dateFormat = scope.disableMonthSelection ? 'yyyy' : (scope.disableDaySelection ? 'MM/yyyy' : 'MM/dd/yyyy'),
date = !viewValue ? '' : (angular.isString(viewValue) ? viewValue : dateFilter(viewValue, dateFormat));
return scope.disableMonthSelection ? date.replace(/(.*)\d{2}\//, '') : (scope.disableDaySelection ? date.replace(/\/\d{2}\//, "/") : date);
};

var getFormattedModelDate = function (modelValue) {
var formattedModelDate = (modelValue && isFormattedDate(modelValue)) ? formatNonStandardDate(modelValue, scope.disableMonthSelection, scope.disableDaySelection) : modelValue;
return ngModel.$error.pattern ? undefined : formattedModelDate;
};

if (scope.disableMonthSelection) {
scope.disableDaySelection = true;
}

var validator = function(newVal) {
ngModel.$setValidity("pattern", isFormattedDate(newVal) || !newVal);
ngModel.$setValidity("range", isInRange(newVal) || !newVal);
ngModel.$setValidity("valid", isValidDate(newVal, scope.disableMonthSelection, scope.disableDaySelection) || !newVal);
return newVal;
};

ngModel.$parsers.push(validator);
ngModel.$formatters.push(validator);

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 + " must be formatted " + (scope.disableMonthSelection ? "YYYY." : (scope.disableDaySelection ? "MM/YYYY." : "MM/DD/YYYY."));
scope.errorHandling.range.message = getInvalidRangeMessage(label);
scope.errorHandling.valid.message = label + " is an invalid date.";
validator(scope.ngModel);
}
});

scope.validAllowedDateRange = {};
scope.$watch("allowedDateRange", function () {
var label = getLabelText(scope.label);
scope.validAllowedDateRange.min = scope.minDate = getMinAllowedDate(scope, formatter);
scope.validAllowedDateRange.max = scope.maxDate = getMaxAllowedDate(scope, formatter);
scope.errorHandling.range.message = getInvalidRangeMessage(label);
validator(scope.ngModel);
}, true);

var getLabelText = function (text) {
text = text || "";
return text.lastIndexOf(":") === text.length - 1 ? text.substr(0, text.length - 1) : text;
};

function getMinAllowedDate() {
return scope.allowedDateRange && scope.allowedDateRange.min && !scope.ngReadonly ? scope.allowedDateRange.min : formatter.getFormattedFrontendDate("01/01/1900");
}

function getMaxAllowedDate() {
return scope.allowedDateRange && scope.allowedDateRange.max && !scope.ngReadonly ? scope.allowedDateRange.max : (scope.futureAllowed ? formatter.getFormattedFrontendDate(formatter.addDays(new Date(),270)) : formatter.getFormattedFrontendDate(new Date()))
}

var getInvalidRangeMessage = function (label) {
var minDate = scope.minDate,
maxDate = scope.maxDate;

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);
if (indexOfFirstBackslash === indexOfLastBackslash) {
tokens[4] = dateString.substr(start + end);
}
else {
tokens[4] = dateString.substr(start + end + 1);
}
}
return tokens || ["", "", "", "", ""];
};

var inputArea = element.find('input'),
prevDateTokens = tokenizeDateString(scope.ngModel),
selectionStart = inputArea[0].selectionStart,
selectionEnd = inputArea[0].selectionEnd;

scope.onChange = function() {
validateAndFormatChangedDate();
};

function validateAndFormatChangedDate() {
if (angular.isString(scope.ngModel)) {
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], dateTokens[2], dateTokens[4]);
formattedDate += getFormattedSlash(dateTokens, prevDateTokens, 1);
formattedDate += getFormattedDay(formattedDate, dateTokens[2], prevDateTokens[2], dateTokens[0], dateTokens[4]);
formattedDate += getFormattedSlash(dateTokens, prevDateTokens, 3);
formattedDate += getFormattedYear(formattedDate, dateTokens[4], prevDateTokens[4], dateTokens[2], dateTokens[0]);
}

prevDateTokens = tokenizeDateString(formattedDate);
scope.ngModel = formattedDate;

if(prevDate === formattedDate && formattedDate !== "") {
$timeout(function(){
inputArea[0].setSelectionRange(selectionStart, selectionEnd);
});
}
} else {
if (scope.disableMonthSelection) {
scope.ngModel = prevDateTokens[4];
}
else if (scope.disableDaySelection) {
scope.ngModel = prevDateTokens[0] + prevDateTokens[1] + prevDateTokens[4];
}
else {
scope.ngModel = prevDateTokens.join("");
}
}
} else {
prevDateTokens = ["", "", "", "", ""];
}
}

var unRegisterWatch = scope.$watch("ngModel", function(newVal, oldVal) {
if (newVal !== oldVal){
ngModel.$dirty = true;
ngModel.$pristine = false;
detachWatch();
}
});

function detachWatch() {
unRegisterWatch();
}

scope.onKeydown = function () {
selectionStart = inputArea[0].selectionStart;
selectionEnd = inputArea[0].selectionEnd;
};

scope.getDayOfWeek = function () {
var dateString = formatNonStandardDate(scope.ngModel, scope.disableMonthSelection, scope.disableDaySelection);

var d = new Date(dateString),
weekday = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
return isValidDate(scope.ngModel, scope.disableMonthSelection, scope.disableDaySelection) ? weekday[d.getDay()] : "";
};

var isMonthFebruary = function (monthString) {
return parseInt(monthString) === 2;
};

var getFormattedMonth = function (newMonth, previousMonth, dayString, yearString) {
if (!scope.disableMonthSelection) {
return isMonthValid(newMonth, dayString, yearString) ? newMonth : previousMonth;
}
return "";
};

var getFormattedDay = function (formattedDate, newDay, previousDay, monthString, yearString) {
if (!scope.disableDaySelection && doesDateContainSlash(formattedDate)) {
return isDayValid(newDay, monthString, yearString) ? newDay : previousDay;
}
return "";
};

var getFormattedYear = function (formattedDate, newYear, previousYear, dayString, monthString) {
if (scope.disableMonthSelection || doesDateContainSlash(formattedDate)) {
return isYearValid(dayString, monthString, newYear) ? newYear : previousYear;
}
return "";
};

var getFormattedSlash = function (dateTokens, prevDateTokens, position) {
if (scope.disableMonthSelection || (position === 1 && scope.disableDaySelection)) {
return "";
}

if (!scope.disableMonthSelection) {
if (scope.disableDaySelection) {
if (position === 3 && dateTokens[4]) {
return "/";
}
}
else {
if ((position === 1 && dateTokens[2])
|| (position === 3 && dateTokens[4])) {
return "/";
}
}
}

if (isSlashValidOrEmpty(dateTokens, prevDateTokens, position)) {
return dateTokens[position];
}
return prevDateTokens[position];
};

var isMonth31Days = function (monthString) {
monthString = parseInt(monthString);
if (monthString === 2 || monthString === 4 || monthString === 6 || monthString === 9 || monthString === 11) {
return false;
}
else {
return true;
}
};

var isMonthValid = function (monthString, dayString, yearString) {
if (isMonthFebruary(monthString)) {
if ((yearString.length === 4) && (parseInt(yearString) % 4 !== 0)) {
return /^(0[1-9]?|1[0-9]?|2[0-8]?)?$/.test(dayString) && /^(0[1-9]?|1[0-2]?)?$/.test(monthString);
}
else {
return /^(0[1-9]?|[12][0-9]?)?$/.test(dayString) && /^(0[1-9]?|1[0-2]?)?$/.test(monthString);
}
}
else if (isMonth31Days(monthString)) {
return /^(0[1-9]?|1[0-2]?)?$/.test(monthString);
}
else {
return /^(0[1-9]?|[12][0-9]?|30?)?$/.test(dayString) && /^(0[1-9]?|1[0-2]?)?$/.test(monthString);
}
};

var isDayValid = function (dayString, monthString, yearString) {
if (isMonthFebruary(monthString)) {
if ((yearString.length === 4) && (parseInt(yearString) % 4 !== 0)) {
return /^(0[1-9]?|1[0-9]?|2[0-8]?)?$/.test(dayString);
}
else {
return /^(0[1-9]?|[12][0-9]?)?$/.test(dayString);
}
}
else if (isMonth31Days(monthString)) {
return /^(0[1-9]?|[12][0-9]?|3[01]?)?$/.test(dayString);
}
else {
return /^(0[1-9]?|[12][0-9]?|30?)?$/.test(dayString);
}
};

var isYearValid = function (dayString, monthString, yearString) {
var yearLength = yearString.length,
intYear = parseInt(yearString),
minYear = new Date(scope.validAllowedDateRange.min).getFullYear().toString(),
maxYear = new Date(scope.validAllowedDateRange.max).getFullYear().toString();

if ((yearLength === 4) && isMonthFebruary(monthString) && (parseInt(yearString) % 4 !== 0)) {
return /^(0[1-9]?|1[0-9]?|2[0-8]?)?$/.test(dayString) && /^(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))));
}
else {
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[4]) && 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: 'modules/ui-components/form/controls/composite/input-calendar-date-picker/input-calendar-date-picker_template.html'
};
})

.directive('accessibleDatepickerAltPopupWrap', function() {
return {
restrict:'EA',
replace: true,
transclude: true,
templateUrl: 'modules/ui-components/form/controls/composite/input-calendar-date-picker/input-calendar-date-picker-popup_template.html',
link:function (scope, element) {
element.bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
}
};
})

.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"
};

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;
}

scope.errorHandling = {
'startAfterEnd' : {
message: scope.labels.start + " must occur before " + scope.labels.end + ".",
priority: 1
},
'bothDatesRequired' : {
message: "Please provide both a " + scope.labels.start + " and " + scope.labels.end + " to filter by Date Range.",
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: 'modules/ui-components/form/controls/composite/input-calendar-date-picker/calendar-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, dateString.indexOf('/')) + "/01" + dateString.slice(dateString.indexOf('/'), dateString.length);
}
return dateString;
};
});