'use strict';
var uiDirectives = angular.module('uiDirectives', []);
uiDirectives.directive('ngSelect2', ['$timeout', function ($timeout) {
return {
scope: {
'model': '=ngModel',
'disabled': '=ngDisabed',
formatResult: '&select2FormatResult',
},
link: function (scope, elem, attrs) {
$timeout(function () {
var $select = $(elem);
var opts = {
value: scope.model,
allowClear: attrs.allowclear,
dropdownAutoWidth: attrs.dropdownautowidth,
placeholder: attrs.placeholder,
dropdownCss: attrs.dropdowncss,
minimumResultsForSearch: +attrs.minimumresultsforsearch,
formatResult: scope.formatResult(),
width: attrs.width
};
$select.select2(opts).on('change', function (e) {
var newVal = e.val;
scope.$apply(function () {
scope.model = newVal;
//console.log('select2.onChange name=' + $select.attr('name') + '; newVal=' + newVal + ';children=' + $select.children().length);
});
});
//if (opts.width)
// $select.parent().css("width", opts.width);
scope.$watch('model', function (newVal, oldVal) {
$timeout(function () {
//console.log('select2 name=' + $select.attr('name') + '; newVal=' + newVal + '; oldVal=' + oldVal + ';children=' + $select.children().length);
$select.select2('val', newVal);
}, 0, false);
});
scope.$watch('disabled', function (newVal, oldVal) {
$timeout(function () {
$select.select2('enable', !newVal);
}, 0, false);
});
$select.on('$destroy', function () {
$select.select2('destroy');
});
}, 0, false);
}
}
}]);
uiDirectives.directive('ngSwitcher', ['$timeout', function ($timeout) {
return {
scope: {
'ngDisabled': '=?ngDisabled',
formatResult: '&select2FormatResult'
},
require: ['?ngModel'],
link: function (scope, elem, attrs, ctrls) {
var $elem = $(elem);
var opts = {
on_state_content: attrs.ngSwOnStateContent,
off_state_content: attrs.ngSwOffStateContent,
width: attrs.ngSwWidth
};
if (scope.ngDisabled)
$elem.prop('disabled', true);
$elem.switcher(opts);
if (opts.width)
$elem.parent().css("width", opts.width);
if (ctrls[0]) {
var ngModelCtrl = ctrls[0];
var listener = function (ev) {
ngModelCtrl.$setViewValue(elem[0].checked, ev && ev.type);
};
elem.on('click', listener);
ngModelCtrl.$render = function () {
$timeout(function () {
elem[0].checked = ngModelCtrl.$viewValue;
$(elem[0]).switcher('refreshView');
}, 0, false);
};
// Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
// This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
// it to a boolean.
ngModelCtrl.$isEmpty = function (value) {
return (value === false);
};
ngModelCtrl.$formatters.push(function (value) {
return (value === true);
});
ngModelCtrl.$parsers.push(function (value) {
return value;
});
}
scope.$watch('ngDisabled', function (newVal, oldVal) {
$timeout(function () {
if (isNaN(newVal))
return;
if (newVal && !oldVal)
$elem.switcher('disable');
else if (!newVal && oldVal)
$elem.switcher('enable');
}, 0, false);
});
$elem.on('$destroy', function () {
$elem.switcher('destroy');
});
}
}
}]);
uiDirectives.directive('ngInitWidget', function () {
return {
restrict: 'A',
priority: 1200, // we need to init widget before ng-repeat added data to the table and change it's size
controller: ['$scope', '$element', function ($scope, $element) {
$($element).activityCalendarGrid('init');
}],
};
});
uiDirectives.directive('optionClassExpr', ['$compile', function ($compile) {
var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
return {
restrict: 'A',
link: function optionClassExprPostLink(scope, elem, attrs) {
var optionsExp = attrs.ngOptions;
if (!optionsExp) return;
var match = optionsExp.match(NG_OPTIONS_REGEXP);
if (!match) return;
var values = match[7];
scope.$watchCollection(function () {
return elem.children();
}, function (newValue) {
angular.forEach(newValue, function (child, index) {
var child = angular.element(child);
var val = child.val();
if (val) {
child.attr('ng-class', values + '[' + (index - 1) + '].' + attrs.optionClassExpr);
$compile(child)(scope);
}
});
});
}
};
}]);
// This is a directive used to move page preference
items from current in specific partial view to the
// target container (assuming it is also a node) specific for the page (it can be a menu in the site header or a menu in specific widget on any dashboard)
uiDirectives.directive('ngWidgetOptionsMenu', ['$timeout', function ($timeout) {
return {
scope: {
'menuId': '=', // an Id property of the target container
'changePageOptionValue': '&changePageOptionValue'
},
link: function (scope, elem, attrs) {
var $container = $(elem);
var $menu = $('#' + scope.menuId);
var $changeHandler = scope.changePageOptionValue();
// move section attribute from container to widget/page options menu
$menu.attr('data-section', $container.data('section'));
$container.removeAttr('data-section');
// move widget/page options from container to menu
angular.forEach($container.find('li'), function (item) {
var liItem = $(item);
var dataKey = liItem.find('[data-key]').data('key');
if (dataKey) {
liItem.change(function (e) {
$timeout(function () {
var newValue = e.val;
if (e && e.target && e.target && e.target.type && e.target.type === 'checkbox') {
newValue = e.target.checked;
}
if ($changeHandler)
$changeHandler(e, dataKey, newValue);
});
});
}
liItem.appendTo($menu);
});
// To-Do: call event.stopPropagation() to fix unexpected closing in IE
}
}
}]);
uiDirectives.directive('ngMovable', function () {
return {
restrict: 'A',
require: ['?ngTargetContainerClass', '?ngParentContainerClass'],
scope: {
'ngParentContainerClass': '=',
'ngTargetContainerClass': '=',
},
link: function (scope, elem, attrs) {
var $element = angular.element(elem);
var $parent = $element.parents('.' + attrs.ngParentContainerClass);
var $container = $parent.find('.' + attrs.ngTargetContainerClass);
$container.append($element);
}
}
});
uiDirectives.directive('ngDateRange', ['$timeout', function ($timeout) {
return {
scope: {
'startDate': '=',
'endDate': '=',
'onChangeStartDate': '&onChangeStartDate',
'onChangeEndDate': '&onChangeEndDate'
},
link: function (scope, elem, attrs) {
var opts = {
format: attrs.format || 'mm/dd/yyyy',
autoclose: attrs.autoclose,
orientation: attrs.orientation || ($('body').hasClass('right-to-left') ? "auto right" : 'auto auto'),
startDate: scope.startDate,
endDate: scope.endDate
};
var $container = $(elem);
var $startChangeHandler = scope.onChangeStartDate();
var $endChangeHandler = scope.onChangeEndDate();
var $txtStart = $container.find('.ng-date-range-start');
$txtStart.prop('id', Math.uuid(15)); // generate id property because compare validator requries it
var $txtEnd = $container.find('.ng-date-range-end');
$txtEnd.prop('id', Math.uuid(15)); // generate id property because compare validator requries it
$txtEnd.attr('valDategreaterthanorequalOtherpropertyname', $txtStart.prop('id'));
var changeDateByPickerFn = function (evt) {
scope.$apply(function () {
if (evt.target.id == $txtStart.prop('id')) {
var sDate = undefined;
var tmpValue = $txtStart.val();
var endDateValue = $txtEnd.val();
if (tmpValue && (tmpValue.length > 0))
sDate = new Date(tmpValue);
// if end date is not set then set it as start date
if (!endDateValue || (endDateValue.length > 0)) {
$container.data('datepicker').pickers[1].prepopulate(sDate);
}
// and limit end date min value
$txtEnd.data('datepicker').setStartDate(sDate);
if ($startChangeHandler) {
$startChangeHandler(evt, $txtStart.data('key'), tmpValue);
}
} else if (evt.target.id == $txtEnd.prop('id')) {
if ($endChangeHandler) {
$endChangeHandler(evt, $txtEnd.data('key'), $txtEnd.val());
}
}
});
};
var changeDateByTextFn = function (evt) {
scope.$apply(function () {
if (evt.target.id == $txtStart.prop('id')) {
if ($startChangeHandler) {
$startChangeHandler(evt, $txtStart.data('key'), $txtStart.val());
}
} else if (evt.target.id == $txtEnd.prop('id')) {
if ($endChangeHandler) {
$endChangeHandler(evt, $txtEnd.data('key'), $txtEnd.val());
}
}
});
};
var picker = $container.datepicker(opts);
$(picker).on('changeDate', changeDateByPickerFn);
$($txtStart).on('blur', changeDateByTextFn);
scope.$watch('startDate', function (newVal, oldVal) {
var newValueAsDate = new Date(newVal);
if (Object.prototype.toString.call(newValueAsDate) === "[object Date]") {
if (!isNaN(newValueAsDate.getTime())) {
// New value is a valid date
$timeout(function () {
$txtStart.data('datepicker').update();
}, 0, false);
}
}
});
scope.$watch('endDate', function (newVal, oldVal) {
var newValueAsDate = new Date(newVal);
if (Object.prototype.toString.call(newValueAsDate) === "[object Date]") {
if (!isNaN(newValueAsDate.getTime())) {
// New value is a valid date
$timeout(function () {
$txtEnd.data('datepicker').update();
}, 0, false);
}
}
});
}
}
}]);
uiDirectives.directive('ngPopupMenu', ['$timeout', function ($timeout) {
return {
link: function (scope, elem, attrs) {
var opts = {
hidePopoversContainer: attrs.hidePopoversContainer
};
var $container = $(elem);
$container.popupMenu(opts);
}
}
}]);
uiDirectives.directive('ngModalDialogForm', ['$timeout', function ($timeout) {
return {
restrict: 'A',
scope: {
},
link: function (scope, elem, attrs) {
var $container = elem;
var confirmCloseMessage = undefined;
if (attrs) {
if (attrs['showFormEvent']) {
scope.$on(attrs['showFormEvent'], function (e) {
$($container).modalDialogForm('show');
})
}
if (attrs['hideFormEvent']) {
scope.$on(attrs['hideFormEvent'], function (e, callbackFn) {
$($container).modalDialogForm('hide');
if (callbackFn && (typeof callbackFn === 'function')) {
callbackFn();
}
})
}
if (attrs['setDataChangedEvent']) {
scope.$on(attrs['setDataChangedEvent'], function (e, dataChangedState) {
var changeState = dataChangedState !== undefined ? dataChangedState : true;
$($container).modalDialogForm('setDataChanged', changeState);
})
}
if (attrs['resetDataChangedEvent']) {
scope.$on(attrs['resetDataChangedEvent'], function (e) {
$($container).modalDialogForm('resetDataChanges');
})
}
if (attrs['confirmCloseMessage']) {
confirmCloseMessage = attrs['confirmCloseMessage'];
}
}
$timeout(function () {
var opts = {
};
if (confirmCloseMessage) {
opts.confirmMessage = confirmCloseMessage
};
scope.$apply($($container).modalDialogForm(opts));
}, 0, false);
}
};
}]);
uiDirectives.directive('ngTooltip', function () {
return {
restrict: 'A',
require: ['?ttOnContent', '?ttHeader'],
scope: {
'onGetContent': '&ttOnContent',
'header': '=ttHeader',
'projectId': '=ttProjectId',
'expcatId': '=ttExpcatId',
'teamId': '=ttTeamId',
'resourceId': '=ttResourceId',
},
link: function (scope, elem, attrs, ctrls) {
var $container = elem;
var doDestroyClick = false;
var doDestroyShow = false;
if (!$(elem).hasClass('tooltip-info')) {
$(elem).addClass('tooltip-info');
}
var tooltipOpts = {
header: scope.header,
projectId: scope.projectId,
expCatId: scope.expcatId,
teamId: scope.teamId,
resourceId: scope.resourceId
}
var toolTipContentHandler = scope.onGetContent();
var showTooltipHandler = function () {
$('.tooltip').removeClass('in').hide();
};
var clickHandler = function (event) {
event.stopPropagation();
var tooltipContent = '';
if (toolTipContentHandler) {
tooltipContent = toolTipContentHandler(tooltipOpts);
}
if($container.data('bs.tooltip')) {
$container.attr('data-original-title', tooltipContent)
return;
}
var opts = {
trigger: 'click',
html: true,
title: tooltipContent
};
$container.tooltip(opts).on('show.bs.tooltip', showTooltipHandler);
doDestroyShow = true;
$container.tooltip('show');
}
if (toolTipContentHandler) {
elem.on('click.tt', clickHandler);
doDestroyClick = true;
}
elem.on('$destroy', function () {
if (doDestroyShow) {
$container.tooltip().off('show.bs.tooltip', showTooltipHandler);
}
if (doDestroyClick) {
$container.off('click.tt', clickHandler);
}
$container.tooltip('destroy');
});
}
}
});