vendor: 4,424 bytes, lines 1-140
1/** 2 * Checklist-model 3 * AngularJS directive for list of checkboxes 4 * https://github.com/vitalets/checklist-model 5 * License: MIT http://opensource.org/licenses/MIT 6 */ 7 8angular.module('checklist-model', []) 9.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) { 10 // contains 11 function contains(arr, item, comparator) { 12 if (angular.isArray(arr)) { 13 for (var i = arr.length; i--;) { 14 if (comparator(arr[i], item)) { 15 return true; 16 } 17 } 18 } 19 return false; 20 } 21 22 // add 23 function add(arr, item, comparator) { 24 arr = angular.isArray(arr) ? arr : []; 25 if(!contains(arr, item, comparator)) { 26 arr.push(item); 27 } 28 return arr; 29 } 30 31 // remove 32 function remove(arr, item, comparator) { 33 if (angular.isArray(arr)) { 34 for (var i = arr.length; i--;) { 35 if (comparator(arr[i], item)) { 36 arr.splice(i, 1); 37 break; 38 } 39 } 40 } 41 return arr; 42 } 43 44 // http://stackoverflow.com/a/19228302/1458162 45 function postLinkFn(scope, elem, attrs) { 46 // exclude recursion, but still keep the model 47 var checklistModel = attrs.checklistModel; 48 attrs.$set("checklistModel", null); 49 // compile with `ng-model` pointing to `checked` 50 $compile(elem)(scope); 51 attrs.$set("checklistModel", checklistModel); 52 53 // getter for original model 54 var checklistModelGetter = $parse(checklistModel); 55 var checklistChange = $parse(attrs.checklistChange); 56 var checklistBeforeChange = $parse(attrs.checklistBeforeChange); 57 var ngModelGetter = $parse(attrs.ngModel); 58 59 60 61 var comparator = angular.equals; 62 63 if (attrs.hasOwnProperty('checklistComparator')){ 64 if (attrs.checklistComparator[0] == '.') { 65 var comparatorExpression = attrs.checklistComparator.substring(1); 66 comparator = function (a, b) { 67 return a[comparatorExpression] === b[comparatorExpression]; 68 }; 69 70 } else { 71 comparator = $parse(attrs.checklistComparator)(scope.$parent); 72 } 73 } 74 75 // watch UI checked change 76 scope.$watch(attrs.ngModel, function(newValue, oldValue) { 77 if (newValue === oldValue) { 78 return; 79 } 80 81 if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) { 82 ngModelGetter.assign(scope, contains(checklistModelGetter(scope.$parent), getChecklistValue(), comparator)); 83 return; 84 } 85 86 setValueInChecklistModel(getChecklistValue(), newValue); 87 88 if (checklistChange) { 89 checklistChange(scope); 90 } 91 }); 92 93 // watches for value change of checklistValue (Credit to @blingerson) 94 scope.$watch(getChecklistValue, function(newValue, oldValue) { 95 if( newValue != oldValue && angular.isDefined(oldValue) && scope[attrs.ngModel] === true ) { 96 var current = checklistModelGetter(scope.$parent); 97 checklistModelGetter.assign(scope.$parent, remove(current, oldValue, comparator)); 98 checklistModelGetter.assign(scope.$parent, add(current, newValue, comparator)); 99 } 100 }); 101 102 function getChecklistValue() { 103 return attrs.checklistValue ? $parse(attrs.checklistValue)(scope.$parent) : attrs.value; 104 } 105 106 function setValueInChecklistModel(value, checked) { 107 var current = checklistModelGetter(scope.$parent); 108 if (angular.isFunction(checklistModelGetter.assign)) { 109 if (checked === true) { 110 checklistModelGetter.assign(scope.$parent, add(current, value, comparator)); 111 } else { 112 checklistModelGetter.assign(scope.$parent, remove(current, value, comparator)); 113 } 114 } 115 116 } 117 118 // declare one function to be used for both $watch functions 119 function setChecked(newArr, oldArr) { 120 if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) { 121 setValueInChecklistModel(getChecklistValue(), ngModelGetter(scope)); 122 return; 123 } 124 ngModelGetter.assign(scope, contains(newArr, getChecklistValue(), comparator)); 125 } 126 127 // watch original model change 128 // use the faster $watchCollection method if it's available 129 if (angular.isFunction(scope.$parent.$watchCollection)) { 130 scope.$parent.$watchCollection(checklistModel, setChecked); 131 } else { 132 scope.$parent.$watch(checklistModel, setChecked, true); 133 } 134 } 135 136 return { 137 restrict: 'A', 138 priority: 1000, 139 terminal: true, 140 scope: true,
141 compile: function(tElement, tAttrs) { 142 143 if (!tAttrs.checklistValue && !tAttrs.value) { 144 throw 'You should provide `value` or `checklist-value`.'; 145 } 146 147 // by default ngModel is 'checked', so we set it if not specified 148 if (!tAttrs.ngModel) { 149 // local scope var storing individual checkbox model 150 tAttrs.$set("ngModel", "checked"); 151 } 152 153 return postLinkFn; 154 } 155 }; 156}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.