Merge pull request #3632 from eileenmcnaughton/tests
[civicrm-core.git] / js / angular-crm-ui.js
CommitLineData
685acae4 1/// crmUi: Sundry UI helpers
2(function (angular, $, _) {
438f2b52 3 var idCount = 0;
685acae4 4
5 angular.module('crmUi', [])
438f2b52
TO
6 // example: <form name="myForm">...<label crm-ui-label crm-for="myField">My Field</span>...<input name="myField"/>...</form>
7 //
8 // Label adapts based on <input required>, <input ng-required>, or any other validation.
9 //
10 // Note: This should work in the normal case where <label> and <input> are in roughly the same scope,
11 // but if the scopes are materially different then problems could arise.
12 .directive('crmUiLabel', function($parse) {
13 return {
14 scope: {
15 name: '@'
16 },
17 transclude: true,
18 template: '<span ng-class="cssClasses"><span ng-transclude></span> <span ng-show="crmRequired" class="crm-marker" title="This field is required.">*</span></span>',
19 link: function(scope, element, attrs) {
20 if (attrs.crmFor == 'name') {
21 throw new Error('Validation monitoring does not work for field name "name"');
22 }
23
24 // 1. Figure out form and input elements
25
26 var form = $(element).closest('form');
27 var formCtrl = scope.$parent.$eval(form.attr('name'));
28 var input = $('input[name="' + attrs.crmFor + '"],select[name="' + attrs.crmFor + '"],textarea[name="' + attrs.crmFor + '"]', form);
29 if (form.length != 1 || input.length != 1) {
30 if (console.log) console.log('Label cannot be matched to input element. Expected to find one form and one input.', form.length, input.length);
31 return;
32 }
33
34 // 2. Make sure that inputs are well-defined (with name+id).
35
36 if (!input.attr('id')) {
37 input.attr('id', 'crmUi_' + (++idCount));
38 }
39 $(element).attr('for', input.attr('id'));
40
41 // 3. Monitor is the "required" and "$valid" properties
42
43 if (input.attr('ng-required')) {
44 scope.crmRequired = scope.$parent.$eval(input.attr('ng-required'));
45 scope.$parent.$watch(input.attr('ng-required'), function(isRequired) {
46 scope.crmRequired = isRequired;
47 });
48 } else {
49 scope.crmRequired = input.prop('required');
50 }
51
52 var inputCtrl = form.attr('name') + '.' + input.attr('name');
53 scope.cssClasses = {};
54 scope.$parent.$watch(inputCtrl + '.$valid', function(newValue) {
55 //scope.cssClasses['ng-valid'] = newValue;
56 //scope.cssClasses['ng-invalid'] = !newValue;
57 scope.cssClasses['crm-error'] = !scope.$parent.$eval(inputCtrl + '.$valid') && !scope.$parent.$eval(inputCtrl + '.$pristine');
58 });
59 scope.$parent.$watch(inputCtrl + '.$pristine', function(newValue) {
60 //scope.cssClasses['ng-pristine'] = newValue;
61 //scope.cssClasses['ng-dirty'] = !newValue;
62 scope.cssClasses['crm-error'] = !scope.$parent.$eval(inputCtrl + '.$valid') && !scope.$parent.$eval(inputCtrl + '.$pristine');
63 });
64
65 }
66 };
67 })
685acae4 68
69 // example: <a crm-ui-lock binding="mymodel.boolfield"></a>
70 // example: <a crm-ui-lock
71 // binding="mymodel.boolfield"
72 // title-locked="ts('Boolfield is locked')"
73 // title-unlocked="ts('Boolfield is unlocked')"></a>
74 .directive('crmUiLock', function ($parse, $rootScope) {
75 var defaultVal = function (defaultValue) {
76 var f = function (scope) {
77 return defaultValue;
78 }
79 f.assign = function (scope, value) {
80 // ignore changes
81 }
82 return f;
83 };
84
85 // like $parse, but accepts a defaultValue in case expr is undefined
86 var parse = function (expr, defaultValue) {
87 return expr ? $parse(expr) : defaultVal(defaultValue);
88 };
89
90 return {
91 template: '',
92 link: function (scope, element, attrs) {
93 var binding = parse(attrs['binding'], true);
94 var titleLocked = parse(attrs['titleLocked'], ts('Locked'));
95 var titleUnlocked = parse(attrs['titleUnlocked'], ts('Unlocked'));
96
97 $(element).addClass('ui-icon lock-button');
98 var refresh = function () {
99 var locked = binding(scope);
100 if (locked) {
101 $(element)
102 .removeClass('ui-icon-unlocked')
103 .addClass('ui-icon-locked')
104 .prop('title', titleLocked(scope))
105 ;
106 }
107 else {
108 $(element)
109 .removeClass('ui-icon-locked')
110 .addClass('ui-icon-unlocked')
111 .prop('title', titleUnlocked(scope))
112 ;
113 }
114 };
115
116 $(element).click(function () {
117 binding.assign(scope, !binding(scope));
118 //scope.$digest();
119 $rootScope.$digest();
120 });
121
122 scope.$watch(attrs.binding, refresh);
123 scope.$watch(attrs.titleLocked, refresh);
124 scope.$watch(attrs.titleUnlocked, refresh);
125
126 refresh();
127 }
128 };
129 })
02308c07
TO
130 .run(function($rootScope, $location) {
131 /// Example: <button ng-click="goto('home')">Go home!</button>
132 $rootScope.goto = function(path) {
133 $location.path(path);
134 };
135 })
685acae4 136 ;
137
138})(angular, CRM.$, CRM._);