+ // example: <input crm-ui-date="myobj.datefield" />
+ // example: <input crm-ui-date="myobj.datefield" crm-ui-date-format="yy-mm-dd" />
+ .directive('crmUiDate', function ($parse, $timeout) {
+ return {
+ restrict: 'AE',
+ scope: {
+ crmUiDate: '@', // expression, model binding
+ crmUiDateFormat: '@' // expression, date format (default: "yy-mm-dd")
+ },
+ link: function (scope, element, attrs) {
+ var fmt = attrs.crmUiDateFormat ? $parse(attrs.crmUiDateFormat)() : "yy-mm-dd";
+ var model = $parse(attrs.crmUiDate);
+
+ element.addClass('dateplugin');
+ $(element).datepicker({
+ dateFormat: fmt
+ });
+
+ var updateChildren = (function() {
+ element.off('change', updateParent);
+ $(element).datepicker('setDate', model(scope.$parent));
+ element.on('change', updateParent);
+ });
+ var updateParent = (function() {
+ $timeout(function () {
+ model.assign(scope.$parent, $(element).val());
+ });
+ });
+
+ updateChildren();
+ scope.$parent.$watch(attrs.crmUiDate, updateChildren);
+ element.on('change', updateParent);
+ }
+ };
+ })
+
+ // example: <div crm-ui-date-time="myobj.mydatetimefield"></div>
+ .directive('crmUiDateTime', function ($parse) {
+ return {
+ restrict: 'AE',
+ scope: {
+ crmUiDateTime: '@'
+ },
+ template: '<input crm-ui-date="dtparts.date" placeholder="{{dateLabel}}"/> <input crm-ui-time="dtparts.time" placeholder="{{timeLabel}}"/>',
+ link: function (scope, element, attrs) {
+ var model = $parse(attrs.crmUiDateTime);
+ scope.dateLabel = ts('Date');
+ scope.timeLabel = ts('Time');
+
+ var updateChildren = (function () {
+ var value = model(scope.$parent);
+ if (value) {
+ var dtparts = value.split(/ /);
+ scope.dtparts = {date: dtparts[0], time: dtparts[1]};
+ }
+ else {
+ scope.dtparts = {date: '', time: ''};
+ }
+ });
+ var updateParent = (function () {
+ model.assign(scope.$parent, scope.dtparts.date + " " + scope.dtparts.time);
+ });
+
+ updateChildren();
+ scope.$parent.$watch(attrs.crmUiDateTime, updateChildren);
+ scope.$watch('dtparts.date', updateParent);
+ scope.$watch('dtparts.time', updateParent);
+ }
+ };
+ })
+
+ // Display a field/row in a field list
+ // example: <div crm-ui-field crm-title="My Field"> {{mydata}} </div>
+ // example: <div crm-ui-field="subform.myfield" crm-title="'My Field'"> <input crm-ui-id="subform.myfield" name="myfield" /> </div>
+ // example: <div crm-ui-field="subform.myfield" crm-title="'My Field'"> <input crm-ui-id="subform.myfield" name="myfield" required /> </div>
+ .directive('crmUiField', function() {
+ // Note: When writing new templates, the "label" position is particular. See/patch "var label" below.
+ var templateUrls = {
+ default: '~/crmUi/field.html',
+ checkbox: '~/crmUi/field-cb.html'
+ };
+
+ return {
+ require: '^crmUiIdScope',
+ restrict: 'EA',
+ scope: {
+ crmUiField: '@',
+ crmTitle: '@'
+ },
+ templateUrl: function(tElement, tAttrs){
+ var layout = tAttrs.crmLayout ? tAttrs.crmLayout : 'default';
+ return templateUrls[layout];
+ },
+ transclude: true,
+ link: function (scope, element, attrs, crmUiIdCtrl) {
+ $(element).addClass('crm-section');
+ scope.crmUiField = attrs.crmUiField;
+ scope.crmTitle = attrs.crmTitle;
+ }
+ };
+ })
+
+ // example: <div ng-form="subform" crm-ui-id-scope><label crm-ui-for="subform.foo">Foo:</label><input crm-ui-id="subform.foo" name="foo"/></div>
+ .directive('crmUiId', function () {
+ return {
+ require: '^crmUiIdScope',
+ restrict: 'EA',
+ link: {
+ pre: function (scope, element, attrs, crmUiIdCtrl) {
+ var id = crmUiIdCtrl.get(attrs.crmUiId);
+ element.attr('id', id);
+ }
+ }
+ };
+ })
+
+ // example: <div ng-form="subform" crm-ui-id-scope><label crm-ui-for="subform.foo">Foo:</label><input crm-ui-id="subform.foo" name="foo"/></div>
+ .directive('crmUiFor', function ($parse, $timeout) {
+ return {
+ require: '^crmUiIdScope',
+ restrict: 'EA',
+ template: '<span ng-class="cssClasses"><span ng-transclude/><span crm-ui-visible="crmIsRequired" class="crm-marker" title="This field is required.">*</span></span>',
+ transclude: true,
+ link: function (scope, element, attrs, crmUiIdCtrl) {
+ scope.crmIsRequired = false;
+ scope.cssClasses = {};
+
+ if (!attrs.crmUiFor) return;
+
+ var id = crmUiIdCtrl.get(attrs.crmUiFor);
+ element.attr('for', id);
+ var ngModel = null;
+
+ var updateCss = function () {
+ scope.cssClasses['crm-error'] = !ngModel.$valid && !ngModel.$pristine;
+ };
+
+ // Note: if target element is dynamically generated (eg via ngInclude), then it may not be available
+ // immediately for initialization. Use retries/retryDelay to initialize such elements.
+ var init = function (retries, retryDelay) {
+ var input = $('#' + id);
+ if (input.length === 0) {
+ if (retries) {
+ $timeout(function(){
+ init(retries-1, retryDelay);
+ }, retryDelay);
+ }
+ return;
+ }
+
+ var tgtScope = scope;//.$parent;
+ if (attrs.crmDepth) {
+ for (var i = attrs.crmDepth; i > 0; i--) {
+ tgtScope = tgtScope.$parent;
+ }
+ }
+
+ if (input.attr('ng-required')) {
+ scope.crmIsRequired = scope.$parent.$eval(input.attr('ng-required'));
+ scope.$parent.$watch(input.attr('ng-required'), function (isRequired) {
+ scope.crmIsRequired = isRequired;
+ });
+ }
+ else {
+ scope.crmIsRequired = input.prop('required');
+ }
+
+ ngModel = $parse(attrs.crmUiFor)(tgtScope);
+ if (ngModel) {
+ ngModel.$viewChangeListeners.push(updateCss);
+ }
+ };
+
+ $timeout(function(){
+ init(3, 100);
+ });
+ }
+ };
+ })
+
+ // example: <div ng-form="subform" crm-ui-id-scope><label crm-ui-for="subform.foo">Foo:</label><input crm-ui-id="subform.foo" name="foo"/></div>
+ .directive('crmUiIdScope', function () {
+ return {
+ restrict: 'EA',
+ scope: {},
+ controllerAs: 'crmUiIdCtrl',
+ controller: function($scope) {
+ var ids = {};
+ this.get = function(name) {
+ if (!ids[name]) {
+ ids[name] = "crmUiId_" + (++uidCount);
+ }
+ return ids[name];
+ };
+ },
+ link: function (scope, element, attrs) {}
+ };
+ })
+