| 
									
										
										
										
											2017-10-04 16:27:36 -06:00
										 |  |  | angular.module('ui.multiselect', []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //from bootstrap-ui typeahead parser
 | 
					
						
							|  |  |  | .factory('optionParser', ['$parse', function ($parse) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     parse: function (input) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       var match = input.match(TYPEAHEAD_REGEXP), modelMapper, viewMapper, source; | 
					
						
							|  |  |  |       if (!match) { | 
					
						
							|  |  |  |         throw new Error( | 
					
						
							|  |  |  |           "Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_'" + | 
					
						
							|  |  |  |           " but got '" + input + "'."); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |           itemName: match[3], | 
					
						
							|  |  |  |           source: $parse(match[4]), | 
					
						
							|  |  |  |           viewMapper: $parse(match[2] || match[1]), | 
					
						
							|  |  |  |           modelMapper: $parse(match[1]) | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   .directive('multiselect', ['$parse', '$document', '$compile', 'optionParser', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function ($parse, $document, $compile, optionParser) { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       restrict: 'E', | 
					
						
							|  |  |  |       require: 'ngModel', | 
					
						
							|  |  |  |       link: function (originalScope, element, attrs, modelCtrl) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         var exp = attrs.options, | 
					
						
							|  |  |  |         parsedResult = optionParser.parse(exp), | 
					
						
							|  |  |  |         isMultiple = attrs.multiple ? true : false, | 
					
						
							|  |  |  |         required = false, | 
					
						
							|  |  |  |         scope = originalScope.$new(), | 
					
						
							|  |  |  |         changeHandler = attrs.change || anguler.noop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scope.items = []; | 
					
						
							|  |  |  |         scope.header = 'Select'; | 
					
						
							|  |  |  |         scope.multiple = isMultiple; | 
					
						
							|  |  |  |         scope.disabled = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         originalScope.$on('$destroy', function () { | 
					
						
							|  |  |  |           scope.$destroy(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         var popUpEl = angular.element('<multiselect-popup></multiselect-popup>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //required validator
 | 
					
						
							|  |  |  |         if (attrs.required || attrs.ngRequired) { | 
					
						
							|  |  |  |           required = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         attrs.$observe('required', function(newVal) { | 
					
						
							|  |  |  |           required = newVal; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //watch disabled state
 | 
					
						
							|  |  |  |         scope.$watch(function () { | 
					
						
							|  |  |  |           return $parse(attrs.disabled)(originalScope); | 
					
						
							|  |  |  |         }, function (newVal) { | 
					
						
							|  |  |  |           scope.disabled = newVal; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //watch single/multiple state for dynamically change single to multiple
 | 
					
						
							|  |  |  |         scope.$watch(function () { | 
					
						
							|  |  |  |           return $parse(attrs.multiple)(originalScope); | 
					
						
							|  |  |  |         }, function (newVal) { | 
					
						
							|  |  |  |           isMultiple = newVal || false; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //watch option changes for options that are populated dynamically
 | 
					
						
							|  |  |  |         scope.$watch(function () { | 
					
						
							|  |  |  |           return parsedResult.source(originalScope); | 
					
						
							|  |  |  |         }, function (newVal) { | 
					
						
							|  |  |  |           if (angular.isDefined(newVal)) | 
					
						
							|  |  |  |           parseModel(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //watch model change
 | 
					
						
							|  |  |  |         scope.$watch(function () { | 
					
						
							|  |  |  |           return modelCtrl.$modelValue; | 
					
						
							|  |  |  |         }, function (newVal, oldVal) { | 
					
						
							|  |  |  |           //when directive initialize, newVal usually undefined. Also, if model value already set in the controller
 | 
					
						
							|  |  |  |           //for preselected list then we need to mark checked in our scope item. But we don't want to do this every time
 | 
					
						
							|  |  |  |           //model changes. We need to do this only if it is done outside directive scope, from controller, for example.
 | 
					
						
							|  |  |  |           if (angular.isDefined(newVal)) { | 
					
						
							|  |  |  |             markChecked(newVal); | 
					
						
							|  |  |  |             scope.$eval(changeHandler); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           getHeaderText(); | 
					
						
							|  |  |  |           modelCtrl.$setValidity('required', scope.valid()); | 
					
						
							|  |  |  |         }, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function parseModel() { | 
					
						
							|  |  |  |           scope.items.length = 0; | 
					
						
							|  |  |  |           var model = parsedResult.source(originalScope); | 
					
						
							|  |  |  |           for (var i = 0; i < model.length; i++) { | 
					
						
							|  |  |  |             var local = {}; | 
					
						
							|  |  |  |             local[parsedResult.itemName] = model[i]; | 
					
						
							|  |  |  |             scope.items.push({ | 
					
						
							|  |  |  |               label: parsedResult.viewMapper(local), | 
					
						
							|  |  |  |               model: model[i], | 
					
						
							|  |  |  |               checked: false | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         parseModel(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         element.append($compile(popUpEl)(scope)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function getHeaderText() { | 
					
						
							|  |  |  |           var edit = "edit"; | 
					
						
							|  |  |  |           if (!modelCtrl.$modelValue || !modelCtrl.$modelValue.length) return scope.header = 'Can ' + edit; | 
					
						
							|  |  |  |           if (isMultiple) { | 
					
						
							|  |  |  |             edit = ''; | 
					
						
							|  |  |  |             var accessLevelArray = []; | 
					
						
							|  |  |  |             modelCtrl.$modelValue.forEach(function(level) { | 
					
						
							|  |  |  |               accessLevelArray.push(level.name); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |             scope.header = "Can " + accessLevelArray.join(', '); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             var local = {}; | 
					
						
							|  |  |  |             local[parsedResult.itemName] = modelCtrl.$modelValue; | 
					
						
							|  |  |  |             scope.header = parsedResult.viewMapper(local); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scope.valid = function validModel() { | 
					
						
							|  |  |  |           if(!required) return true; | 
					
						
							|  |  |  |           var value = modelCtrl.$modelValue; | 
					
						
							|  |  |  |           return (angular.isArray(value) && value.length > 0) || (!angular.isArray(value) && value != null); | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function selectSingle(item) { | 
					
						
							|  |  |  |           if (item.checked) { | 
					
						
							|  |  |  |             scope.uncheckAll(); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             scope.uncheckAll(); | 
					
						
							|  |  |  |             item.checked = !item.checked; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           setModelValue(false); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function selectMultiple(item) { | 
					
						
							|  |  |  |           item.checked = !item.checked; | 
					
						
							|  |  |  |           setModelValue(true); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function setModelValue(isMultiple) { | 
					
						
							|  |  |  |           var value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (isMultiple) { | 
					
						
							|  |  |  |             value = []; | 
					
						
							|  |  |  |             angular.forEach(scope.items, function (item) { | 
					
						
							|  |  |  |               if (item.checked) value.push(item.model); | 
					
						
							| 
									
										
										
										
											2017-10-05 13:01:05 -06:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2017-10-04 16:27:36 -06:00
										 |  |  |           } else { | 
					
						
							|  |  |  |             angular.forEach(scope.items, function (item) { | 
					
						
							|  |  |  |               if (item.checked) { | 
					
						
							|  |  |  |                 value = item.model; | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2017-10-05 13:01:05 -06:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2017-10-04 16:27:36 -06:00
										 |  |  |           } | 
					
						
							|  |  |  |           modelCtrl.$setViewValue(value); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function markChecked(newVal) { | 
					
						
							|  |  |  |           if (!angular.isArray(newVal)) { | 
					
						
							|  |  |  |             angular.forEach(scope.items, function (item) { | 
					
						
							|  |  |  |               if (angular.equals(item.model, newVal)) { | 
					
						
							|  |  |  |                 item.checked = true; | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             angular.forEach(newVal, function (i) { | 
					
						
							|  |  |  |               angular.forEach(scope.items, function (item) { | 
					
						
							|  |  |  |                 if (angular.equals(item.model, i)) { | 
					
						
							|  |  |  |                   item.checked = true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |               }); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scope.checkAll = function () { | 
					
						
							|  |  |  |           if (!isMultiple) return; | 
					
						
							|  |  |  |           angular.forEach(scope.items, function (item) { | 
					
						
							|  |  |  |             item.checked = true; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           setModelValue(true); | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scope.uncheckAll = function () { | 
					
						
							|  |  |  |           angular.forEach(scope.items, function (item) { | 
					
						
							|  |  |  |             item.checked = false; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           setModelValue(true); | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scope.select = function (item) { | 
					
						
							|  |  |  |           if (isMultiple === false) { | 
					
						
							|  |  |  |             selectSingle(item); | 
					
						
							|  |  |  |             scope.toggleSelect(); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             selectMultiple(item); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-10-05 13:01:05 -06:00
										 |  |  |         }; | 
					
						
							| 
									
										
										
										
											2017-10-04 16:27:36 -06:00
										 |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   .directive('multiselectPopup', ['$document', function ($document) { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       restrict: 'E', | 
					
						
							|  |  |  |       scope: false, | 
					
						
							|  |  |  |       replace: true, | 
					
						
							|  |  |  |       templateUrl: 'templates/widgets/share-access-multiselect.html', | 
					
						
							|  |  |  |       link: function (scope, element, attrs) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scope.isVisible = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scope.toggleSelect = function () { | 
					
						
							|  |  |  |           if (element.hasClass('open')) { | 
					
						
							|  |  |  |             element.removeClass('open'); | 
					
						
							|  |  |  |             $document.unbind('click', clickHandler); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             element.addClass('open'); | 
					
						
							|  |  |  |             scope.focus(); | 
					
						
							|  |  |  |             $document.bind('click', clickHandler); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function clickHandler(event) { | 
					
						
							|  |  |  |           if (elementMatchesAnyInArray(event.target, element.find(event.target.tagName))) | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |           element.removeClass('open'); | 
					
						
							|  |  |  |           $document.unbind('click', clickHandler); | 
					
						
							|  |  |  |           scope.$digest(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         scope.focus = function focus(){ | 
					
						
							|  |  |  |           var searchBox = element.find('input')[0]; | 
					
						
							|  |  |  |           searchBox.focus(); | 
					
						
							| 
									
										
										
										
											2017-10-05 13:01:05 -06:00
										 |  |  |         }; | 
					
						
							| 
									
										
										
										
											2017-10-04 16:27:36 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         var elementMatchesAnyInArray = function (element, elementArray) { | 
					
						
							|  |  |  |           for (var i = 0; i < elementArray.length; i++) | 
					
						
							|  |  |  |           if (element == elementArray[i]) | 
					
						
							|  |  |  |           return true; | 
					
						
							|  |  |  |           return false; | 
					
						
							| 
									
										
										
										
											2017-10-05 13:01:05 -06:00
										 |  |  |         }; | 
					
						
							| 
									
										
										
										
											2017-10-04 16:27:36 -06:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-10-05 13:01:05 -06:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-10-04 16:27:36 -06:00
										 |  |  |   }]); |