/// crmUi: Sundry UI helpers
(function (angular, $, _) {
+ var idCount = 0;
angular.module('crmUi', [])
+ // example: <form name="myForm">...<label crm-ui-label crm-for="myField">My Field</span>...<input name="myField"/>...</form>
+ //
+ // Label adapts based on <input required>, <input ng-required>, or any other validation.
+ //
+ // Note: This should work in the normal case where <label> and <input> are in roughly the same scope,
+ // but if the scopes are materially different then problems could arise.
+ .directive('crmUiLabel', function($parse) {
+ return {
+ scope: {
+ name: '@'
+ },
+ transclude: true,
+ template: '<span ng-class="cssClasses"><span ng-transclude></span> <span ng-show="crmRequired" class="crm-marker" title="This field is required.">*</span></span>',
+ link: function(scope, element, attrs) {
+ if (attrs.crmFor == 'name') {
+ throw new Error('Validation monitoring does not work for field name "name"');
+ }
+
+ // 1. Figure out form and input elements
+
+ var form = $(element).closest('form');
+ var formCtrl = scope.$parent.$eval(form.attr('name'));
+ var input = $('input[name="' + attrs.crmFor + '"],select[name="' + attrs.crmFor + '"],textarea[name="' + attrs.crmFor + '"]', form);
+ if (form.length != 1 || input.length != 1) {
+ if (console.log) console.log('Label cannot be matched to input element. Expected to find one form and one input.', form.length, input.length);
+ return;
+ }
+
+ // 2. Make sure that inputs are well-defined (with name+id).
+
+ if (!input.attr('id')) {
+ input.attr('id', 'crmUi_' + (++idCount));
+ }
+ $(element).attr('for', input.attr('id'));
+
+ // 3. Monitor is the "required" and "$valid" properties
+
+ if (input.attr('ng-required')) {
+ scope.crmRequired = scope.$parent.$eval(input.attr('ng-required'));
+ scope.$parent.$watch(input.attr('ng-required'), function(isRequired) {
+ scope.crmRequired = isRequired;
+ });
+ } else {
+ scope.crmRequired = input.prop('required');
+ }
+
+ var inputCtrl = form.attr('name') + '.' + input.attr('name');
+ scope.cssClasses = {};
+ scope.$parent.$watch(inputCtrl + '.$valid', function(newValue) {
+ //scope.cssClasses['ng-valid'] = newValue;
+ //scope.cssClasses['ng-invalid'] = !newValue;
+ scope.cssClasses['crm-error'] = !scope.$parent.$eval(inputCtrl + '.$valid') && !scope.$parent.$eval(inputCtrl + '.$pristine');
+ });
+ scope.$parent.$watch(inputCtrl + '.$pristine', function(newValue) {
+ //scope.cssClasses['ng-pristine'] = newValue;
+ //scope.cssClasses['ng-dirty'] = !newValue;
+ scope.cssClasses['crm-error'] = !scope.$parent.$eval(inputCtrl + '.$valid') && !scope.$parent.$eval(inputCtrl + '.$pristine');
+ });
+
+ }
+ };
+ })
// example: <a crm-ui-lock binding="mymodel.boolfield"></a>
// example: <a crm-ui-lock
<table class="form-layout">
<tbody>
<tr>
- <td class="label">Label</td>
+ <td class="label">
+ <label crm-ui-label crm-for="title">
+ Title
+ </label>
+ </td>
<td>
- <input type="text" ng-model="caseType.title" class="big crm-form-text"/>
+ <input
+ type="text"
+ name="title"
+ ng-model="caseType.title"
+ class="big crm-form-text"
+ required
+ />
</td>
</tr>
<tr>
- <td class="label">Name</td>
+ <td class="label">
+ <label crm-ui-label crm-for="caseTypeName">
+ Name
+ </label>
+ </td>
<td>
- <input type="text" ng-model="caseType.name" ng-disabled="locks.caseTypeName" class="big crm-form-text"/>
+ <input
+ type="text"
+ name="caseTypeName"
+ ng-model="caseType.name"
+ ng-disabled="locks.caseTypeName"
+ ng-pattern="/^[a-zA-Z0-9_]+$/"
+ required
+ class="big crm-form-text"/>
+
<a crm-ui-lock binding="locks.caseTypeName"></a>
</td>
</tr>
<tr>
- <td class="label">Description</td>
+ <td class="label">
+ <label crm-ui-label crm-for="description">
+ Description
+ </label>
+ </td>
<td>
- <textarea ng-model="caseType.description" class="big crm-form-textarea"></textarea>
+ <textarea name="description" ng-model="caseType.description" class="big crm-form-textarea"></textarea>
</td>
</tr>
<tr>
- <td class="label">Enabled?</td>
+ <td class="label">
+ <label crm-ui-label crm-for="is_active">
+ Enabled?
+ </label>
+ </td>
<td>
- <input type="checkbox" ng-model="caseType.is_active" ng-true-value="1" ng-false-value="0"/>
+ <input name="is_active" type="checkbox" ng-model="caseType.is_active" ng-true-value="1" ng-false-value="0"/>
</td>
</tr>
</tbody>