From c4e02e5d1658fcfe26e3d268fceaf5a74d72e1b5 Mon Sep 17 00:00:00 2001 From: Jo Jordan Date: Thu, 28 Oct 2021 04:04:43 -0700 Subject: [PATCH] remove console log --- dist/all.js | 2 -- dist/all.min.js | 2 +- dist/all.min.js.map | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dist/all.js b/dist/all.js index a8d31c2..7f10c3b 100644 --- a/dist/all.js +++ b/dist/all.js @@ -1268,7 +1268,6 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope if (options.tagsInput.bulkSingleRequest) { var request_config = JSON.parse(options.tagsInput.bulkSingleRequest); - console.log(request_config); return Api.post({ url: request_config.url, data: { @@ -1277,7 +1276,6 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope } }).then(function (response) { response.map(function (item) { - console.log(item); tagsInput.addTag(item); }); }); diff --git a/dist/all.min.js b/dist/all.min.js index e62e80f..bb70186 100644 --- a/dist/all.min.js +++ b/dist/all.min.js @@ -1,2 +1,2 @@ -"use strict";function _defineProperty(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};!function(){function e(e){_.forOwn(e,function(e,t,n){_.set(n,t,null)})}function t(){var t={};return{on:function(e,n){return e.split(" ").forEach(function(e){t[e]||(t[e]=[]),t[e].push(n)}),this},trigger:function(e,n){return angular.forEach(t[e],function(e){e.call(null,n)}),this},destroy:function(){e(t),t=null}}}function n(e,t,n){return e=e||[],e.length>0&&!angular.isObject(e[0])&&e.forEach(function(i,a){e[a]=_defineProperty({},t,i),n&&(e[a][n]=i)}),e}function i(e,t){return"object"===t.arrayValueType?(e||[]).map(function(e){return _.isObject(e&&e[t.valueProperty])?e[t.valueProperty]:e}):_.pluck(e,t.valueProperty)}function a(e,t,n){var i=null,a=0,s=e.length;if(_.isFunction(n)){var o=n(t);if(!o)return null;for(;a=t.minLength)&&(!t.maxLength||n.length<=t.maxLength)&&t.allowedTagsPattern.test(n)&&!a(r.items,e,t.valueProperty||i)},r.items=[],r.addText=function(e){var t={};s(t,e),r.add(t)},r.add=function(e){if(!e.disabled){var a=i(e);return a.trim&&(a=a.trim()),t.replaceSpacesWithDashes&&(a=a.replace(/\s/g,"-")),s(e,a),o(e)?(t.maxTags&&r.items.length>=t.maxTags&&(r.items.pop(),n.trigger("tag-removed",{$tag:e,$event:"tag-removed"})),r.items.push(e),n.trigger("tag-added",{$tag:e,$event:"tag-added"})):n.trigger("invalid-tag",{$tag:e,$event:"invalid-tag"}),e}},r.remove=function(e){var t=r.items.splice(e,1)[0];return n.trigger("tag-removed",{$tag:t,$event:"tag-removed"}),t},r.removeLast=function(){var e,n=r.items.length-1;return t.enableEditingLastTag||r.selected?(r.selected=null,e=r.remove(n)):r.selected||(r.selected=r.items[n]),e},r.removeAll=function(e){e.preventDefault();var t=r.items.splice(0,r.items.length);t.forEach(function(e){n.trigger("tag-removed",{$tag:e,$event:"tag-removed"})})},r.copyToClipboard=function(){var e=document.createElement("textarea");e.style.position="fixed",e.style.opacity="0",e.textContent=r.items.map(function(e){return t.displayProperty&&e[t.displayProperty]?e[t.displayProperty]:e}).join("\n");var n=document.getElementsByTagName("body")[0];n.appendChild(e),e.select(),document.execCommand("copy"),n.removeChild(e)},r.destroy=function(){e(r),r=null},r}return{restrict:"E",require:"ngModel",scope:{tags:"=ngModel",itemFormatter:"=",ngDisabled:"=",onBeforeTagAdded:"&",onBeforeTagRemoved:"&",onBeforeTagChanged:"&",onTagAdded:"&",onTagRemoved:"&",onTagChanged:"&",onInit:"&",newTag:"=?"},replace:!1,transclude:!0,templateUrl:"cnTagsInput/tags-input.html",controller:["$scope","$attrs","$element",function(n,i,a){function s(e){n.events.trigger("input-keydown",e)}l.load("tagsInput",n,i,{placeholder:[String,""],tabindex:[Number],removeTagSymbol:[String,String.fromCharCode(215)],replaceSpacesWithDashes:[Boolean,!1],minLength:[Number,2],maxLength:[Number],addOnEnter:[Boolean,!0],addOnSpace:[Boolean,!1],addOnComma:[Boolean,!0],addOnBlur:[Boolean,!1],clearOnBlur:[Boolean,!1],allowedTagsPattern:[RegExp,/.+/],enableEditingLastTag:[Boolean,!1],required:[Boolean,!1],minTags:[Number],maxTags:[Number],displayProperty:[String,"text"],valueProperty:[String],allowLeftoverText:[Boolean,!1],addFromAutocompleteOnly:[Boolean,!1],tagClass:[String,""],modelType:[String,"array"],arrayValueType:[String,"object"],hideTags:[Boolean,!1],dropdownIcon:[Boolean,!1],tagsStyle:[String,"tags"],allowBulk:[Boolean,!1],bulkSingleRequest:[String,""],bulkDelimiter:[RegExp,/, ?|\n/],bulkPlaceholder:[String,"Enter a list separated by commas or new lines"],sortFilteredResults:[Boolean,!1],showClearAll:[Boolean,!1],showClearCache:[Boolean,!1],showButton:[Boolean,!1]});var o=n.options,r=o.input=a.find("input.input");r.on("keydown",s),n.$on("$destroy",function(){r.off("keydown",s),r=null,e(o),o=null,n.events.destroy(),n.tagList.destroy(),n.processBulk=null}),o.valueProperty||/object|array/.test(o.modelType)&&"object"===o.arrayValueType||(o.valueProperty="value"),n.itemFormatter&&(o.itemFormatter=n.itemFormatter),"tags"===o.tagsStyle&&(o.tagClass=o.tagClass||"label-primary"),!o.allowBulk||"array"===o.modelType&&1!==o.maxTags||(o.allowBulk=!1),n.events=new t,n.tagList=new d(o,n.events),this.registerAutocomplete=function(){return{addTag:function(e){return n.tagList.add(e)},focusInput:function(){r[0].focus()},blurInput:function(){r[0].blur()},getTags:function(){return n.tagList.items},getModel:function(){return n.tags},getOptions:function(){return o},on:function(e,t){return n.events.on(e,t),this},registerProcessBulk:function(e){n.processBulk=function(){e(n.bulkTags).then(function(){n.showBulk=!1,n.bulkTags=""})}},registerSuggestionList:function(e){n.tagList.suggestionList=e}}}}],link:function(e,t,a,l){function c(){}function d(e,t){return function(){var n=arguments;e.apply(this,n),s(function(){t.apply(this,n)})}}function f(){return function(){if(arguments.length>0&&_.isArray(arguments[0].$tag)){var t=arguments[0].$tag,n=_.every(t,function(e){return"object"===("undefined"==typeof e?"undefined":_typeof(e))&&null!==e&&L.displayProperty&&e[L.displayProperty]});n&&e.tagList&&e.tagList.items&&t&&(e.tagList.items=t)}}}function m(t){if(!t.isImmediatePropagationStopped||!t.isImmediatePropagationStopped()){var n,i,a=t.keyCode,s=t.shiftKey||t.altKey||t.ctrlKey||t.metaKey,o={};if(!s&&w.indexOf(a)!==-1)if(o[p.enter]=L.addOnEnter,o[p.comma]=L.addOnComma,o[p.space]=L.addOnSpace,n=!L.addFromAutocompleteOnly&&o[a],i=!n&&a===p.backspace&&0===e.newTag.text.length,n)x.addText(e.newTag.text),e.$apply(),t.preventDefault();else if(i){var r=x.removeLast();r&&L.enableEditingLastTag&&(e.newTag.text=r[L.displayProperty]),e.$apply(),t.preventDefault()}}}function y(n){T=s(function(){if(!P)return!1;var i=r.prop("activeElement"),a=i===P[0],s=t.find(".host")[0].contains(i);!a&&s||(e.hasFocus=!1,k.trigger("input-blur",n))},150)}function h(t){t&&t.preventDefault(),e.ngDisabled||(g(t.target),T&&s.cancel(T),e.hasFocus=!0,k.trigger("input-focus",P.val()),/apply|digest/.test(e.$root.$$phase)||e.$apply())}function v(t){t.keyCode===p.enter&&(t.altKey||t.ctrlKey||t.metaKey||t.shiftKey||(t.preventDefault(),e.processBulk()))}function b(e){var t=$(e.target);t.closest(".suggestion").length||t.parent().hasClass("help-block")||(e.preventDefault(),P[0].focus())}e.__tag=new c;var T,w=[p.enter,p.comma,p.space,p.backspace],x=e.tagList,k=e.events,L=e.options,P=t.find("input.input"),I=t.find("textarea"),B=t.find("div");a.inputId&&!l.$name&&(l.$name=a.inputId),k.on("tag-added",d(e.onBeforeTagAdded,e.onTagAdded)).on("tag-removed",d(e.onBeforeTagRemoved,e.onTagRemoved)).on("tag-changed",d(e.onBeforeTagChanged,e.onTagChanged)).on("tag-changed",f()).on("tag-init",e.onInit).on("tag-added tag-removed",function(t){!L.maxTags||L.maxTags>e.tagList.items.length?g(L.input[0]):e.newTag.text="","array"===L.modelType?(L.valueProperty?e.tags=i(e.tagList.items,L):e.tags=e.tagList.items,e.tagList.items.length>=L.minTags&&l.$setValidity("tv4-400",!0)):"tag-removed"===t.$event?e.tags=void 0:L.valueProperty?e.tags=_.has(t.$tag,L.valueProperty)?t.$tag[L.valueProperty]:t.$tag[L.displayProperty]:e.tags=t.$tag}).on("invalid-tag",function(){e.newTag.invalid=!0}).on("input-change",function(){x.selected=null,e.newTag.invalid=null}).on("input-focus",function(){l.$setValidity("leftoverText",!0)}).on("input-blur",function(){L.addFromAutocompleteOnly||L.addOnBlur&&e.newTag.text&&x.addText(e.newTag.text),L.clearOnBlur&&(e.newTag.text="",e.newTag.invalid=null)}),e.newTag={text:"",invalid:null},e.getDisplayText=e.itemFormatter||function(e){return e&&((e[L.displayProperty]||"undefined")+"").trim()},e.getDisplayHtml=function(t){return u.trustAsHtml(e.getDisplayText(t))},e.track=function(e){return e[L.displayProperty]},e.newTagChange=function(){k.trigger("input-change",e.newTag.text)},e.processBulk=e.processBulk||function(){var t=e.bulkTags.split(L.bulkDelimiter);_.each(t,function(t){var n={};n[L.displayProperty]=t,e.tagList.add(n)}),e.showBulk=!1,e.bulkTags=""};var S=!0;e.triggerInit=function(e,t){var n=L.valueProperty?_defineProperty({},L.valueProperty,e):e;x.items.length&&_.find(x.items,n)||k.trigger("tag-init",{$tag:e,$prev:t,$event:"tag-init",$setter:function(e){if(e&&!_.isObject(e)){var t;x.items=[(t={},_defineProperty(t,L.displayProperty,e),_defineProperty(t,L.valueProperty,e),t)]}else x.items=_.isArray(e)?e:[e];return x.items}})},e.$watch("tags",function(t,a){var s=!angular.equals(t,a),r=!s&&S;if(r&&e.triggerInit(t,a),s&&k.trigger("tag-changed",{$tag:t,$prev:a,$event:"tag-changed"}),"array"===L.modelType){if(_.isArray(t)){if(t.length){if(o(x.items,e.tags,L)||e.triggerInit(t,a),!o(x.items,e.tags,L)||x.items.length!==e.tags.length)return x.items=n(t,L.displayProperty,L.valueProperty),void(e.tags=i(x.items,L))}else if(x.items=[],angular.isUndefined(a))return}else if(void 0===t)return x.items=[],void(e.tags=[])}else if(angular.isDefined(t))if(_.isArray(t)){if(t.length)return void(L.valueProperty?e.tags=t[0][L.valueProperty]:e.tags=t[0]);e.tags=void 0}else if("object"===L.modelType)null!==t&&(x.items=[t]);else{if(_.isObject(t)){x.items=[t];var u=t[L.valueProperty];return _.isUndefined(u)&&(u=t[L.displayProperty]),void(e.tags=u)}_.isUndefined(t)||x.items.length&&x.items[0][L.valueProperty]===t||e.triggerInit(t,a)}else!t&&x.items.length&&(x.items=[]);!r&&s&&l.$setDirty(),l.$setValidity("schemaForm",!0),"array"===L.modelType?(l.$setValidity("tv4-401",!t||!L.maxTags||t.length<=L.maxTags),l.$setValidity("tv4-302",!!t&&(!angular.isDefined(L.minTags)||t.length>=L.minTags))):l.$setValidity("tv4-302",!L.required||!angular.isUndefined(t)),S=!1},!0);var C=s(function(){P.on("keydown",m).on("focus",h).on("blur",y)});I.on("keydown",v),B.on("click",b),e.$on("$destroy",function(){P.off("keydown",m).off("focus",h).off("blur",y),I.off("keydown",v),B.off("click",b),P=null,I=null,B=null,k.destroy(),k=null,S=null,w=null,L=null,x=null,s.cancel(C)})}}}]),d.directive("autoComplete",["$document","$timeout","$filter","$sce","tagsInputConfig","$parse","Api","$q",function(t,i,o,l,u,g,d,f){function m(e,t){var s,r,l,u,p,d,m,y={};return u=function(e,t){var n,i={},a=[],s=0;return _.each(e,function(e){n=g(t)(e),_.isArray(n)||(n=[n]),_.each(n,function(t){i[t]||(i[t]=[]),i[t].push(e)})}),_.each(i,function(e){e.indexes=[],_.each(e,function(t){e.indexes.push(s++),a.push(t)})}),{groups:i,map:a}},d=function(e,t){return t?(_.isArray(t)||(t=[t,{}]),g(t[0])((t[1].val=e)&&t[1])):e},p=function(n){function i(e,n,i,a){var s=_.isObject(n)?n[a||t.tagsInput.displayProperty]:n,o={text:d(s,i.formatter),value:s,key:e,childKey:a};_.find(i.items,o)||i.items.push(o)}var a=[];return _.each(e.searchKeys,function(e){var t=e.key;e.items=[],_.each(n,function(n){n[t]&&(_.isArray(n[t])?_.each(n[t],function(n){i(t,n,e,e.childKey)}):i(t,n[t],e,e.childKey))}),a.push(e)}),a},m=function(e){var t=[],n=0;return _.each(e,function(e){e.indexes=[],_.each(e.items,function(i){e.indexes.push(n++),t.push(i)})}),t},r=function(e,n){return n.length?e.filter(function(e){return!a(n,e,t.tagsInput.valueProperty||t.tagsInput.getTagText)}):e.filter(function(e){return""!==e[t.tagsInput.displayProperty]})},y.reset=function(){l=null,y.items=[],y.visible=!1,y.index=-1,y.selected=null,y.query=null,i.cancel(s)},y.show=function(){y.selected=null,y.visible=!0,y.select(0)},y.load=function(a,g){if(a.length=t.length&&(e=0),y.index=e,y.itemMap?y.selected=y.itemMap[e]:y.selected=y.items[e]},y}return{restrict:"E",require:"^tagsInput",scope:{source:"&",searchKeys:"=?"},templateUrl:function(e,t){return t.customTemplateUrl||"cnTagsInput/auto-complete.html"},link:function(n,i,a,g){function f(){}var y,h,v,b,T,w=[p.enter,p.tab,p.escape,p.up,p.down];n.__tag=new f,u.load("autoComplete",n,a,{debounceDelay:[Number,250],minLength:[Number,3],singleQuery:[Boolean,!1],highlightMatchedText:[Boolean,!0],maxResultsToShow:[Number,75],groupBy:[String,""],skipFiltering:[Boolean,!1]}),v=n.options,h=g.registerAutocomplete(),n.tagsInput=h,v.tagsInput=h.getOptions(),0===v.minLength?(v.tagsInput.dropdownIcon=!0,1===v.tagsInput.maxTags?v.tagsInput.dropdownStyle="caret":v.tagsInput.dropdownStyle="fa fa-plus"):v.tagsInput.dropdownStyle="fa fa-search",y=new m(n,v),h.registerSuggestionList(y),b=v.tagsInput.itemFormatter||function(e){return String(e[v.tagsInput.displayProperty])},n.suggestionList=y;var x=h.getModel();v.singleQuery&&x&&!angular.equals(x,[])&&y._load().then(function(e){var t=r(e,x,v.tagsInput),n=h.getTags();angular.equals(t,n)||(n.length=0,t.forEach(function(e){return h.addTag(e)}))}),n.addSuggestion=function(e){e.preventDefault();var t=!1;if(y.selected){if(h.addTag(angular.copy(y.selected)),!v.tagsInput.maxTags||h.getTags().length]*>|[^<]*)/g)).map(function(e){return e.length&&"<"!==e[0]?s(e,y.query,"$&"):e}).join("")),l.trustAsHtml(""+n+"")},n.track=function(e,t){return b(e,t)},n.noResultsMessage=function(e){var t=(e.visible,e.query);return t?l.trustAsHtml("No results for "+t+"..."):"No options..."},h.registerProcessBulk(function(e){var t=e.split(v.tagsInput.bulkDelimiter),i=function(e){return function(t){_.times(e,function(e){t[e]&&h.addTag(t[e])})}};if(v.tagsInput.bulkSingleRequest){var a=JSON.parse(v.tagsInput.bulkSingleRequest);return console.log(a),d.post({url:a.url,data:{location_types:a.location_types,terms:t}}).then(function(e){e.map(function(e){console.log(e),h.addTag(e)})})}return d.batch(function(){for(var e=0,a=t.length;e=v.tagsInput.maxTags);e++){var s=t[e],r=1,l=t[e].match(/(.*) ?\[(\d+)\]$/);l&&(s=l[1],r=parseInt(l[2]));var u=n.source({$query:s});if(_.isArray(u)){if(u.length){if(!v.skipFiltering){var g=s;u=o("cnFilter")(u,g)}v.tagsInput.sortFilteredResults&&(u=c(u,s,v.tagsInput.displayProperty)),i(r)(u)}else if(!v.tagsInput.addFromAutocompleteOnly){var p;h.addTag((p={},_defineProperty(p,v.tagsInput.displayProperty,s),_defineProperty(p,v.tagsInput.valueProperty,s),p))}}else u.then&&u.then(i(r))}})}),h.on("input-change",function(e){e||!v.minLength?y.load(e,h.getTags()):y.reset()}).on("input-focus",function(e){y.visible||y.load(e,h.getTags())}).on("input-keydown",function(e){var t,i;if(w.indexOf(e.keyCode)!==-1){var a=!1;e.stopImmediatePropagation=function(){a=!0,e.stopPropagation()},e.isImmediatePropagationStopped=function(){return a},y.visible&&(t=e.keyCode,i=!1,t===p.down?(y.selectNext(),i=!0):t===p.up?(y.selectPrior(),i=!0):t===p.escape?(y.reset(),i=!0):t===p.enter&&(i=n.addSuggestion(e)),i&&(e.preventDefault(),e.stopImmediatePropagation(),n.$apply()))}}).on("input-blur",function(e){y.reset()}),T=function(e){e.isDefaultPrevented()||y.visible&&(!$(e.target).closest(".suggestion").length&&$(e.target).closest(i[0]).length||"blur"===e.type&&!/^(input|select|textarea|button|a)$/i.test(e.target.tagName)||(y.reset(),/apply|digest/.test(n.$root.$$phase)||n.$apply()))},t.on("click",T).on("blur",T),n.$on("$destroy",function(){t.off("click",T).off("blur",T),e(h),h=null,e(v),v=null})}}}]),d.directive("tiTranscludeAppend",function(){return function(e,t,n,i,a){a(function(e){t.append(e)})}}),d.directive("tiAutosize",function(){return{restrict:"A",require:"ngModel",link:function(e,t,n,i){var a,s,o=3;a=angular.element(''),a.css("display","none").css("visibility","hidden").css("width","auto").css("white-space","pre"),t.parent().append(a),s=function(e){var i,s=e;return angular.isString(s)&&0===s.length&&(s=n.placeholder),s&&(a.text(s),a.css("display",""),i=a.prop("offsetWidth"),a.css("display","none")),t.css("width",i?i+o+"px":""),e},i.$parsers.unshift(s),i.$formatters.unshift(s),n.$observe("placeholder",function(e){i.$modelValue||s(e)})}}}),d.provider("tagsInputConfig",function(){var e={},t={};this.setDefaults=function(t,n){return e[t]=n,this},this.setActiveInterpolation=function(e,n){return t[e]=n,this},this.$get=["$interpolate",function(n){var i={};return i[String]=function(e){return e},i[Number]=function(e){return parseInt(e,10)},i[Boolean]=function(e){return"true"===e.toLowerCase()},i[RegExp]=function(e){return new RegExp(e)},i[Object]=function(e){return"object"===("undefined"==typeof e?"undefined":_typeof(e))?e:Object(e)},{load:function(a,s,o,r){s.options={},s.attrs=o,s.uid=_.uniqueId(),angular.forEach(r,function(r,l){var u,g,c,p,d;u=r[0],g=r[1],c=i[u],p=function(){var t=e[a]&&e[a][l];return angular.isDefined(t)?t:g},d=function(e){s.options[l]=e?c(e):p()},s[l]?d(s[l]):t[a]&&t[a][l]?o.$observe(l,function(e){d(e)}):d(o[l]&&n(o[l])(s.$parent))})}}}]}),d.run(["$templateCache",function(e){e.put("cnTagsInput/tags-input.html",'\n
    \n
  • \n \n \n
  • \n
\n
\n \n \n \n
\n \n \n \n \n ×\n \n \n \n \n
\n
\n
\n Batch\n \n Clear\n \n Update Data\n \n Copy\n \n
\n
\n \n

\n Press "Enter" to submit, "Shift+Enter" to add a new line\n

\n

\n Add multiple with brackets, eg. "citizennet[10]"\n

\n
\n \n
\n
'),e.put("cnTagsInput/auto-complete.html",'\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
')}])}(); +"use strict";function _defineProperty(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};!function(){function t(t){_.forOwn(t,function(t,e,n){_.set(n,e,null)})}function e(){var e={};return{on:function(t,n){return t.split(" ").forEach(function(t){e[t]||(e[t]=[]),e[t].push(n)}),this},trigger:function(t,n){return angular.forEach(e[t],function(t){t.call(null,n)}),this},destroy:function(){t(e),e=null}}}function n(t,e,n){return t=t||[],t.length>0&&!angular.isObject(t[0])&&t.forEach(function(i,a){t[a]=_defineProperty({},e,i),n&&(t[a][n]=i)}),t}function i(t,e){return"object"===e.arrayValueType?(t||[]).map(function(t){return _.isObject(t&&t[e.valueProperty])?t[e.valueProperty]:t}):_.pluck(t,e.valueProperty)}function a(t,e,n){var i=null,a=0,s=t.length;if(_.isFunction(n)){var o=n(e);if(!o)return null;for(;a=e.minLength)&&(!e.maxLength||n.length<=e.maxLength)&&e.allowedTagsPattern.test(n)&&!a(r.items,t,e.valueProperty||i)},r.items=[],r.addText=function(t){var e={};s(e,t),r.add(e)},r.add=function(t){if(!t.disabled){var a=i(t);return a.trim&&(a=a.trim()),e.replaceSpacesWithDashes&&(a=a.replace(/\s/g,"-")),s(t,a),o(t)?(e.maxTags&&r.items.length>=e.maxTags&&(r.items.pop(),n.trigger("tag-removed",{$tag:t,$event:"tag-removed"})),r.items.push(t),n.trigger("tag-added",{$tag:t,$event:"tag-added"})):n.trigger("invalid-tag",{$tag:t,$event:"invalid-tag"}),t}},r.remove=function(t){var e=r.items.splice(t,1)[0];return n.trigger("tag-removed",{$tag:e,$event:"tag-removed"}),e},r.removeLast=function(){var t,n=r.items.length-1;return e.enableEditingLastTag||r.selected?(r.selected=null,t=r.remove(n)):r.selected||(r.selected=r.items[n]),t},r.removeAll=function(t){t.preventDefault();var e=r.items.splice(0,r.items.length);e.forEach(function(t){n.trigger("tag-removed",{$tag:t,$event:"tag-removed"})})},r.copyToClipboard=function(){var t=document.createElement("textarea");t.style.position="fixed",t.style.opacity="0",t.textContent=r.items.map(function(t){return e.displayProperty&&t[e.displayProperty]?t[e.displayProperty]:t}).join("\n");var n=document.getElementsByTagName("body")[0];n.appendChild(t),t.select(),document.execCommand("copy"),n.removeChild(t)},r.destroy=function(){t(r),r=null},r}return{restrict:"E",require:"ngModel",scope:{tags:"=ngModel",itemFormatter:"=",ngDisabled:"=",onBeforeTagAdded:"&",onBeforeTagRemoved:"&",onBeforeTagChanged:"&",onTagAdded:"&",onTagRemoved:"&",onTagChanged:"&",onInit:"&",newTag:"=?"},replace:!1,transclude:!0,templateUrl:"cnTagsInput/tags-input.html",controller:["$scope","$attrs","$element",function(n,i,a){function s(t){n.events.trigger("input-keydown",t)}l.load("tagsInput",n,i,{placeholder:[String,""],tabindex:[Number],removeTagSymbol:[String,String.fromCharCode(215)],replaceSpacesWithDashes:[Boolean,!1],minLength:[Number,2],maxLength:[Number],addOnEnter:[Boolean,!0],addOnSpace:[Boolean,!1],addOnComma:[Boolean,!0],addOnBlur:[Boolean,!1],clearOnBlur:[Boolean,!1],allowedTagsPattern:[RegExp,/.+/],enableEditingLastTag:[Boolean,!1],required:[Boolean,!1],minTags:[Number],maxTags:[Number],displayProperty:[String,"text"],valueProperty:[String],allowLeftoverText:[Boolean,!1],addFromAutocompleteOnly:[Boolean,!1],tagClass:[String,""],modelType:[String,"array"],arrayValueType:[String,"object"],hideTags:[Boolean,!1],dropdownIcon:[Boolean,!1],tagsStyle:[String,"tags"],allowBulk:[Boolean,!1],bulkSingleRequest:[String,""],bulkDelimiter:[RegExp,/, ?|\n/],bulkPlaceholder:[String,"Enter a list separated by commas or new lines"],sortFilteredResults:[Boolean,!1],showClearAll:[Boolean,!1],showClearCache:[Boolean,!1],showButton:[Boolean,!1]});var o=n.options,r=o.input=a.find("input.input");r.on("keydown",s),n.$on("$destroy",function(){r.off("keydown",s),r=null,t(o),o=null,n.events.destroy(),n.tagList.destroy(),n.processBulk=null}),o.valueProperty||/object|array/.test(o.modelType)&&"object"===o.arrayValueType||(o.valueProperty="value"),n.itemFormatter&&(o.itemFormatter=n.itemFormatter),"tags"===o.tagsStyle&&(o.tagClass=o.tagClass||"label-primary"),!o.allowBulk||"array"===o.modelType&&1!==o.maxTags||(o.allowBulk=!1),n.events=new e,n.tagList=new d(o,n.events),this.registerAutocomplete=function(){return{addTag:function(t){return n.tagList.add(t)},focusInput:function(){r[0].focus()},blurInput:function(){r[0].blur()},getTags:function(){return n.tagList.items},getModel:function(){return n.tags},getOptions:function(){return o},on:function(t,e){return n.events.on(t,e),this},registerProcessBulk:function(t){n.processBulk=function(){t(n.bulkTags).then(function(){n.showBulk=!1,n.bulkTags=""})}},registerSuggestionList:function(t){n.tagList.suggestionList=t}}}}],link:function(t,e,a,l){function c(){}function d(t,e){return function(){var n=arguments;t.apply(this,n),s(function(){e.apply(this,n)})}}function f(){return function(){if(arguments.length>0&&_.isArray(arguments[0].$tag)){var e=arguments[0].$tag,n=_.every(e,function(t){return"object"===("undefined"==typeof t?"undefined":_typeof(t))&&null!==t&&L.displayProperty&&t[L.displayProperty]});n&&t.tagList&&t.tagList.items&&e&&(t.tagList.items=e)}}}function m(e){if(!e.isImmediatePropagationStopped||!e.isImmediatePropagationStopped()){var n,i,a=e.keyCode,s=e.shiftKey||e.altKey||e.ctrlKey||e.metaKey,o={};if(!s&&w.indexOf(a)!==-1)if(o[p.enter]=L.addOnEnter,o[p.comma]=L.addOnComma,o[p.space]=L.addOnSpace,n=!L.addFromAutocompleteOnly&&o[a],i=!n&&a===p.backspace&&0===t.newTag.text.length,n)x.addText(t.newTag.text),t.$apply(),e.preventDefault();else if(i){var r=x.removeLast();r&&L.enableEditingLastTag&&(t.newTag.text=r[L.displayProperty]),t.$apply(),e.preventDefault()}}}function y(n){T=s(function(){if(!P)return!1;var i=r.prop("activeElement"),a=i===P[0],s=e.find(".host")[0].contains(i);!a&&s||(t.hasFocus=!1,k.trigger("input-blur",n))},150)}function h(e){e&&e.preventDefault(),t.ngDisabled||(g(e.target),T&&s.cancel(T),t.hasFocus=!0,k.trigger("input-focus",P.val()),/apply|digest/.test(t.$root.$$phase)||t.$apply())}function v(e){e.keyCode===p.enter&&(e.altKey||e.ctrlKey||e.metaKey||e.shiftKey||(e.preventDefault(),t.processBulk()))}function b(t){var e=$(t.target);e.closest(".suggestion").length||e.parent().hasClass("help-block")||(t.preventDefault(),P[0].focus())}t.__tag=new c;var T,w=[p.enter,p.comma,p.space,p.backspace],x=t.tagList,k=t.events,L=t.options,P=e.find("input.input"),I=e.find("textarea"),B=e.find("div");a.inputId&&!l.$name&&(l.$name=a.inputId),k.on("tag-added",d(t.onBeforeTagAdded,t.onTagAdded)).on("tag-removed",d(t.onBeforeTagRemoved,t.onTagRemoved)).on("tag-changed",d(t.onBeforeTagChanged,t.onTagChanged)).on("tag-changed",f()).on("tag-init",t.onInit).on("tag-added tag-removed",function(e){!L.maxTags||L.maxTags>t.tagList.items.length?g(L.input[0]):t.newTag.text="","array"===L.modelType?(L.valueProperty?t.tags=i(t.tagList.items,L):t.tags=t.tagList.items,t.tagList.items.length>=L.minTags&&l.$setValidity("tv4-400",!0)):"tag-removed"===e.$event?t.tags=void 0:L.valueProperty?t.tags=_.has(e.$tag,L.valueProperty)?e.$tag[L.valueProperty]:e.$tag[L.displayProperty]:t.tags=e.$tag}).on("invalid-tag",function(){t.newTag.invalid=!0}).on("input-change",function(){x.selected=null,t.newTag.invalid=null}).on("input-focus",function(){l.$setValidity("leftoverText",!0)}).on("input-blur",function(){L.addFromAutocompleteOnly||L.addOnBlur&&t.newTag.text&&x.addText(t.newTag.text),L.clearOnBlur&&(t.newTag.text="",t.newTag.invalid=null)}),t.newTag={text:"",invalid:null},t.getDisplayText=t.itemFormatter||function(t){return t&&((t[L.displayProperty]||"undefined")+"").trim()},t.getDisplayHtml=function(e){return u.trustAsHtml(t.getDisplayText(e))},t.track=function(t){return t[L.displayProperty]},t.newTagChange=function(){k.trigger("input-change",t.newTag.text)},t.processBulk=t.processBulk||function(){var e=t.bulkTags.split(L.bulkDelimiter);_.each(e,function(e){var n={};n[L.displayProperty]=e,t.tagList.add(n)}),t.showBulk=!1,t.bulkTags=""};var S=!0;t.triggerInit=function(t,e){var n=L.valueProperty?_defineProperty({},L.valueProperty,t):t;x.items.length&&_.find(x.items,n)||k.trigger("tag-init",{$tag:t,$prev:e,$event:"tag-init",$setter:function(t){if(t&&!_.isObject(t)){var e;x.items=[(e={},_defineProperty(e,L.displayProperty,t),_defineProperty(e,L.valueProperty,t),e)]}else x.items=_.isArray(t)?t:[t];return x.items}})},t.$watch("tags",function(e,a){var s=!angular.equals(e,a),r=!s&&S;if(r&&t.triggerInit(e,a),s&&k.trigger("tag-changed",{$tag:e,$prev:a,$event:"tag-changed"}),"array"===L.modelType){if(_.isArray(e)){if(e.length){if(o(x.items,t.tags,L)||t.triggerInit(e,a),!o(x.items,t.tags,L)||x.items.length!==t.tags.length)return x.items=n(e,L.displayProperty,L.valueProperty),void(t.tags=i(x.items,L))}else if(x.items=[],angular.isUndefined(a))return}else if(void 0===e)return x.items=[],void(t.tags=[])}else if(angular.isDefined(e))if(_.isArray(e)){if(e.length)return void(L.valueProperty?t.tags=e[0][L.valueProperty]:t.tags=e[0]);t.tags=void 0}else if("object"===L.modelType)null!==e&&(x.items=[e]);else{if(_.isObject(e)){x.items=[e];var u=e[L.valueProperty];return _.isUndefined(u)&&(u=e[L.displayProperty]),void(t.tags=u)}_.isUndefined(e)||x.items.length&&x.items[0][L.valueProperty]===e||t.triggerInit(e,a)}else!e&&x.items.length&&(x.items=[]);!r&&s&&l.$setDirty(),l.$setValidity("schemaForm",!0),"array"===L.modelType?(l.$setValidity("tv4-401",!e||!L.maxTags||e.length<=L.maxTags),l.$setValidity("tv4-302",!!e&&(!angular.isDefined(L.minTags)||e.length>=L.minTags))):l.$setValidity("tv4-302",!L.required||!angular.isUndefined(e)),S=!1},!0);var C=s(function(){P.on("keydown",m).on("focus",h).on("blur",y)});I.on("keydown",v),B.on("click",b),t.$on("$destroy",function(){P.off("keydown",m).off("focus",h).off("blur",y),I.off("keydown",v),B.off("click",b),P=null,I=null,B=null,k.destroy(),k=null,S=null,w=null,L=null,x=null,s.cancel(C)})}}}]),d.directive("autoComplete",["$document","$timeout","$filter","$sce","tagsInputConfig","$parse","Api","$q",function(e,i,o,l,u,g,d,f){function m(t,e){var s,r,l,u,p,d,m,y={};return u=function(t,e){var n,i={},a=[],s=0;return _.each(t,function(t){n=g(e)(t),_.isArray(n)||(n=[n]),_.each(n,function(e){i[e]||(i[e]=[]),i[e].push(t)})}),_.each(i,function(t){t.indexes=[],_.each(t,function(e){t.indexes.push(s++),a.push(e)})}),{groups:i,map:a}},d=function(t,e){return e?(_.isArray(e)||(e=[e,{}]),g(e[0])((e[1].val=t)&&e[1])):t},p=function(n){function i(t,n,i,a){var s=_.isObject(n)?n[a||e.tagsInput.displayProperty]:n,o={text:d(s,i.formatter),value:s,key:t,childKey:a};_.find(i.items,o)||i.items.push(o)}var a=[];return _.each(t.searchKeys,function(t){var e=t.key;t.items=[],_.each(n,function(n){n[e]&&(_.isArray(n[e])?_.each(n[e],function(n){i(e,n,t,t.childKey)}):i(e,n[e],t,t.childKey))}),a.push(t)}),a},m=function(t){var e=[],n=0;return _.each(t,function(t){t.indexes=[],_.each(t.items,function(i){t.indexes.push(n++),e.push(i)})}),e},r=function(t,n){return n.length?t.filter(function(t){return!a(n,t,e.tagsInput.valueProperty||e.tagsInput.getTagText)}):t.filter(function(t){return""!==t[e.tagsInput.displayProperty]})},y.reset=function(){l=null,y.items=[],y.visible=!1,y.index=-1,y.selected=null,y.query=null,i.cancel(s)},y.show=function(){y.selected=null,y.visible=!0,y.select(0)},y.load=function(a,g){if(a.length=e.length&&(t=0),y.index=t,y.itemMap?y.selected=y.itemMap[t]:y.selected=y.items[t]},y}return{restrict:"E",require:"^tagsInput",scope:{source:"&",searchKeys:"=?"},templateUrl:function(t,e){return e.customTemplateUrl||"cnTagsInput/auto-complete.html"},link:function(n,i,a,g){function f(){}var y,h,v,b,T,w=[p.enter,p.tab,p.escape,p.up,p.down];n.__tag=new f,u.load("autoComplete",n,a,{debounceDelay:[Number,250],minLength:[Number,3],singleQuery:[Boolean,!1],highlightMatchedText:[Boolean,!0],maxResultsToShow:[Number,75],groupBy:[String,""],skipFiltering:[Boolean,!1]}),v=n.options,h=g.registerAutocomplete(),n.tagsInput=h,v.tagsInput=h.getOptions(),0===v.minLength?(v.tagsInput.dropdownIcon=!0,1===v.tagsInput.maxTags?v.tagsInput.dropdownStyle="caret":v.tagsInput.dropdownStyle="fa fa-plus"):v.tagsInput.dropdownStyle="fa fa-search",y=new m(n,v),h.registerSuggestionList(y),b=v.tagsInput.itemFormatter||function(t){return String(t[v.tagsInput.displayProperty])},n.suggestionList=y;var x=h.getModel();v.singleQuery&&x&&!angular.equals(x,[])&&y._load().then(function(t){var e=r(t,x,v.tagsInput),n=h.getTags();angular.equals(e,n)||(n.length=0,e.forEach(function(t){return h.addTag(t)}))}),n.addSuggestion=function(t){t.preventDefault();var e=!1;if(y.selected){if(h.addTag(angular.copy(y.selected)),!v.tagsInput.maxTags||h.getTags().length]*>|[^<]*)/g)).map(function(t){return t.length&&"<"!==t[0]?s(t,y.query,"$&"):t}).join("")),l.trustAsHtml(""+n+"")},n.track=function(t,e){return b(t,e)},n.noResultsMessage=function(t){var e=(t.visible,t.query);return e?l.trustAsHtml("No results for "+e+"..."):"No options..."},h.registerProcessBulk(function(t){var e=t.split(v.tagsInput.bulkDelimiter),i=function(t){return function(e){_.times(t,function(t){e[t]&&h.addTag(e[t])})}};if(v.tagsInput.bulkSingleRequest){var a=JSON.parse(v.tagsInput.bulkSingleRequest);return d.post({url:a.url,data:{location_types:a.location_types,terms:e}}).then(function(t){t.map(function(t){h.addTag(t)})})}return d.batch(function(){for(var t=0,a=e.length;t=v.tagsInput.maxTags);t++){var s=e[t],r=1,l=e[t].match(/(.*) ?\[(\d+)\]$/);l&&(s=l[1],r=parseInt(l[2]));var u=n.source({$query:s});if(_.isArray(u)){if(u.length){if(!v.skipFiltering){var g=s;u=o("cnFilter")(u,g)}v.tagsInput.sortFilteredResults&&(u=c(u,s,v.tagsInput.displayProperty)),i(r)(u)}else if(!v.tagsInput.addFromAutocompleteOnly){var p;h.addTag((p={},_defineProperty(p,v.tagsInput.displayProperty,s),_defineProperty(p,v.tagsInput.valueProperty,s),p))}}else u.then&&u.then(i(r))}})}),h.on("input-change",function(t){t||!v.minLength?y.load(t,h.getTags()):y.reset()}).on("input-focus",function(t){y.visible||y.load(t,h.getTags())}).on("input-keydown",function(t){var e,i;if(w.indexOf(t.keyCode)!==-1){var a=!1;t.stopImmediatePropagation=function(){a=!0,t.stopPropagation()},t.isImmediatePropagationStopped=function(){return a},y.visible&&(e=t.keyCode,i=!1,e===p.down?(y.selectNext(),i=!0):e===p.up?(y.selectPrior(),i=!0):e===p.escape?(y.reset(),i=!0):e===p.enter&&(i=n.addSuggestion(t)),i&&(t.preventDefault(),t.stopImmediatePropagation(),n.$apply()))}}).on("input-blur",function(t){y.reset()}),T=function(t){t.isDefaultPrevented()||y.visible&&(!$(t.target).closest(".suggestion").length&&$(t.target).closest(i[0]).length||"blur"===t.type&&!/^(input|select|textarea|button|a)$/i.test(t.target.tagName)||(y.reset(),/apply|digest/.test(n.$root.$$phase)||n.$apply()))},e.on("click",T).on("blur",T),n.$on("$destroy",function(){e.off("click",T).off("blur",T),t(h),h=null,t(v),v=null})}}}]),d.directive("tiTranscludeAppend",function(){return function(t,e,n,i,a){a(function(t){e.append(t)})}}),d.directive("tiAutosize",function(){return{restrict:"A",require:"ngModel",link:function(t,e,n,i){var a,s,o=3;a=angular.element(''),a.css("display","none").css("visibility","hidden").css("width","auto").css("white-space","pre"),e.parent().append(a),s=function(t){var i,s=t;return angular.isString(s)&&0===s.length&&(s=n.placeholder),s&&(a.text(s),a.css("display",""),i=a.prop("offsetWidth"),a.css("display","none")),e.css("width",i?i+o+"px":""),t},i.$parsers.unshift(s),i.$formatters.unshift(s),n.$observe("placeholder",function(t){i.$modelValue||s(t)})}}}),d.provider("tagsInputConfig",function(){var t={},e={};this.setDefaults=function(e,n){return t[e]=n,this},this.setActiveInterpolation=function(t,n){return e[t]=n,this},this.$get=["$interpolate",function(n){var i={};return i[String]=function(t){return t},i[Number]=function(t){return parseInt(t,10)},i[Boolean]=function(t){return"true"===t.toLowerCase()},i[RegExp]=function(t){return new RegExp(t)},i[Object]=function(t){return"object"===("undefined"==typeof t?"undefined":_typeof(t))?t:Object(t)},{load:function(a,s,o,r){s.options={},s.attrs=o,s.uid=_.uniqueId(),angular.forEach(r,function(r,l){var u,g,c,p,d;u=r[0],g=r[1],c=i[u],p=function(){var e=t[a]&&t[a][l];return angular.isDefined(e)?e:g},d=function(t){s.options[l]=t?c(t):p()},s[l]?d(s[l]):e[a]&&e[a][l]?o.$observe(l,function(t){d(t)}):d(o[l]&&n(o[l])(s.$parent))})}}}]}),d.run(["$templateCache",function(t){t.put("cnTagsInput/tags-input.html",'\n
    \n
  • \n \n \n
  • \n
\n
\n \n \n \n
\n \n \n \n \n ×\n \n \n \n \n
\n
\n
\n Batch\n \n Clear\n \n Update Data\n \n Copy\n \n
\n
\n \n

\n Press "Enter" to submit, "Shift+Enter" to add a new line\n

\n

\n Add multiple with brackets, eg. "citizennet[10]"\n

\n
\n \n
\n
'),t.put("cnTagsInput/auto-complete.html",'\n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
')}])}(); //# sourceMappingURL=all.min.js.map diff --git a/dist/all.min.js.map b/dist/all.min.js.map index c193315..e80afc5 100644 --- a/dist/all.min.js.map +++ b/dist/all.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["all.js","cn-tags-input.js"],"names":["_defineProperty","obj","key","value","Object","defineProperty","enumerable","configurable","writable","_typeof","Symbol","iterator","constructor","prototype","empty","_","forOwn","_value","coll","set","SimplePubSub","events","on","names","handler","split","forEach","name","push","this","trigger","args","angular","call","destroy","makeObjectArray","array","key2","length","isObject","item","index","getArrayModelVal","options","arrayValueType","map","valueProperty","pluck","findInObjectArray","i","l","isFunction","objVal","has","toJson","toLowerCase","replaceAll","str","substr","newSubstr","expression","replace","RegExp","matchTagsWithModel","tags","model","isArray","equals","some","tag","findTagsForValue","matches","filter","find","val","matchTag","addFromAutocompleteOnly","each","v","m","modelType","tagValue","objectContains","small","large","every","selectAll","input","setSelectionRange","sortResults","results","displayProperty","valueFor","first","remove","result","startsWith","sortBy","reTag","second","test","search","third","concat","KEYS","backspace","tab","enter","escape","space","up","down","comma","tagsInput","module","directive","$timeout","$document","tagsInputConfig","$sce","$rootScope","TagList","getTagText","setTagText","tagIsValid","self","itemFormatter","text","tagText","minLength","maxLength","allowedTagsPattern","items","addText","add","disabled","trim","replaceSpacesWithDashes","maxTags","pop","$tag","$event","splice","removeLast","lastTagIndex","enableEditingLastTag","selected","removeAll","e","preventDefault","copyToClipboard","copyElement","document","createElement","style","position","opacity","textContent","join","body","getElementsByTagName","appendChild","select","execCommand","removeChild","restrict","require","scope","ngDisabled","onBeforeTagAdded","onBeforeTagRemoved","onBeforeTagChanged","onTagAdded","onTagRemoved","onTagChanged","onInit","newTag","transclude","templateUrl","controller","$scope","$attrs","$element","handleKeydown","load","placeholder","String","tabindex","Number","removeTagSymbol","fromCharCode","Boolean","addOnEnter","addOnSpace","addOnComma","addOnBlur","clearOnBlur","required","minTags","allowLeftoverText","tagClass","hideTags","dropdownIcon","tagsStyle","allowBulk","bulkSingleRequest","bulkDelimiter","bulkPlaceholder","sortFilteredResults","showClearAll","showClearCache","showButton","$on","off","tagList","processBulk","registerAutocomplete","addTag","focusInput","focus","blurInput","blur","getTags","getModel","getOptions","registerProcessBulk","fn","bulkTags","then","showBulk","registerSuggestionList","suggestionList","link","element","attrs","ngModelCtrl","tagsInputTag","beforeAndAfter","before","after","arguments","apply","inlineChangeTags","newTags","isObjectArray","handleInputKeydown","isImmediatePropagationStopped","shouldAdd","shouldRemove","keyCode","isModifier","shiftKey","altKey","ctrlKey","metaKey","addKeys","hotkeys","indexOf","$apply","handleInputBlur","blurTimeout","activeElement","prop","lostFocusToBrowserWindow","lostFocusToChildElement","contains","hasFocus","handleInputFocus","target","cancel","$root","$$phase","handleTextareaKeydown","handleDivClick","$target","$","closest","parent","hasClass","__tag","textarea","div","inputId","$name","$setValidity","undefined","invalid","getDisplayText","getDisplayHtml","trustAsHtml","track","newTagChange","triggerInit","prev","criteria","$prev","$setter","_ref2","$watch","changed","init","isUndefined","isDefined","$setDirty","uglyHackTimeout","$filter","$parse","Api","$q","SuggestionList","debouncedLoadId","getDifference","lastPromise","groupList","splitListItems","formatItemText","mapIndexes","list","groupBy","keys","filtered","group","indexes","groups","formatter","addItem","toAdd","childKey","searchKeys","child","array1","array2","reset","visible","query","show","promise","filterBy","processItems","isGroups","label","reconciliateItems","idx","__uniqueid","uniqueId","cloneDeep","ref","slice","maxResultsToShow","itemMap","data","skipFiltering","_load","debounceDelay","clearCache","event","_source","source","$query","refreshData","d","defer","resolve","selectNext","selectPrior","elem","customTemplateUrl","tagsInputCtrl","autoCompleteTag","getItemText","documentClick","singleQuery","highlightMatchedText","dropdownStyle","tagsValue","curTags","addSuggestion","added","copy","highlight","match","s","noResultsMessage","_ref3","addTags","times","request_config","JSON","parse","console","log","post","url","location_types","terms","response","batch","multiple","parseInt","_tagsInput$addTag","handled","immediatePropagationStopped","stopImmediatePropagation","stopPropagation","isDefaultPrevented","type","tagName","ctrl","transcludeFn","clone","append","span","resize","THRESHOLD","css","originalValue","width","isString","$parsers","unshift","$formatters","$observe","$modelValue","provider","globalDefaults","interpolationStatus","setDefaults","defaults","setActiveInterpolation","$get","$interpolate","converters","uid","localDefault","converter","getDefault","updateValue","globalValue","$parent","run","$templateCache","put"],"mappings":"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","file":"all.min.js","sourcesContent":["'use strict';\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n/*!;\n tagsInput = null;\n * ngTagsInput v2.0.1\n * http://mbenford.github.io/ngTagsInput\n *\n * Copyright (c) 2013-2014 Michael Benford\n * License: MIT\n *\n * Generated at 2014-04-13 21:25:38 -0300\n */\n(function () {\n 'use strict';\n\n var KEYS = {\n backspace: 8,\n tab: 9,\n enter: 13,\n escape: 27,\n space: 32,\n up: 38,\n down: 40,\n comma: 188\n };\n\n function empty(obj) {\n _.forOwn(obj, function (_value, key, coll) {\n _.set(coll, key, null);\n });\n }\n\n function SimplePubSub() {\n var events = {};\n return {\n on: function on(names, handler) {\n names.split(' ').forEach(function (name) {\n if (!events[name]) {\n events[name] = [];\n }\n events[name].push(handler);\n });\n return this;\n },\n trigger: function trigger(name, args) {\n angular.forEach(events[name], function (handler) {\n handler.call(null, args);\n });\n return this;\n },\n destroy: function destroy() {\n empty(events);\n events = null;\n }\n };\n }\n\n function makeObjectArray(array, key, key2) {\n array = array || [];\n if (array.length > 0 && !angular.isObject(array[0])) {\n array.forEach(function (item, index) {\n array[index] = _defineProperty({}, key, item);\n if (key2) array[index][key2] = item;\n });\n }\n return array;\n }\n\n function getArrayModelVal(array, options) {\n if (options.arrayValueType === 'object') {\n return (array || []).map(function (item) {\n return _.isObject(item && item[options.valueProperty]) ? item[options.valueProperty] : item;\n });\n } else {\n return _.pluck(array, options.valueProperty);\n }\n }\n\n function findInObjectArray(array, obj, key) {\n var item = null;\n var i = 0;\n var l = array.length;\n\n if (_.isFunction(key)) {\n var objVal = key(obj);\n if (!objVal) return null;\n for (; i < l; i++) {\n if (objVal === key(array[i])) {\n item = array[i];\n break;\n }\n }\n } else {\n for (; i < l; i++) {\n // I'm aware of the internationalization issues regarding toLowerCase()\n // but I couldn't come up with a better solution right now\n if (_.has(obj, key) && _.has(array[i], key) && (angular.toJson(array[i][key]) + '').toLowerCase() === (angular.toJson(obj[key]) + '').toLowerCase()) {\n item = array[i];\n break;\n }\n }\n }\n return item;\n }\n\n function replaceAll(str, substr, newSubstr) {\n var expression = substr.replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n return str.replace(new RegExp(expression, 'gi'), newSubstr);\n }\n\n function matchTagsWithModel(tags, model, options) {\n if (!model || !tags || !tags.length) return false;\n\n if (!_.isArray(model)) {\n return angular.equals(model, tags[0][options.valueProperty]) || angular.equals(model, tags[0]);\n }\n\n var array = getArrayModelVal(tags, options);\n return _.some(array, function (tag, i) {\n return angular.equals(model[i], tag) || angular.equals(model[i], tag[options.valueProperty]);\n });\n }\n\n function findTagsForValue(tags, value, options) {\n if (_.isArray(value)) {\n var matches = _.filter(tags, function (tag) {\n return _.find(value, function (val) {\n return matchTag(tag, val, options.valueProperty, options.arrayValueType);\n });\n });\n\n if (!options.addFromAutocompleteOnly && matches.length < value.length) {\n _.each(value, function (v) {\n if (!_.find(matches, function (m) {\n return matchTag(m, v, options.valueProperty, options.arrayValueType);\n })) matches.push(v);\n });\n }\n\n return matches;\n }\n\n return _.filter(tags, function (tag) {\n return matchTag(tag, value, options.valueProperty, options.modelType);\n });\n }\n\n function matchTag(tag, value, valueProperty, modelType) {\n var tagValue = valueProperty ? tag[valueProperty] : tag;\n return modelType === 'object' ? objectContains(value, tagValue) : value == tagValue;\n }\n\n function objectContains(small, large) {\n if (angular.isArray(small)) {\n return angular.equals(small, large);\n }\n return _.every(small, function (val, key) {\n return key === '$$hashKey' || (angular.isObject(val) ? objectContains(val, large[key]) : val == large[key]);\n });\n }\n\n function selectAll(input) {\n if (input.value) {\n input.setSelectionRange(0, input.value.length);\n }\n }\n\n function sortResults(results, tag, displayProperty) {\n var valueFor = function valueFor(val) {\n return displayProperty && val[displayProperty] ? val[displayProperty] : val;\n };\n var first = _.remove(results, function (result) {\n return _.startsWith(valueFor(result), valueFor(tag));\n });\n first = _.sortBy(first, [function (result) {\n return valueFor(result).length;\n }]);\n var reTag = new RegExp(valueFor(tag), \"i\");\n var second = _.remove(results, function (result) {\n return reTag.test(valueFor(result));\n });\n second = _.sortBy(second, [function (result) {\n return valueFor(result).search(reTag);\n }, function (result) {\n return valueFor(result).length;\n }]);\n var third = _.sortBy(results, [function (result) {\n return valueFor(result).length;\n }]);\n return first.concat(second, third);\n }\n\n var tagsInput = angular.module('cnTagsInput', []);\n\n /**\n * @ngdoc directive\n * @name tagsInput\n * @module cnTagsInput\n *\n * @description\n * Renders an input box with tag editing support.\n *\n * @param {string} ngModel Assignable angular expression to data-bind to.\n * @param {string=} [displayProperty=text] Property to be rendered as the tag label.\n * @param {string=} [valueProperty=value] Property to be used as the value when modelType is not array/object.\n * @param {number=} tabindex Tab order of the control.\n * @param {string=} [placeholder=Add a tag] Placeholder text for the control.\n * @param {number=} [minLength=3] Minimum length for a new tag.\n * @param {number=} maxLength Maximum length allowed for a new tag.\n * @param {boolean=} required Sets required validation error key.\n * @param {number=} minTags Sets minTags validation error key if the number of tags added is less than minTags.\n * @param {number=} maxTags Sets maxTags validation error key if the number of tags added is greater than maxTags.\n * @param {boolean=} [allowLeftoverText=false] Sets leftoverText validation error key if there is any leftover text in\n * the input element when the directive loses focus.\n * @param {string=} [removeTagSymbol=×] Symbol character for the remove tag button.\n * @param {boolean=} [addOnEnter=true] Flag indicating that a new tag will be added on pressing the ENTER key.\n * @param {boolean=} [addOnSpace=false] Flag indicating that a new tag will be added on pressing the SPACE key.\n * @param {boolean=} [addOnComma=true] Flag indicating that a new tag will be added on pressing the COMMA key.\n * @param {boolean=} [addOnBlur=false] Flag indicating that a new tag will be added when the input field loses focus.\n * @param {boolean=} [clearOnBlur=false] Flag indicating whether to clear the typed text when the input field loses focus.\n * @param {boolean=} [replaceSpacesWithDashes=false] Flag indicating that spaces will be replaced with dashes.\n * @param {string=} [allowedTagsPattern=.+] Regular expression that determines whether a new tag is valid.\n * @param {boolean=} [enableEditingLastTag=false] Flag indicating that the last tag will be moved back into\n * the new tag input box instead of being removed when the backspace key\n * is pressed and the input box is empty.\n * @param {boolean=} [addFromAutocompleteOnly=false] Flag indicating that only tags coming from the autocomplete list will be allowed.\n * When this flag is true, addOnEnter, addOnComma, addOnSpace, addOnBlur and\n * allowLeftoverText values are ignored.\n * @param {expression} onBeforeTagAdded Expression to evaluate upon adding a new tag. The new tag is available as $tag.\n * @param {expression} onBeforeTagRemoved Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.\n * @param {expression} onBeforeTagChanged Expression to evaluate upon adding or removing a tag. The affected tag is available as $tag. Prev value avialble as $prev.\n * @param {expression} onTagAdded Expression to evaluate upon adding a new tag. The new tag is available as $tag.\n * @param {expression} onTagRemoved Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.\n * @param {expression} onTagChanged Expression to evaluate upon adding or removing a tag. The affected tag is available as $tag. Prev value avialble as $prev.\n * @param {expression} onInit Expression to evaluate upon initializing model value.\n * @param {string} modelType Defines ngModel type, if anything other than array, model is set to first tag in list\n * @param {string} arrayValueType Defines ngModel[] type, if anything other than object, value is set mapped from object's values\n * @param {boolean=} [hideTags=false] Flag indicating whether to hide tag list (for manually displaying tag list in other way)\n * @param {boolean=} [dropdownIcon=false] Flag to show icon on right side\n * @param {string=} [tagsStyle='tags'] Default tags style\n * @param {boolean=} sortFilteredResults Flag to set whether to sort autocomplete list\n */\n tagsInput.directive('tagsInput', [\"$timeout\", \"$document\", \"tagsInputConfig\", \"$sce\", \"$rootScope\", function ($timeout, $document, tagsInputConfig, $sce, $rootScope) {\n function TagList(options, events) {\n var self = {},\n getTagText,\n setTagText,\n tagIsValid;\n\n getTagText = options.getTagText = function (tag) {\n if (!_.isObject(tag)) return tag;\n return options.itemFormatter ? options.itemFormatter(tag) : tag[options.displayProperty];\n };\n\n setTagText = function setTagText(tag, text) {\n // only create tag object when not adding from auto-complete\n if (tag[options.displayProperty]) return;\n\n tag[options.displayProperty] = text;\n if (options.valueProperty && !_.has(tag, options.valueProperty)) {\n tag[options.valueProperty] = text;\n }\n };\n\n tagIsValid = function tagIsValid(tag) {\n var tagText = getTagText(tag) + '';\n\n return (!options.minLength || tagText.length >= options.minLength) && (!options.maxLength || tagText.length <= options.maxLength) && options.allowedTagsPattern.test(tagText) && !findInObjectArray(self.items, tag, options.valueProperty || getTagText);\n };\n\n self.items = [];\n\n self.addText = function (text) {\n var tag = {};\n setTagText(tag, text);\n self.add(tag);\n };\n\n self.add = function (tag) {\n if (tag.disabled) return;\n\n var tagText = getTagText(tag);\n\n if (tagText.trim) tagText = tagText.trim();\n\n if (options.replaceSpacesWithDashes) {\n tagText = tagText.replace(/\\s/g, '-');\n }\n\n setTagText(tag, tagText);\n\n if (tagIsValid(tag)) {\n if (options.maxTags && self.items.length >= options.maxTags) {\n self.items.pop();\n events.trigger('tag-removed', { $tag: tag, $event: 'tag-removed' });\n }\n self.items.push(tag);\n events.trigger('tag-added', { $tag: tag, $event: 'tag-added' });\n } else {\n events.trigger('invalid-tag', { $tag: tag, $event: 'invalid-tag' });\n }\n return tag;\n };\n\n self.remove = function (index) {\n var tag = self.items.splice(index, 1)[0];\n events.trigger('tag-removed', { $tag: tag, $event: 'tag-removed' });\n return tag;\n };\n\n self.removeLast = function () {\n var tag,\n lastTagIndex = self.items.length - 1;\n\n if (options.enableEditingLastTag || self.selected) {\n self.selected = null;\n tag = self.remove(lastTagIndex);\n } else if (!self.selected) {\n self.selected = self.items[lastTagIndex];\n }\n\n return tag;\n };\n\n self.removeAll = function (e) {\n e.preventDefault();\n var tags = self.items.splice(0, self.items.length);\n tags.forEach(function (tag) {\n events.trigger('tag-removed', { $tag: tag, $event: 'tag-removed' });\n });\n };\n\n self.copyToClipboard = function () {\n var copyElement = document.createElement(\"textarea\");\n copyElement.style.position = 'fixed';\n copyElement.style.opacity = '0';\n copyElement.textContent = self.items.map(function (e) {\n return options.displayProperty && e[options.displayProperty] ? e[options.displayProperty] : e;\n }).join('\\n');\n var body = document.getElementsByTagName('body')[0];\n body.appendChild(copyElement);\n copyElement.select();\n document.execCommand('copy');\n body.removeChild(copyElement);\n };\n\n self.destroy = function () {\n empty(self);\n self = null;\n };\n\n return self;\n }\n\n return {\n restrict: 'E',\n require: 'ngModel',\n scope: {\n tags: '=ngModel',\n itemFormatter: '=',\n ngDisabled: '=',\n onBeforeTagAdded: '&',\n onBeforeTagRemoved: '&',\n onBeforeTagChanged: '&',\n onTagAdded: '&',\n onTagRemoved: '&',\n onTagChanged: '&',\n onInit: '&',\n newTag: '=?'\n },\n replace: false,\n transclude: true,\n templateUrl: 'cnTagsInput/tags-input.html',\n controller: [\"$scope\", \"$attrs\", \"$element\", function ($scope, $attrs, $element) {\n tagsInputConfig.load('tagsInput', $scope, $attrs, {\n placeholder: [String, ''],\n tabindex: [Number],\n removeTagSymbol: [String, String.fromCharCode(215)],\n replaceSpacesWithDashes: [Boolean, false],\n minLength: [Number, 2],\n maxLength: [Number],\n addOnEnter: [Boolean, true],\n addOnSpace: [Boolean, false],\n addOnComma: [Boolean, true],\n addOnBlur: [Boolean, false],\n clearOnBlur: [Boolean, false],\n allowedTagsPattern: [RegExp, /.+/],\n enableEditingLastTag: [Boolean, false],\n required: [Boolean, false],\n minTags: [Number],\n maxTags: [Number],\n displayProperty: [String, 'text'],\n valueProperty: [String],\n allowLeftoverText: [Boolean, false],\n addFromAutocompleteOnly: [Boolean, false],\n tagClass: [String, ''],\n modelType: [String, 'array'],\n arrayValueType: [String, 'object'],\n hideTags: [Boolean, false],\n dropdownIcon: [Boolean, false],\n tagsStyle: [String, 'tags'],\n allowBulk: [Boolean, false],\n bulkSingleRequest: [String, ''],\n bulkDelimiter: [RegExp, /, ?|\\n/],\n bulkPlaceholder: [String, 'Enter a list separated by commas or new lines'],\n sortFilteredResults: [Boolean, false],\n showClearAll: [Boolean, false],\n showClearCache: [Boolean, false],\n showButton: [Boolean, false]\n });\n\n var options = $scope.options;\n var input = options.input = $element.find('input.input');\n\n function handleKeydown(e) {\n $scope.events.trigger('input-keydown', e);\n }\n\n input.on('keydown', handleKeydown);\n\n $scope.$on('$destroy', function () {\n input.off('keydown', handleKeydown);\n input = null;\n empty(options);\n options = null;\n $scope.events.destroy();\n $scope.tagList.destroy();\n $scope.processBulk = null;\n });\n\n if (!options.valueProperty && (!/object|array/.test(options.modelType) || options.arrayValueType !== 'object')) {\n options.valueProperty = 'value';\n }\n\n if ($scope.itemFormatter) options.itemFormatter = $scope.itemFormatter;\n\n if (options.tagsStyle === 'tags') {\n options.tagClass = options.tagClass || 'label-primary';\n }\n\n if (options.allowBulk && (options.modelType !== 'array' || options.maxTags === 1)) {\n options.allowBulk = false;\n }\n\n $scope.events = new SimplePubSub();\n $scope.tagList = new TagList(options, $scope.events);\n\n this.registerAutocomplete = function () {\n return {\n addTag: function addTag(tag) {\n return $scope.tagList.add(tag);\n },\n focusInput: function focusInput() {\n input[0].focus();\n },\n blurInput: function blurInput() {\n input[0].blur();\n },\n getTags: function getTags() {\n return $scope.tagList.items;\n },\n getModel: function getModel() {\n return $scope.tags;\n },\n getOptions: function getOptions() {\n return options;\n },\n on: function on(name, handler) {\n $scope.events.on(name, handler);\n return this;\n },\n registerProcessBulk: function registerProcessBulk(fn) {\n $scope.processBulk = function () {\n fn($scope.bulkTags).then(function () {\n $scope.showBulk = false;\n $scope.bulkTags = '';\n });\n };\n },\n registerSuggestionList: function registerSuggestionList(suggestionList) {\n $scope.tagList.suggestionList = suggestionList;\n }\n };\n };\n }],\n link: function link(scope, element, attrs, ngModelCtrl) {\n function tagsInputTag() {}\n scope.__tag = new tagsInputTag();\n\n var hotkeys = [KEYS.enter, KEYS.comma, KEYS.space, KEYS.backspace],\n tagList = scope.tagList,\n events = scope.events,\n options = scope.options,\n input = element.find('input.input'),\n textarea = element.find('textarea'),\n div = element.find('div'),\n blurTimeout;\n\n if (attrs.inputId && !ngModelCtrl.$name) {\n ngModelCtrl.$name = attrs.inputId;\n }\n\n // before callbacks allow code to modify tag before it's added\n // after callback fired after ngModel has chance to update\n function beforeAndAfter(before, after) {\n return function () {\n var args = arguments;\n before.apply(this, args);\n $timeout(function () {\n after.apply(this, args);\n });\n };\n }\n\n function inlineChangeTags() {\n return function () {\n if (arguments.length > 0 && _.isArray(arguments[0].$tag)) {\n var newTags = arguments[0].$tag;\n var isObjectArray = _.every(newTags, function (v) {\n return (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object' && v !== null && options.displayProperty && v[options.displayProperty];\n });\n if (isObjectArray) {\n if (scope.tagList && scope.tagList.items && newTags) {\n scope.tagList.items = newTags;\n }\n }\n }\n };\n }\n\n events.on('tag-added', beforeAndAfter(scope.onBeforeTagAdded, scope.onTagAdded)).on('tag-removed', beforeAndAfter(scope.onBeforeTagRemoved, scope.onTagRemoved)).on('tag-changed', beforeAndAfter(scope.onBeforeTagChanged, scope.onTagChanged)).on('tag-changed', inlineChangeTags()).on('tag-init', scope.onInit).on('tag-added tag-removed', function (e) {\n if (!options.maxTags || options.maxTags > scope.tagList.items.length) {\n selectAll(options.input[0]);\n } else {\n scope.newTag.text = '';\n }\n if (options.modelType === 'array') {\n if (!options.valueProperty) {\n scope.tags = scope.tagList.items;\n } else {\n scope.tags = getArrayModelVal(scope.tagList.items, options);\n }\n if (scope.tagList.items.length >= options.minTags) {\n ngModelCtrl.$setValidity('tv4-400', true);\n }\n } else {\n if (e.$event === 'tag-removed') {\n scope.tags = undefined;\n } else {\n if (!options.valueProperty) {\n scope.tags = e.$tag;\n } else {\n scope.tags = _.has(e.$tag, options.valueProperty) ? e.$tag[options.valueProperty] : e.$tag[options.displayProperty];\n }\n }\n }\n }).on('invalid-tag', function () {\n scope.newTag.invalid = true;\n }).on('input-change', function () {\n tagList.selected = null;\n scope.newTag.invalid = null;\n }).on('input-focus', function () {\n ngModelCtrl.$setValidity('leftoverText', true);\n }).on('input-blur', function () {\n if (!options.addFromAutocompleteOnly) {\n if (options.addOnBlur && scope.newTag.text) {\n tagList.addText(scope.newTag.text);\n }\n }\n\n // Reset newTag\n if (options.clearOnBlur) {\n scope.newTag.text = '';\n scope.newTag.invalid = null;\n }\n });\n\n scope.newTag = { text: '', invalid: null };\n\n scope.getDisplayText = scope.itemFormatter || function (tag) {\n return tag && ((tag[options.displayProperty] || 'undefined') + '').trim();\n };\n\n scope.getDisplayHtml = function (tag) {\n return $sce.trustAsHtml(scope.getDisplayText(tag));\n };\n\n scope.track = function (tag) {\n return tag[options.displayProperty];\n };\n\n scope.newTagChange = function () {\n events.trigger('input-change', scope.newTag.text);\n };\n\n scope.processBulk = scope.processBulk || function () {\n var tags = scope.bulkTags.split(options.bulkDelimiter);\n _.each(tags, function (text) {\n var tag = {};\n tag[options.displayProperty] = text;\n scope.tagList.add(tag);\n });\n scope.showBulk = false;\n scope.bulkTags = '';\n };\n\n var first = true;\n\n scope.triggerInit = function (value, prev) {\n var criteria = options.valueProperty ? _defineProperty({}, options.valueProperty, value) : value;\n if (!tagList.items.length || !_.find(tagList.items, criteria)) {\n events.trigger('tag-init', {\n $tag: value,\n $prev: prev,\n $event: 'tag-init',\n $setter: function $setter(val) {\n if (val && !_.isObject(val)) {\n var _ref2;\n\n tagList.items = [(_ref2 = {}, _defineProperty(_ref2, options.displayProperty, val), _defineProperty(_ref2, options.valueProperty, val), _ref2)];\n } else {\n tagList.items = _.isArray(val) ? val : [val];\n }\n return tagList.items;\n }\n });\n }\n };\n\n scope.$watch('tags', function (value, prev) {\n var changed = !angular.equals(value, prev);\n var init = !changed && first;\n\n if (init) {\n scope.triggerInit(value, prev);\n }\n if (changed) {\n events.trigger('tag-changed', {\n $tag: value,\n $prev: prev,\n $event: 'tag-changed'\n });\n }\n\n if (options.modelType === 'array') {\n if (_.isArray(value)) {\n if (value.length) {\n if (!matchTagsWithModel(tagList.items, scope.tags, options)) {\n scope.triggerInit(value, prev);\n }\n if (!matchTagsWithModel(tagList.items, scope.tags, options) || tagList.items.length !== scope.tags.length) {\n tagList.items = makeObjectArray(value, options.displayProperty, options.valueProperty);\n scope.tags = getArrayModelVal(tagList.items, options);\n return;\n }\n } else {\n tagList.items = [];\n if (angular.isUndefined(prev)) return;\n }\n } else if (value === undefined) {\n tagList.items = [];\n scope.tags = [];\n return;\n }\n } else if (angular.isDefined(value)) {\n if (_.isArray(value)) {\n if (value.length) {\n //if(options.modelType === 'object') {\n if (!options.valueProperty) {\n scope.tags = value[0];\n } else {\n scope.tags = value[0][options.valueProperty];\n }\n\n return;\n } else {\n scope.tags = undefined;\n }\n } else {\n if (options.modelType === 'object') {\n if (value !== null) tagList.items = [value];\n } else {\n if (_.isObject(value)) {\n tagList.items = [value];\n\n var val = value[options.valueProperty];\n if (_.isUndefined(val)) val = value[options.displayProperty];\n scope.tags = val;\n\n return;\n } else if (!_.isUndefined(value) && (!tagList.items.length || tagList.items[0][options.valueProperty] !== value)) {\n scope.triggerInit(value, prev);\n }\n }\n }\n } else if (!value && tagList.items.length) {\n tagList.items = [];\n }\n\n if (!init && changed) {\n ngModelCtrl.$setDirty();\n }\n\n // hack because schemaForm is incorrectly invalidating model sometimes\n ngModelCtrl.$setValidity('schemaForm', true);\n if (options.modelType === 'array') {\n ngModelCtrl.$setValidity('tv4-401', value && options.maxTags ? value.length <= options.maxTags : true);\n ngModelCtrl.$setValidity('tv4-302', value ? angular.isDefined(options.minTags) ? value.length >= options.minTags : true : false);\n } else {\n ngModelCtrl.$setValidity('tv4-302', !options.required || !angular.isUndefined(value));\n }\n\n first = false;\n }, true);\n\n function handleInputKeydown(e) {\n // This hack is needed because jqLite doesn't implement stopImmediatePropagation properly.\n // I've sent a PR to Angular addressing this issue and hopefully it'll be fixed soon.\n // https://github.com/angular/angular.js/pull/4833\n if (e.isImmediatePropagationStopped && e.isImmediatePropagationStopped()) {\n return;\n }\n\n var key = e.keyCode,\n isModifier = e.shiftKey || e.altKey || e.ctrlKey || e.metaKey,\n addKeys = {},\n shouldAdd,\n shouldRemove;\n\n if (isModifier || hotkeys.indexOf(key) === -1) {\n return;\n }\n\n addKeys[KEYS.enter] = options.addOnEnter;\n addKeys[KEYS.comma] = options.addOnComma;\n addKeys[KEYS.space] = options.addOnSpace;\n\n shouldAdd = !options.addFromAutocompleteOnly && addKeys[key];\n shouldRemove = !shouldAdd && key === KEYS.backspace && scope.newTag.text.length === 0;\n\n if (shouldAdd) {\n tagList.addText(scope.newTag.text);\n\n scope.$apply();\n e.preventDefault();\n } else if (shouldRemove) {\n var tag = tagList.removeLast();\n if (tag && options.enableEditingLastTag) {\n scope.newTag.text = tag[options.displayProperty];\n }\n\n scope.$apply();\n e.preventDefault();\n }\n }\n\n function handleInputBlur(e) {\n blurTimeout = $timeout(function () {\n // race condition can cause input to be destroyed before timeout ends\n if (!input) return false;\n var activeElement = $document.prop('activeElement'),\n lostFocusToBrowserWindow = activeElement === input[0],\n lostFocusToChildElement = element.find('.host')[0].contains(activeElement);\n\n if (lostFocusToBrowserWindow || !lostFocusToChildElement) {\n scope.hasFocus = false;\n events.trigger('input-blur', e);\n }\n }, 150); // timeout so that click event triggers first\n }\n\n function handleInputFocus(e) {\n if (e) e.preventDefault();\n if (scope.ngDisabled) return;\n\n selectAll(e.target);\n\n if (blurTimeout) $timeout.cancel(blurTimeout);\n\n scope.hasFocus = true;\n events.trigger('input-focus', input.val());\n\n if (!/apply|digest/.test(scope.$root.$$phase)) scope.$apply();\n }\n\n function handleTextareaKeydown(e) {\n if (e.keyCode === KEYS.enter) {\n if (!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {\n e.preventDefault();\n scope.processBulk();\n }\n }\n }\n\n function handleDivClick(e) {\n var $target = $(e.target);\n if (!$target.closest('.suggestion').length &&\n // we don't want any of the buttons underneath to trigger\n !$target.parent().hasClass('help-block')) {\n e.preventDefault();\n input[0].focus();\n }\n }\n\n // stupid ugly hack to fix order between input and autocomplete events\n var uglyHackTimeout = $timeout(function () {\n input.on('keydown', handleInputKeydown).on('focus', handleInputFocus).on('blur', handleInputBlur);\n });\n\n textarea.on('keydown', handleTextareaKeydown);\n\n div.on('click', handleDivClick);\n\n scope.$on('$destroy', function () {\n input.off('keydown', handleInputKeydown).off('focus', handleInputFocus).off('blur', handleInputBlur);\n\n textarea.off('keydown', handleTextareaKeydown);\n div.off('click', handleDivClick);\n input = null;\n textarea = null;\n div = null;\n events.destroy();\n events = null;\n first = null;\n hotkeys = null;\n options = null;\n tagList = null;\n $timeout.cancel(uglyHackTimeout);\n });\n }\n };\n }]);\n\n /**\n * @ngdoc directive\n * @name autoComplete\n * @module cnTagsInput\n *\n * @description\n * Provides autocomplete support for the tagsInput directive.\n *\n * @param {expression} source Expression to evaluate upon changing the input content. The input value is available as\n * $query. The result of the expression must be a promise that eventually resolves to an\n * array of strings.\n * @param {number=} [debounceDelay=100] Amount of time, in milliseconds, to wait before evaluating the expression in\n * the source option after the last keystroke.\n * @param {number=} [minLength=3] Minimum number of characters that must be entered before evaluating the expression\n * in the source option.\n * @param {boolean=} [highlightMatchedText=true] Flag indicating that the matched text will be highlighted in the\n * suggestions list.\n * @param {number=} [maxResultsToShow=10] Maximum number of results to be displayed at a time.\n */\n tagsInput.directive('autoComplete', [\"$document\", \"$timeout\", \"$filter\", \"$sce\", \"tagsInputConfig\", \"$parse\", 'Api', '$q', function ($document, $timeout, $filter, $sce, tagsInputConfig, $parse, Api, $q) {\n function SuggestionList(scope, options) {\n var self = {},\n debouncedLoadId,\n getDifference,\n lastPromise,\n groupList,\n splitListItems,\n formatItemText,\n mapIndexes;\n\n groupList = function groupList(list, groupBy) {\n var filtered = {},\n map = [],\n index = 0,\n keys;\n\n // loop through each item in the list\n _.each(list, function (item) {\n keys = $parse(groupBy)(item);\n if (!_.isArray(keys)) keys = [keys];\n _.each(keys, function (key) {\n if (!filtered[key]) {\n filtered[key] = [];\n }\n filtered[key].push(item);\n });\n });\n\n _.each(filtered, function (group) {\n group.indexes = [];\n _.each(group, function (item) {\n group.indexes.push(index++);\n map.push(item);\n });\n });\n\n return {\n groups: filtered,\n map: map\n };\n };\n\n formatItemText = function formatItemText(item, formatter) {\n if (formatter) {\n if (!_.isArray(formatter)) {\n formatter = [formatter, {}];\n }\n return $parse(formatter[0])((formatter[1].val = item) && formatter[1]);\n }\n\n return item;\n };\n\n splitListItems = function splitListItems(items) {\n var keys = [];\n\n function addItem(key, item, group, prop) {\n var text = _.isObject(item) ? item[prop || options.tagsInput.displayProperty] : item,\n toAdd = {\n text: formatItemText(text, group.formatter),\n value: text,\n key: key,\n childKey: prop /*,\n tagClass: options.tagClasses && options.tagClasses[key] || options.tagClass*/\n };\n\n if (!_.find(group.items, toAdd)) {\n group.items.push(toAdd);\n }\n }\n\n _.each(scope.searchKeys, function (group) {\n var key = group.key;\n group.items = [];\n\n _.each(items, function (item) {\n if (item[key]) {\n if (_.isArray(item[key])) {\n _.each(item[key], function (child) {\n addItem(key, child, group, group.childKey);\n });\n } else {\n addItem(key, item[key], group, group.childKey);\n }\n }\n });\n keys.push(group);\n });\n\n return keys;\n };\n\n mapIndexes = function mapIndexes(items) {\n var map = [],\n index = 0;\n\n _.each(items, function (group) {\n group.indexes = [];\n _.each(group.items, function (item) {\n group.indexes.push(index++);\n map.push(item);\n });\n });\n\n return map;\n };\n\n getDifference = function getDifference(array1, array2) {\n if (!array2.length) {\n return array1.filter(function (item) {\n return item[options.tagsInput.displayProperty] !== '';\n });\n }\n return array1.filter(function (item) {\n return !findInObjectArray(array2, item, options.tagsInput.valueProperty || options.tagsInput.getTagText);\n });\n };\n\n self.reset = function () {\n lastPromise = null;\n\n self.items = [];\n self.visible = false;\n self.index = -1;\n self.selected = null;\n self.query = null;\n\n $timeout.cancel(debouncedLoadId);\n };\n\n self.show = function () {\n self.selected = null;\n self.visible = true;\n self.select(0);\n };\n\n self.load = function (query, tags) {\n if (query.length < options.minLength) {\n self.reset();\n return;\n }\n\n var promise,\n\n //filterBy = {},\n filterBy = query,\n groups,\n processItems = function processItems(items) {\n if (promise && promise !== lastPromise) {\n return;\n }\n\n if (scope.searchKeys) {\n scope.isGroups = true;\n //filterBy = query;\n items = splitListItems(items);\n }\n if (_.isObject(items) && !_.isArray(items)) {\n scope.isGroups = true;\n items = _.map(items, function (list, group) {\n return {\n items: list,\n label: group\n };\n });\n }\n if (scope.isGroups) {\n _.each(items, function (group) {\n group.items = getDifference(group.items, tags);\n if (query) {\n var reconciliateItems = {};\n group.items.map(function (item, idx) {\n item.__uniqueid = _.uniqueId('__uniqueid');\n reconciliateItems[item.__uniqueid] = _.cloneDeep(item);\n if ('key' in item) delete item.key;\n if ('childKey' in item) delete item.childKey;\n });\n group.items = $filter('cnFilter')(group.items, filterBy);\n if (options.tagsInput.sortFilteredResults) {\n group.items = sortResults(group.items, filterBy, options.tagsInput.displayProperty);\n }\n group.items.map(function (item) {\n var ref = reconciliateItems[item.__uniqueid];\n if ('key' in ref) item.key = ref.key;\n if ('childKey' in ref) item.childKey = ref.childKey;\n delete item.__uniqueid;\n });\n }\n\n group.items = group.items.slice(0, options.maxResultsToShow);\n });\n self.itemMap = mapIndexes(items);\n } else {\n //filterBy[options.tagsInput.displayProperty] = query;\n items = makeObjectArray(items.data || items, options.tagsInput.displayProperty);\n items = getDifference(items, tags);\n if (query && !options.skipFiltering) {\n items = $filter('cnFilter')(items, filterBy);\n }\n\n if (options.tagsInput.sortFilteredResults) {\n items = sortResults(items, filterBy, options.tagsInput.displayProperty);\n }\n\n items = items.slice(0, options.maxResultsToShow);\n\n if (options.groupBy) {\n groups = groupList(items, options.groupBy);\n items = groups.groups;\n self.itemMap = groups.map;\n }\n }\n\n self.items = items;\n self.show();\n };\n\n $timeout.cancel(debouncedLoadId);\n self.query = query;\n debouncedLoadId = $timeout(function () {\n self._load(query, promise).then(processItems);\n }, options.minLength ? options.debounceDelay : 0, false);\n };\n\n self.clearCache = function (event, query) {\n event.preventDefault();\n if (scope._source) scope.source = scope._source;\n var source = scope.source;\n source({ $query: query, options: { refreshData: true } }).then(function (results) {\n scope._source = source;\n scope.source = function () {\n return results;\n };\n scope.tagsInput.focusInput();\n });\n };\n\n self._load = function (query, promise) {\n var d = $q.defer();\n var source = scope.source({ $query: query });\n if (_.isArray(source)) {\n $timeout(function () {\n d.resolve(source || []);\n });\n } else {\n promise = source;\n lastPromise = promise;\n return promise;\n }\n return d.promise;\n };\n\n self.selectNext = function () {\n self.select(++self.index);\n };\n\n self.selectPrior = function () {\n self.select(--self.index);\n };\n\n self.select = function (index) {\n var list = self.itemMap || self.items;\n if (index < 0) {\n index = list.length - 1;\n } else if (index >= list.length) {\n index = 0;\n }\n self.index = index;\n if (self.itemMap) {\n self.selected = self.itemMap[index];\n } else {\n self.selected = self.items[index];\n }\n };\n\n return self;\n }\n\n function encodeHTML(value) {\n return value ? value.replace(/&/g, '&').replace(//g, '>') : '';\n }\n\n return {\n restrict: 'E',\n require: '^tagsInput',\n scope: {\n source: '&',\n searchKeys: '=?'\n },\n templateUrl: function templateUrl(elem, attrs) {\n return attrs.customTemplateUrl || 'cnTagsInput/auto-complete.html';\n },\n link: function link(scope, element, attrs, tagsInputCtrl) {\n var hotkeys = [KEYS.enter, KEYS.tab, KEYS.escape, KEYS.up, KEYS.down],\n suggestionList,\n tagsInput,\n options,\n getItemText,\n documentClick;\n\n function autoCompleteTag() {}\n scope.__tag = new autoCompleteTag();\n\n tagsInputConfig.load('autoComplete', scope, attrs, {\n debounceDelay: [Number, 250],\n minLength: [Number, 3],\n singleQuery: [Boolean, false],\n highlightMatchedText: [Boolean, true],\n maxResultsToShow: [Number, 75],\n groupBy: [String, ''],\n skipFiltering: [Boolean, false]\n });\n\n options = scope.options;\n\n tagsInput = tagsInputCtrl.registerAutocomplete();\n scope.tagsInput = tagsInput;\n\n options.tagsInput = tagsInput.getOptions();\n\n if (options.minLength === 0 /* && _.isArray(scope.source())*/) {\n options.tagsInput.dropdownIcon = true;\n if (options.tagsInput.maxTags === 1) {\n options.tagsInput.dropdownStyle = 'caret';\n } else {\n options.tagsInput.dropdownStyle = 'fa fa-plus';\n }\n } else {\n options.tagsInput.dropdownStyle = 'fa fa-search';\n }\n\n suggestionList = new SuggestionList(scope, options);\n tagsInput.registerSuggestionList(suggestionList);\n\n getItemText = options.tagsInput.itemFormatter || function (item) {\n return String(item[options.tagsInput.displayProperty]);\n };\n\n scope.suggestionList = suggestionList;\n\n var tagsValue = tagsInput.getModel();\n\n if (options.singleQuery && tagsValue && !angular.equals(tagsValue, [])) {\n suggestionList._load().then(function (results) {\n var tags = findTagsForValue(results, tagsValue, options.tagsInput);\n var curTags = tagsInput.getTags();\n if (!angular.equals(tags, curTags)) {\n curTags.length = 0; // hack to get event to retrigger\n tags.forEach(function (tag) {\n return tagsInput.addTag(tag);\n });\n }\n });\n }\n\n scope.addSuggestion = function (e) {\n e.preventDefault();\n\n var added = false;\n\n if (suggestionList.selected) {\n tagsInput.addTag(angular.copy(suggestionList.selected));\n\n if (!options.tagsInput.maxTags || tagsInput.getTags().length < options.tagsInput.maxTags) {\n var i = suggestionList.items.indexOf(suggestionList.selected);\n suggestionList.items.splice(i, 1);\n suggestionList.select(i);\n tagsInput.focusInput();\n } else {\n suggestionList.reset();\n tagsInput.blurInput();\n }\n\n added = true;\n }\n return added;\n };\n\n scope.highlight = function (item, key) {\n var text = getItemText(item, key);\n if (suggestionList.query && options.highlightMatchedText) {\n text = _(text.match(/(<[^>]*>|[^<]*)/g)) // regex will create a list of all html and text nodes\n .map(function (s) {\n return s.length && s[0] !== '<' ? replaceAll(s, suggestionList.query, '$&') : s;\n }).join('');\n }\n return $sce.trustAsHtml('' + text + '');\n };\n\n scope.track = function (item, key) {\n return getItemText(item, key);\n };\n\n scope.noResultsMessage = function (_ref3) {\n var visible = _ref3.visible,\n query = _ref3.query;\n\n if (!query) return 'No options...';\n return $sce.trustAsHtml('No results for ' + query + '...');\n };\n\n tagsInput.registerProcessBulk(function (bulkTags) {\n var tags = bulkTags.split(options.tagsInput.bulkDelimiter);\n var addTags = function addTags(i) {\n return function (data) {\n _.times(i, function (i) {\n if (data[i]) tagsInput.addTag(data[i]);\n });\n };\n };\n\n if (options.tagsInput.bulkSingleRequest) {\n var request_config = JSON.parse(options.tagsInput.bulkSingleRequest);\n console.log(request_config);\n return Api.post({\n url: request_config.url,\n data: {\n location_types: request_config.location_types,\n terms: tags\n }\n }).then(function (response) {\n response.map(function (item) {\n console.log(item);\n tagsInput.addTag(item);\n });\n });\n }\n // in case a query is involved...doesn't hurt to use even if not\n return Api.batch(function () {\n for (var i = 0, l = tags.length; i < l; i++) {\n if (options.tagsInput.maxTags && tagsInput.getTags().length >= options.tagsInput.maxTags) break;\n var tag = tags[i];\n var times = 1;\n var multiple = tags[i].match(/(.*) ?\\[(\\d+)\\]$/);\n\n if (multiple) {\n tag = multiple[1];\n times = parseInt(multiple[2]);\n }\n\n var results = scope.source({ $query: tag });\n\n if (_.isArray(results)) {\n if (results.length) {\n if (!options.skipFiltering) {\n var filterBy = tag;\n results = $filter('cnFilter')(results, filterBy);\n }\n if (options.tagsInput.sortFilteredResults) {\n results = sortResults(results, tag, options.tagsInput.displayProperty);\n }\n addTags(times)(results);\n } else if (!options.tagsInput.addFromAutocompleteOnly) {\n var _tagsInput$addTag;\n\n tagsInput.addTag((_tagsInput$addTag = {}, _defineProperty(_tagsInput$addTag, options.tagsInput.displayProperty, tag), _defineProperty(_tagsInput$addTag, options.tagsInput.valueProperty, tag), _tagsInput$addTag));\n }\n } else if (results.then) {\n results.then(addTags(times));\n }\n }\n });\n });\n\n tagsInput.on('input-change', function (value) {\n if (value || !options.minLength) {\n suggestionList.load(value, tagsInput.getTags());\n } else {\n suggestionList.reset();\n }\n }).on('input-focus', function (value) {\n if (!suggestionList.visible) {\n suggestionList.load(value, tagsInput.getTags());\n }\n }).on('input-keydown', function (e) {\n var key, handled;\n\n if (hotkeys.indexOf(e.keyCode) === -1) {\n return;\n }\n\n // This hack is needed because jqLite doesn't implement stopImmediatePropagation properly.\n // I've sent a PR to Angular addressing this issue and hopefully it'll be fixed soon.\n // https://github.com/angular/angular.js/pull/4833\n var immediatePropagationStopped = false;\n e.stopImmediatePropagation = function () {\n immediatePropagationStopped = true;\n e.stopPropagation();\n };\n e.isImmediatePropagationStopped = function () {\n return immediatePropagationStopped;\n };\n\n if (suggestionList.visible) {\n key = e.keyCode;\n handled = false;\n\n if (key === KEYS.down) {\n suggestionList.selectNext();\n handled = true;\n } else if (key === KEYS.up) {\n suggestionList.selectPrior();\n handled = true;\n } else if (key === KEYS.escape) {\n suggestionList.reset();\n handled = true;\n } else if (key === KEYS.enter) {\n handled = scope.addSuggestion(e);\n }\n\n if (handled) {\n e.preventDefault();\n e.stopImmediatePropagation();\n scope.$apply();\n }\n }\n }).on('input-blur', function (e) {\n //changed to use document click or focus, as this fires too soon and cancels\n //automcomplete click events\n suggestionList.reset();\n });\n\n documentClick = function documentClick(e) {\n if (e.isDefaultPrevented()) return;\n\n if (suggestionList.visible) {\n // if autocomplete option was selected, or click/focus triggered outside of directive\n if (($(e.target).closest('.suggestion').length || !$(e.target).closest(element[0]).length) && !(e.type === 'blur' && !/^(input|select|textarea|button|a)$/i.test(e.target.tagName))) {\n suggestionList.reset();\n if (!/apply|digest/.test(scope.$root.$$phase)) scope.$apply();\n }\n }\n };\n\n $document.on('click', documentClick).on('blur', documentClick);\n\n scope.$on('$destroy', function () {\n $document.off('click', documentClick).off('blur', documentClick);\n\n empty(tagsInput);\n tagsInput = null;\n\n empty(options);\n options = null;\n });\n }\n };\n }]);\n\n /**\n * @ngdoc directive\n * @name tiTranscludeAppend\n * @module cnTagsInput\n *\n * @description\n * Re-creates the old behavior of ng-transclude. Used internally by tagsInput directive.\n */\n tagsInput.directive('tiTranscludeAppend', function () {\n return function (scope, element, attrs, ctrl, transcludeFn) {\n transcludeFn(function (clone) {\n element.append(clone);\n });\n };\n });\n\n /**\n * @ngdoc directive\n * @name tiAutosize\n * @module cnTagsInput\n *\n * @description\n * Automatically sets the input's width so its content is always visible. Used internally by tagsInput directive.\n */\n tagsInput.directive('tiAutosize', function () {\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function link(scope, element, attrs, ctrl) {\n var THRESHOLD = 3,\n span,\n resize;\n\n span = angular.element('');\n span.css('display', 'none').css('visibility', 'hidden').css('width', 'auto').css('white-space', 'pre');\n\n element.parent().append(span);\n\n resize = function resize(originalValue) {\n var value = originalValue,\n width;\n\n if (angular.isString(value) && value.length === 0) {\n value = attrs.placeholder;\n }\n\n if (value) {\n span.text(value);\n span.css('display', '');\n width = span.prop('offsetWidth');\n span.css('display', 'none');\n }\n\n element.css('width', width ? width + THRESHOLD + 'px' : '');\n\n return originalValue;\n };\n\n ctrl.$parsers.unshift(resize);\n ctrl.$formatters.unshift(resize);\n\n attrs.$observe('placeholder', function (value) {\n if (!ctrl.$modelValue) {\n resize(value);\n }\n });\n }\n };\n });\n\n /**\n * @ngdoc service\n * @name tagsInputConfig\n * @module cnTagsInput\n *\n * @description\n * Sets global configuration settings for both tagsInput and autoComplete directives. It's also used internally to parse and\n * initialize options from HTML attributes.\n */\n tagsInput.provider('tagsInputConfig', function () {\n var globalDefaults = {},\n interpolationStatus = {};\n\n /**\n * @ngdoc method\n * @name setDefaults\n * @description Sets the default configuration option for a directive.\n * @methodOf tagsInputConfig\n *\n * @param {string} directive Name of the directive to be configured. Must be either 'tagsInput' or 'autoComplete'.\n * @param {object} defaults Object containing options and their values.\n *\n * @returns {object} The service itself for chaining purposes.\n */\n this.setDefaults = function (directive, defaults) {\n globalDefaults[directive] = defaults;\n return this;\n };\n\n /***\n * @ngdoc method\n * @name setActiveInterpolation\n * @description Sets active interpolation for a set of options.\n * @methodOf tagsInputConfig\n *\n * @param {string} directive Name of the directive to be configured. Must be either 'tagsInput' or 'autoComplete'.\n * @param {object} options Object containing which options should have interpolation turned on at all times.\n *\n * @returns {object} The service itself for chaining purposes.\n */\n this.setActiveInterpolation = function (directive, options) {\n interpolationStatus[directive] = options;\n return this;\n };\n\n this.$get = [\"$interpolate\", function ($interpolate) {\n var converters = {};\n converters[String] = function (value) {\n return value;\n };\n converters[Number] = function (value) {\n return parseInt(value, 10);\n };\n converters[Boolean] = function (value) {\n return value.toLowerCase() === 'true';\n };\n converters[RegExp] = function (value) {\n return new RegExp(value);\n };\n converters[Object] = function (value) {\n return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' ? value : Object(value);\n };\n\n return {\n load: function load(directive, scope, attrs, options) {\n scope.options = {};\n scope.attrs = attrs;\n scope.uid = _.uniqueId();\n\n angular.forEach(options, function (value, key) {\n var type, localDefault, converter, getDefault, updateValue;\n\n type = value[0];\n localDefault = value[1];\n converter = converters[type];\n\n getDefault = function getDefault() {\n var globalValue = globalDefaults[directive] && globalDefaults[directive][key];\n return angular.isDefined(globalValue) ? globalValue : localDefault;\n };\n\n updateValue = function updateValue(value) {\n scope.options[key] = value ? converter(value) : getDefault();\n };\n\n if (scope[key]) {\n updateValue(scope[key]);\n } else if (interpolationStatus[directive] && interpolationStatus[directive][key]) {\n attrs.$observe(key, function (value) {\n updateValue(value);\n });\n } else {\n updateValue(attrs[key] && $interpolate(attrs[key])(scope.$parent));\n }\n });\n }\n };\n }];\n });\n\n /* HTML templates */\n tagsInput.run([\"$templateCache\", function ($templateCache) {\n $templateCache.put('cnTagsInput/tags-input.html', '\\n
    \\n
  • \\n \\n \\n
  • \\n
\\n
\\n \\n \\n \\n
\\n \\n \\n \\n \\n ×\\n \\n \\n \\n \\n
\\n
\\n
\\n Batch\\n \\n Clear\\n \\n Update Data\\n \\n Copy\\n \\n
\\n
\\n \\n

\\n Press \"Enter\" to submit, \"Shift+Enter\" to add a new line\\n

\\n

\\n Add multiple with brackets, eg. \"citizennet[10]\"\\n

\\n
\\n \\n
\\n
');\n\n $templateCache.put('cnTagsInput/auto-complete.html', '\\n
\\n
    \\n
  • \\n
\\n
\\n
\\n
    \\n
  • No results...
  • \\n
  • \\n
  • {{group.label | titleCase}}
  • \\n
  • \\n
  • \\n
  • \\n
  • \\n
\\n
\\n
\\n
    \\n
  • \\n
  • \\n
\\n
\\n
\\n
    \\n
  • \\n
  • {{group | titleCase}}
  • \\n
  • \\n
  • \\n
  • \\n
  • \\n
\\n
');\n }]);\n})();","/*!;\n tagsInput = null;\n * ngTagsInput v2.0.1\n * http://mbenford.github.io/ngTagsInput\n *\n * Copyright (c) 2013-2014 Michael Benford\n * License: MIT\n *\n * Generated at 2014-04-13 21:25:38 -0300\n */\n(function() {\n 'use strict';\n\n var KEYS = {\n backspace: 8,\n tab: 9,\n enter: 13,\n escape: 27,\n space: 32,\n up: 38,\n down: 40,\n comma: 188\n };\n\n function empty(obj) {\n _.forOwn(obj, function(_value, key, coll) {\n _.set(coll, key, null);\n });\n }\n\n function SimplePubSub() {\n var events = {};\n return {\n on: function(names, handler) {\n names.split(' ').forEach(function(name) {\n if(!events[name]) {\n events[name] = [];\n }\n events[name].push(handler);\n });\n return this;\n },\n trigger: function(name, args) {\n angular.forEach(events[name], function(handler) {\n handler.call(null, args);\n });\n return this;\n },\n destroy: function() {\n empty(events);\n events = null;\n }\n };\n }\n\n function makeObjectArray(array, key, key2) {\n array = array || [];\n if(array.length > 0 && !angular.isObject(array[0])) {\n array.forEach(function(item, index) {\n array[index] = {\n [key]: item\n };\n if(key2) array[index][key2] = item;\n });\n }\n return array;\n }\n\n function getArrayModelVal(array, options) {\n if(options.arrayValueType === 'object') {\n return (array || []).map(item => _.isObject(item && item[options.valueProperty]) ? item[options.valueProperty] : item);\n }\n else {\n return _.pluck(array, options.valueProperty);\n }\n }\n\n function findInObjectArray(array, obj, key) {\n var item = null;\n var i = 0;\n var l = array.length;\n\n if(_.isFunction(key)) {\n var objVal = key(obj);\n if(!objVal) return null;\n for(; i < l; i++) {\n if(objVal === key(array[i])) {\n item = array[i];\n break;\n }\n }\n }\n else {\n for(; i < l; i++) {\n // I'm aware of the internationalization issues regarding toLowerCase()\n // but I couldn't come up with a better solution right now\n if(_.has(obj, key) &&\n _.has(array[i], key) &&\n (angular.toJson(array[i][key]) + '').toLowerCase() === (angular.toJson(obj[key]) + '').toLowerCase()) {\n item = array[i];\n break;\n }\n }\n }\n return item;\n }\n\n function replaceAll(str, substr, newSubstr) {\n var expression = substr.replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n return str.replace(new RegExp(expression, 'gi'), newSubstr);\n }\n\n function matchTagsWithModel(tags, model, options) {\n if(!model || !tags || !tags.length) return false;\n\n if(!_.isArray(model)) {\n return angular.equals(model, tags[0][options.valueProperty]) || angular.equals(model, tags[0]);\n }\n\n let array = getArrayModelVal(tags, options);\n return _.some(array, (tag, i) => {\n return angular.equals(model[i], tag) || angular.equals(model[i], tag[options.valueProperty]);\n });\n }\n\n function findTagsForValue(tags, value, options) {\n if(_.isArray(value)) {\n var matches = _.filter(tags, tag => _.find(value, val =>\n matchTag(tag, val, options.valueProperty, options.arrayValueType)));\n\n if(!options.addFromAutocompleteOnly && matches.length < value.length) {\n _.each(value, v => {\n if(!_.find(matches, m => matchTag(m, v, options.valueProperty, options.arrayValueType))) matches.push(v);\n });\n }\n\n return matches;\n }\n\n return _.filter(tags, tag => matchTag(tag, value, options.valueProperty, options.modelType));\n }\n\n function matchTag(tag, value, valueProperty, modelType) {\n var tagValue = valueProperty ? tag[valueProperty] : tag;\n return modelType === 'object' ?\n objectContains(value, tagValue) :\n value == tagValue;\n }\n\n function objectContains(small, large) {\n if(angular.isArray(small)) {\n return angular.equals(small, large);\n }\n return _.every(small, (val, key) => {\n return key === '$$hashKey' || (\n angular.isObject(val) ?\n objectContains(val, large[key]) :\n val == large[key]\n );\n });\n }\n\n function selectAll(input) {\n if(input.value) {\n input.setSelectionRange(0, input.value.length);\n }\n }\n\n function sortResults(results, tag, displayProperty) {\n const valueFor = val => {\n return displayProperty && val[displayProperty] ? val[displayProperty] : val;\n };\n var first = _.remove(results, result => {\n return _.startsWith(valueFor(result), valueFor(tag));\n });\n first = _.sortBy(first, [\n result => { return valueFor(result).length; }\n ]);\n const reTag = new RegExp(valueFor(tag), \"i\");\n var second = _.remove(results, result => {\n return reTag.test(valueFor(result));\n });\n second = _.sortBy(second, [\n result => { return valueFor(result).search(reTag);},\n result => { return valueFor(result).length; }\n ]);\n var third = _.sortBy(results, [\n result => { return valueFor(result).length; }\n ]);\n return first.concat(second, third);\n }\n\n var tagsInput = angular.module('cnTagsInput', []);\n\n /**\n * @ngdoc directive\n * @name tagsInput\n * @module cnTagsInput\n *\n * @description\n * Renders an input box with tag editing support.\n *\n * @param {string} ngModel Assignable angular expression to data-bind to.\n * @param {string=} [displayProperty=text] Property to be rendered as the tag label.\n * @param {string=} [valueProperty=value] Property to be used as the value when modelType is not array/object.\n * @param {number=} tabindex Tab order of the control.\n * @param {string=} [placeholder=Add a tag] Placeholder text for the control.\n * @param {number=} [minLength=3] Minimum length for a new tag.\n * @param {number=} maxLength Maximum length allowed for a new tag.\n * @param {boolean=} required Sets required validation error key.\n * @param {number=} minTags Sets minTags validation error key if the number of tags added is less than minTags.\n * @param {number=} maxTags Sets maxTags validation error key if the number of tags added is greater than maxTags.\n * @param {boolean=} [allowLeftoverText=false] Sets leftoverText validation error key if there is any leftover text in\n * the input element when the directive loses focus.\n * @param {string=} [removeTagSymbol=×] Symbol character for the remove tag button.\n * @param {boolean=} [addOnEnter=true] Flag indicating that a new tag will be added on pressing the ENTER key.\n * @param {boolean=} [addOnSpace=false] Flag indicating that a new tag will be added on pressing the SPACE key.\n * @param {boolean=} [addOnComma=true] Flag indicating that a new tag will be added on pressing the COMMA key.\n * @param {boolean=} [addOnBlur=false] Flag indicating that a new tag will be added when the input field loses focus.\n * @param {boolean=} [clearOnBlur=false] Flag indicating whether to clear the typed text when the input field loses focus.\n * @param {boolean=} [replaceSpacesWithDashes=false] Flag indicating that spaces will be replaced with dashes.\n * @param {string=} [allowedTagsPattern=.+] Regular expression that determines whether a new tag is valid.\n * @param {boolean=} [enableEditingLastTag=false] Flag indicating that the last tag will be moved back into\n * the new tag input box instead of being removed when the backspace key\n * is pressed and the input box is empty.\n * @param {boolean=} [addFromAutocompleteOnly=false] Flag indicating that only tags coming from the autocomplete list will be allowed.\n * When this flag is true, addOnEnter, addOnComma, addOnSpace, addOnBlur and\n * allowLeftoverText values are ignored.\n * @param {expression} onBeforeTagAdded Expression to evaluate upon adding a new tag. The new tag is available as $tag.\n * @param {expression} onBeforeTagRemoved Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.\n * @param {expression} onBeforeTagChanged Expression to evaluate upon adding or removing a tag. The affected tag is available as $tag. Prev value avialble as $prev.\n * @param {expression} onTagAdded Expression to evaluate upon adding a new tag. The new tag is available as $tag.\n * @param {expression} onTagRemoved Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.\n * @param {expression} onTagChanged Expression to evaluate upon adding or removing a tag. The affected tag is available as $tag. Prev value avialble as $prev.\n * @param {expression} onInit Expression to evaluate upon initializing model value.\n * @param {string} modelType Defines ngModel type, if anything other than array, model is set to first tag in list\n * @param {string} arrayValueType Defines ngModel[] type, if anything other than object, value is set mapped from object's values\n * @param {boolean=} [hideTags=false] Flag indicating whether to hide tag list (for manually displaying tag list in other way)\n * @param {boolean=} [dropdownIcon=false] Flag to show icon on right side\n * @param {string=} [tagsStyle='tags'] Default tags style\n * @param {boolean=} sortFilteredResults Flag to set whether to sort autocomplete list\n */\n tagsInput.directive('tagsInput', [\n \"$timeout\", \"$document\", \"tagsInputConfig\", \"$sce\", \"$rootScope\",\n function($timeout, $document, tagsInputConfig, $sce, $rootScope) {\n function TagList(options, events) {\n var self = {}, getTagText, setTagText, tagIsValid;\n\n getTagText = options.getTagText = function(tag) {\n if(!_.isObject(tag)) return tag;\n return options.itemFormatter ? options.itemFormatter(tag) : tag[options.displayProperty];\n };\n\n setTagText = function(tag, text) {\n // only create tag object when not adding from auto-complete\n if(tag[options.displayProperty]) return;\n\n tag[options.displayProperty] = text;\n if(options.valueProperty && !_.has(tag, options.valueProperty)) {\n tag[options.valueProperty] = text;\n }\n };\n\n tagIsValid = function(tag) {\n var tagText = getTagText(tag) + '';\n\n return (!options.minLength || tagText.length >= options.minLength) &&\n (!options.maxLength || tagText.length <= options.maxLength) &&\n options.allowedTagsPattern.test(tagText) &&\n !findInObjectArray(\n self.items,\n tag,\n options.valueProperty || getTagText\n );\n };\n\n self.items = [];\n\n self.addText = function(text) {\n var tag = {};\n setTagText(tag, text);\n self.add(tag);\n };\n\n self.add = function(tag) {\n if(tag.disabled) return;\n\n var tagText = getTagText(tag);\n\n if(tagText.trim) tagText = tagText.trim();\n\n if(options.replaceSpacesWithDashes) {\n tagText = tagText.replace(/\\s/g, '-');\n }\n\n setTagText(tag, tagText);\n\n if(tagIsValid(tag)) {\n if(options.maxTags && self.items.length >= options.maxTags) {\n self.items.pop();\n events.trigger('tag-removed', {$tag: tag, $event: 'tag-removed'});\n }\n self.items.push(tag);\n events.trigger('tag-added', {$tag: tag, $event: 'tag-added'});\n }\n else {\n events.trigger('invalid-tag', {$tag: tag, $event: 'invalid-tag'});\n }\n return tag;\n };\n\n self.remove = function(index) {\n var tag = self.items.splice(index, 1)[0];\n events.trigger('tag-removed', {$tag: tag, $event: 'tag-removed'});\n return tag;\n };\n\n self.removeLast = function() {\n var tag, lastTagIndex = self.items.length - 1;\n\n if(options.enableEditingLastTag || self.selected) {\n self.selected = null;\n tag = self.remove(lastTagIndex);\n }\n else if(!self.selected) {\n self.selected = self.items[lastTagIndex];\n }\n\n return tag;\n };\n\n self.removeAll = function(e) {\n e.preventDefault();\n var tags = self.items.splice(0, self.items.length);\n tags.forEach(function(tag) {\n events.trigger('tag-removed', {$tag: tag, $event: 'tag-removed'});\n });\n };\n\n self.copyToClipboard = function() {\n var copyElement = document.createElement(\"textarea\");\n copyElement.style.position = 'fixed';\n copyElement.style.opacity = '0';\n copyElement.textContent = self.items.map(\n e => options.displayProperty && e[options.displayProperty] ? e[options.displayProperty] : e\n ).join('\\n');\n var body = document.getElementsByTagName('body')[0];\n body.appendChild(copyElement);\n copyElement.select();\n document.execCommand('copy');\n body.removeChild(copyElement);\n };\n\n self.destroy = function() {\n empty(self);\n self = null;\n };\n\n return self;\n }\n\n return {\n restrict: 'E',\n require: 'ngModel',\n scope: {\n tags: '=ngModel',\n itemFormatter: '=',\n ngDisabled: '=',\n onBeforeTagAdded: '&',\n onBeforeTagRemoved: '&',\n onBeforeTagChanged: '&',\n onTagAdded: '&',\n onTagRemoved: '&',\n onTagChanged: '&',\n onInit: '&',\n newTag: '=?'\n },\n replace: false,\n transclude: true,\n templateUrl: 'cnTagsInput/tags-input.html',\n controller: [\"$scope\", \"$attrs\", \"$element\", function($scope, $attrs, $element) {\n tagsInputConfig.load('tagsInput', $scope, $attrs, {\n placeholder: [String, ''],\n tabindex: [Number],\n removeTagSymbol: [String, String.fromCharCode(215)],\n replaceSpacesWithDashes: [Boolean, false],\n minLength: [Number, 2],\n maxLength: [Number],\n addOnEnter: [Boolean, true],\n addOnSpace: [Boolean, false],\n addOnComma: [Boolean, true],\n addOnBlur: [Boolean, false],\n clearOnBlur: [Boolean, false],\n allowedTagsPattern: [RegExp, /.+/],\n enableEditingLastTag: [Boolean, false],\n required: [Boolean, false],\n minTags: [Number],\n maxTags: [Number],\n displayProperty: [String, 'text'],\n valueProperty: [String],\n allowLeftoverText: [Boolean, false],\n addFromAutocompleteOnly: [Boolean, false],\n tagClass: [String, ''],\n modelType: [String, 'array'],\n arrayValueType: [String, 'object'],\n hideTags: [Boolean, false],\n dropdownIcon: [Boolean, false],\n tagsStyle: [String, 'tags'],\n allowBulk: [Boolean, false],\n bulkSingleRequest: [String, ''],\n bulkDelimiter: [RegExp, /, ?|\\n/],\n bulkPlaceholder: [String, 'Enter a list separated by commas or new lines'],\n sortFilteredResults: [Boolean, false],\n showClearAll: [Boolean, false],\n showClearCache: [Boolean, false],\n showButton: [Boolean, false]\n });\n\n var options = $scope.options;\n var input = options.input = $element.find('input.input');\n\n function handleKeydown(e) {\n $scope.events.trigger('input-keydown', e);\n }\n\n input.on('keydown', handleKeydown);\n\n $scope.$on('$destroy', function() {\n input.off('keydown', handleKeydown);\n input = null;\n empty(options);\n options = null;\n $scope.events.destroy();\n $scope.tagList.destroy();\n $scope.processBulk = null;\n });\n\n if(!options.valueProperty &&\n (!/object|array/.test(options.modelType) || options.arrayValueType !== 'object')) {\n options.valueProperty = 'value';\n }\n\n if($scope.itemFormatter) options.itemFormatter = $scope.itemFormatter;\n\n if(options.tagsStyle === 'tags') {\n options.tagClass = options.tagClass || 'label-primary';\n }\n\n if(options.allowBulk && (options.modelType !== 'array' || options.maxTags === 1)) {\n options.allowBulk = false;\n }\n\n $scope.events = new SimplePubSub();\n $scope.tagList = new TagList(options, $scope.events);\n\n this.registerAutocomplete = function() {\n return {\n addTag: function(tag) {\n return $scope.tagList.add(tag);\n },\n focusInput: function() {\n input[0].focus();\n },\n blurInput: function() {\n input[0].blur();\n },\n getTags: function() {\n return $scope.tagList.items;\n },\n getModel: function() {\n return $scope.tags;\n },\n getOptions: function() {\n return options;\n },\n on: function(name, handler) {\n $scope.events.on(name, handler);\n return this;\n },\n registerProcessBulk: function(fn) {\n $scope.processBulk = function() {\n fn($scope.bulkTags).then(function() {\n $scope.showBulk = false;\n $scope.bulkTags = '';\n });\n };\n },\n registerSuggestionList: function(suggestionList) {\n $scope.tagList.suggestionList = suggestionList;\n }\n };\n };\n }],\n link: function(scope, element, attrs, ngModelCtrl) {\n function tagsInputTag() {}\n scope.__tag = new tagsInputTag();\n\n var hotkeys = [KEYS.enter, KEYS.comma, KEYS.space, KEYS.backspace],\n tagList = scope.tagList,\n events = scope.events,\n options = scope.options,\n input = element.find('input.input'),\n textarea = element.find('textarea'),\n div = element.find('div'),\n blurTimeout;\n\n if(attrs.inputId && !ngModelCtrl.$name) {\n ngModelCtrl.$name = attrs.inputId;\n }\n\n // before callbacks allow code to modify tag before it's added\n // after callback fired after ngModel has chance to update\n function beforeAndAfter(before, after) {\n return function() {\n var args = arguments;\n before.apply(this, args);\n $timeout(function(){\n after.apply(this, args);\n });\n };\n }\n\n function inlineChangeTags() {\n return function() {\n if (arguments.length > 0 && _.isArray(arguments[0].$tag)) {\n let newTags = arguments[0].$tag;\n const isObjectArray = _.every(newTags, (v) => typeof v === 'object' && v !== null && options.displayProperty && v[options.displayProperty]);\n if (isObjectArray) {\n if (scope.tagList && scope.tagList.items && newTags) {\n scope.tagList.items = newTags;\n }\n }\n }\n };\n }\n\n events\n .on('tag-added', beforeAndAfter(scope.onBeforeTagAdded, scope.onTagAdded))\n .on('tag-removed', beforeAndAfter(scope.onBeforeTagRemoved, scope.onTagRemoved))\n .on('tag-changed', beforeAndAfter(scope.onBeforeTagChanged, scope.onTagChanged))\n .on('tag-changed', inlineChangeTags())\n .on('tag-init', scope.onInit)\n .on('tag-added tag-removed', function(e) {\n if(!options.maxTags || options.maxTags > scope.tagList.items.length) {\n selectAll(options.input[0]);\n }\n else {\n scope.newTag.text = '';\n }\n if(options.modelType === 'array') {\n if(!options.valueProperty) {\n scope.tags = scope.tagList.items;\n }\n else {\n scope.tags = getArrayModelVal(scope.tagList.items, options);\n }\n if (scope.tagList.items.length >= options.minTags) {\n ngModelCtrl.$setValidity('tv4-400', true);\n }\n }\n else {\n if(e.$event === 'tag-removed') {\n scope.tags = undefined;\n }\n else {\n if(!options.valueProperty) {\n scope.tags = e.$tag;\n }\n else {\n scope.tags = _.has(e.$tag, options.valueProperty) ?\n e.$tag[options.valueProperty] : e.$tag[options.displayProperty];\n }\n }\n }\n })\n .on('invalid-tag', function() {\n scope.newTag.invalid = true;\n })\n .on('input-change', function() {\n tagList.selected = null;\n scope.newTag.invalid = null;\n })\n .on('input-focus', function() {\n ngModelCtrl.$setValidity('leftoverText', true);\n })\n .on('input-blur', function() {\n if(!options.addFromAutocompleteOnly) {\n if(options.addOnBlur && scope.newTag.text) {\n tagList.addText(scope.newTag.text);\n }\n }\n\n // Reset newTag\n if(options.clearOnBlur) {\n scope.newTag.text = '';\n scope.newTag.invalid = null;\n }\n });\n\n scope.newTag = {text: '', invalid: null};\n\n scope.getDisplayText = scope.itemFormatter || function(tag) {\n return tag && ((tag[options.displayProperty] || 'undefined') + '').trim();\n };\n\n scope.getDisplayHtml = function(tag) {\n return $sce.trustAsHtml(scope.getDisplayText(tag));\n };\n\n scope.track = function(tag) {\n return tag[options.displayProperty];\n };\n\n scope.newTagChange = function() {\n events.trigger('input-change', scope.newTag.text);\n };\n\n scope.processBulk = scope.processBulk || function() {\n var tags = scope.bulkTags.split(options.bulkDelimiter);\n _.each(tags, function(text) {\n var tag = {};\n tag[options.displayProperty] = text;\n scope.tagList.add(tag);\n });\n scope.showBulk = false;\n scope.bulkTags = '';\n };\n\n var first = true;\n\n scope.triggerInit = function(value, prev) {\n var criteria = options.valueProperty ? {[options.valueProperty]: value} : value;\n if(!tagList.items.length || !_.find(tagList.items, criteria)) {\n events.trigger('tag-init', {\n $tag: value,\n $prev: prev,\n $event: 'tag-init',\n $setter: function(val) {\n if(val && !_.isObject(val)) {\n tagList.items = [{\n [options.displayProperty]: val,\n [options.valueProperty]: val\n }];\n }\n else {\n tagList.items = _.isArray(val) ? val : [val];\n }\n return tagList.items;\n }\n });\n }\n };\n\n scope.$watch('tags', function(value, prev) {\n var changed = !angular.equals(value, prev);\n var init = !changed && first;\n\n if(init) {\n scope.triggerInit(value, prev);\n }\n if(changed) {\n events.trigger('tag-changed', {\n $tag: value,\n $prev: prev,\n $event: 'tag-changed'\n });\n }\n\n if(options.modelType === 'array') {\n if(_.isArray(value)) {\n if(value.length) {\n if(!matchTagsWithModel(tagList.items, scope.tags, options)) {\n scope.triggerInit(value, prev);\n }\n if(!matchTagsWithModel(tagList.items, scope.tags, options) || tagList.items.length !== scope.tags.length) {\n tagList.items = makeObjectArray(value, options.displayProperty, options.valueProperty);\n scope.tags = getArrayModelVal(tagList.items, options);\n return;\n }\n }\n else {\n tagList.items = [];\n if(angular.isUndefined(prev)) return;\n }\n }\n else if(value === undefined) {\n tagList.items = [];\n scope.tags = [];\n return;\n }\n }\n else if(angular.isDefined(value)) {\n if(_.isArray(value)) {\n if(value.length) {\n //if(options.modelType === 'object') {\n if(!options.valueProperty) {\n scope.tags = value[0];\n }\n else {\n scope.tags = value[0][options.valueProperty];\n }\n\n return;\n }\n else {\n scope.tags = undefined;\n }\n }\n else {\n if(options.modelType === 'object') {\n if(value !== null) tagList.items = [value];\n }\n else {\n if(_.isObject(value)) {\n tagList.items = [value];\n\n var val = value[options.valueProperty];\n if(_.isUndefined(val)) val = value[options.displayProperty];\n scope.tags = val;\n\n return;\n }\n else if(!_.isUndefined(value) &&\n (!tagList.items.length || tagList.items[0][options.valueProperty] !== value)) {\n scope.triggerInit(value, prev);\n }\n }\n }\n }\n else if(!value && tagList.items.length) {\n tagList.items = [];\n }\n\n if(!init && changed) {\n ngModelCtrl.$setDirty();\n }\n\n // hack because schemaForm is incorrectly invalidating model sometimes\n ngModelCtrl.$setValidity('schemaForm', true);\n if(options.modelType === 'array') {\n ngModelCtrl.$setValidity('tv4-401', value && options.maxTags ? value.length <= options.maxTags : true);\n ngModelCtrl.$setValidity('tv4-302', value ? angular.isDefined(options.minTags) ? value.length >= options.minTags : true : false);\n }\n else {\n ngModelCtrl.$setValidity('tv4-302', !options.required || !(angular.isUndefined(value)));\n }\n\n first = false;\n\n }, true);\n\n function handleInputKeydown(e) {\n // This hack is needed because jqLite doesn't implement stopImmediatePropagation properly.\n // I've sent a PR to Angular addressing this issue and hopefully it'll be fixed soon.\n // https://github.com/angular/angular.js/pull/4833\n if(e.isImmediatePropagationStopped && e.isImmediatePropagationStopped()) {\n return;\n }\n\n var key = e.keyCode,\n isModifier = e.shiftKey || e.altKey || e.ctrlKey || e.metaKey,\n addKeys = {},\n shouldAdd, shouldRemove;\n\n if(isModifier || hotkeys.indexOf(key) === -1) {\n return;\n }\n\n addKeys[KEYS.enter] = options.addOnEnter;\n addKeys[KEYS.comma] = options.addOnComma;\n addKeys[KEYS.space] = options.addOnSpace;\n\n shouldAdd = !options.addFromAutocompleteOnly && addKeys[key];\n shouldRemove = !shouldAdd && key === KEYS.backspace && scope.newTag.text.length === 0;\n\n if(shouldAdd) {\n tagList.addText(scope.newTag.text);\n\n scope.$apply();\n e.preventDefault();\n }\n else if(shouldRemove) {\n var tag = tagList.removeLast();\n if(tag && options.enableEditingLastTag) {\n scope.newTag.text = tag[options.displayProperty];\n }\n\n scope.$apply();\n e.preventDefault();\n }\n }\n\n function handleInputBlur(e) {\n blurTimeout = $timeout(function() {\n // race condition can cause input to be destroyed before timeout ends\n if(!input) return false;\n var activeElement = $document.prop('activeElement'),\n lostFocusToBrowserWindow = activeElement === input[0],\n lostFocusToChildElement = element.find('.host')[0].contains(activeElement);\n\n if(lostFocusToBrowserWindow || !lostFocusToChildElement) {\n scope.hasFocus = false;\n events.trigger('input-blur', e);\n }\n }, 150); // timeout so that click event triggers first\n }\n\n function handleInputFocus(e) {\n if(e) e.preventDefault();\n if(scope.ngDisabled) return;\n\n selectAll(e.target);\n\n if(blurTimeout) $timeout.cancel(blurTimeout);\n\n scope.hasFocus = true;\n events.trigger('input-focus', input.val());\n\n if(!/apply|digest/.test(scope.$root.$$phase)) scope.$apply();\n }\n\n function handleTextareaKeydown(e) {\n if(e.keyCode === KEYS.enter) {\n if(!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {\n e.preventDefault();\n scope.processBulk();\n }\n }\n }\n\n function handleDivClick(e) {\n var $target = $(e.target);\n if(!$target.closest('.suggestion').length &&\n // we don't want any of the buttons underneath to trigger\n !$target.parent().hasClass('help-block')) {\n e.preventDefault();\n input[0].focus();\n }\n }\n\n // stupid ugly hack to fix order between input and autocomplete events\n let uglyHackTimeout = $timeout(function() {\n input\n .on('keydown', handleInputKeydown)\n .on('focus', handleInputFocus)\n .on('blur', handleInputBlur);\n });\n\n textarea.on('keydown', handleTextareaKeydown);\n\n div.on('click', handleDivClick);\n\n scope.$on('$destroy', function() {\n input\n .off('keydown', handleInputKeydown)\n .off('focus', handleInputFocus)\n .off('blur', handleInputBlur);\n\n textarea.off('keydown', handleTextareaKeydown);\n div.off('click', handleDivClick);\n input = null;\n textarea = null;\n div = null;\n events.destroy();\n events = null;\n first = null;\n hotkeys = null;\n options = null;\n tagList = null;\n $timeout.cancel(uglyHackTimeout);\n });\n }\n };\n }]);\n\n /**\n * @ngdoc directive\n * @name autoComplete\n * @module cnTagsInput\n *\n * @description\n * Provides autocomplete support for the tagsInput directive.\n *\n * @param {expression} source Expression to evaluate upon changing the input content. The input value is available as\n * $query. The result of the expression must be a promise that eventually resolves to an\n * array of strings.\n * @param {number=} [debounceDelay=100] Amount of time, in milliseconds, to wait before evaluating the expression in\n * the source option after the last keystroke.\n * @param {number=} [minLength=3] Minimum number of characters that must be entered before evaluating the expression\n * in the source option.\n * @param {boolean=} [highlightMatchedText=true] Flag indicating that the matched text will be highlighted in the\n * suggestions list.\n * @param {number=} [maxResultsToShow=10] Maximum number of results to be displayed at a time.\n */\n tagsInput.directive('autoComplete', [\n \"$document\", \"$timeout\", \"$filter\", \"$sce\", \"tagsInputConfig\", \"$parse\", 'Api', '$q',\n function($document, $timeout, $filter, $sce, tagsInputConfig, $parse, Api, $q) {\n function SuggestionList(scope, options) {\n var self = {}, debouncedLoadId, getDifference, lastPromise, groupList,\n splitListItems, formatItemText, mapIndexes;\n\n groupList = function(list, groupBy) {\n var filtered = {},\n map = [],\n index = 0,\n keys;\n\n // loop through each item in the list\n _.each(list, function(item) {\n keys = $parse(groupBy)(item);\n if(!_.isArray(keys)) keys = [keys];\n _.each(keys, function(key) {\n if(!filtered[key]) {\n filtered[key] = [];\n }\n filtered[key].push(item);\n });\n });\n\n _.each(filtered, function(group) {\n group.indexes = [];\n _.each(group, function(item) {\n group.indexes.push(index++);\n map.push(item);\n });\n });\n\n return {\n groups: filtered,\n map: map\n };\n };\n\n formatItemText = function(item, formatter) {\n if(formatter) {\n if(!_.isArray(formatter)) {\n formatter = [formatter, {}];\n }\n return $parse(formatter[0])((formatter[1].val = item) && formatter[1]);\n }\n\n return item;\n };\n\n splitListItems = function(items) {\n var keys = [];\n\n function addItem(key, item, group, prop) {\n var text = _.isObject(item) ? item[prop || options.tagsInput.displayProperty] : item,\n toAdd = {\n text: formatItemText(text, group.formatter),\n value: text,\n key: key,\n childKey: prop/*,\n tagClass: options.tagClasses && options.tagClasses[key] || options.tagClass*/\n };\n\n if(!_.find(group.items, toAdd)) {\n group.items.push(toAdd);\n }\n }\n\n _.each(scope.searchKeys, function(group) {\n var key = group.key;\n group.items = [];\n\n _.each(items, function(item) {\n if(item[key]) {\n if(_.isArray(item[key])) {\n _.each(item[key], function(child) {\n addItem(key, child, group, group.childKey);\n });\n }\n else {\n addItem(key, item[key], group, group.childKey);\n }\n }\n });\n keys.push(group);\n });\n\n return keys;\n };\n\n mapIndexes = function(items) {\n var map = [],\n index = 0;\n\n _.each(items, function(group) {\n group.indexes = [];\n _.each(group.items, function(item) {\n group.indexes.push(index++);\n map.push(item);\n });\n });\n\n return map;\n };\n\n getDifference = function(array1, array2) {\n if(!array2.length) {\n return array1.filter(function(item) {\n return item[options.tagsInput.displayProperty] !== '';\n });\n }\n return array1.filter(function(item) {\n return !findInObjectArray(\n array2,\n item,\n options.tagsInput.valueProperty || options.tagsInput.getTagText\n );\n });\n };\n\n self.reset = function() {\n lastPromise = null;\n\n self.items = [];\n self.visible = false;\n self.index = -1;\n self.selected = null;\n self.query = null;\n\n $timeout.cancel(debouncedLoadId);\n };\n\n self.show = function() {\n self.selected = null;\n self.visible = true;\n self.select(0);\n };\n\n self.load = function(query, tags) {\n if(query.length < options.minLength) {\n self.reset();\n return;\n }\n\n var promise,\n //filterBy = {},\n filterBy = query,\n groups,\n processItems = function(items) {\n if(promise && promise !== lastPromise) {\n return;\n }\n\n if(scope.searchKeys) {\n scope.isGroups = true;\n //filterBy = query;\n items = splitListItems(items);\n }\n if(_.isObject(items) && !_.isArray(items)) {\n scope.isGroups = true;\n items = _.map(items, function(list, group) {\n return {\n items: list,\n label: group\n };\n });\n }\n if(scope.isGroups) {\n _.each(items, function(group) {\n group.items = getDifference(group.items, tags);\n if(query) {\n let reconciliateItems = {};\n group.items.map((item, idx) => {\n item.__uniqueid = _.uniqueId('__uniqueid');\n reconciliateItems[item.__uniqueid] =_.cloneDeep(item);\n if ('key' in item) delete item.key;\n if ('childKey' in item) delete item.childKey;\n });\n group.items = $filter('cnFilter')(group.items, filterBy);\n if (options.tagsInput.sortFilteredResults) {\n group.items = sortResults(group.items, filterBy, options.tagsInput.displayProperty);\n }\n group.items.map((item) => {\n let ref = reconciliateItems[item.__uniqueid];\n if ('key' in ref) item.key = ref.key;\n if ('childKey' in ref) item.childKey = ref.childKey;\n delete item.__uniqueid;\n });\n }\n\n group.items = group.items.slice(0, options.maxResultsToShow);\n });\n self.itemMap = mapIndexes(items);\n }\n else {\n //filterBy[options.tagsInput.displayProperty] = query;\n items = makeObjectArray(items.data || items, options.tagsInput.displayProperty);\n items = getDifference(items, tags);\n if(query && !options.skipFiltering) {\n items = $filter('cnFilter')(items, filterBy);\n }\n\n if (options.tagsInput.sortFilteredResults) {\n items = sortResults(items, filterBy, options.tagsInput.displayProperty);\n }\n\n items = items.slice(0, options.maxResultsToShow);\n\n if(options.groupBy) {\n groups = groupList(items, options.groupBy);\n items = groups.groups;\n self.itemMap = groups.map;\n }\n }\n\n self.items = items;\n self.show();\n };\n\n $timeout.cancel(debouncedLoadId);\n self.query = query;\n debouncedLoadId = $timeout(function() {\n self._load(query, promise).then(processItems);\n }, options.minLength ? options.debounceDelay : 0, false);\n };\n\n self.clearCache = function(event, query) {\n event.preventDefault();\n if(scope._source) scope.source = scope._source;\n var source = scope.source;\n source({$query: query, options: { refreshData: true }})\n .then(function(results) {\n scope._source = source;\n scope.source = function() {\n return results;\n };\n scope.tagsInput.focusInput();\n });\n };\n\n self._load = function(query, promise) {\n var d = $q.defer();\n var source = scope.source({$query: query});\n if(_.isArray(source)) {\n $timeout(function() {\n d.resolve(source || []);\n });\n }\n else {\n promise = source;\n lastPromise = promise;\n return promise;\n }\n return d.promise;\n };\n\n self.selectNext = function() {\n self.select(++self.index);\n };\n\n self.selectPrior = function() {\n self.select(--self.index);\n };\n\n self.select = function(index) {\n var list = self.itemMap || self.items;\n if(index < 0) {\n index = list.length - 1;\n }\n else if(index >= list.length) {\n index = 0;\n }\n self.index = index;\n if(self.itemMap) {\n self.selected = self.itemMap[index];\n }\n else {\n self.selected = self.items[index];\n }\n };\n\n return self;\n }\n\n function encodeHTML(value) {\n return value ? value\n .replace(/&/g, '&')\n .replace(//g, '>') : '';\n }\n\n return {\n restrict: 'E',\n require: '^tagsInput',\n scope: {\n source: '&',\n searchKeys: '=?'\n },\n templateUrl: function(elem, attrs) {\n return attrs.customTemplateUrl || 'cnTagsInput/auto-complete.html';\n },\n link: function(scope, element, attrs, tagsInputCtrl) {\n var hotkeys = [KEYS.enter, KEYS.tab, KEYS.escape, KEYS.up, KEYS.down],\n suggestionList, tagsInput, options, getItemText, documentClick;\n\n function autoCompleteTag() {}\n scope.__tag = new autoCompleteTag();\n\n tagsInputConfig.load('autoComplete', scope, attrs, {\n debounceDelay: [Number, 250],\n minLength: [Number, 3],\n singleQuery: [Boolean, false],\n highlightMatchedText: [Boolean, true],\n maxResultsToShow: [Number, 75],\n groupBy: [String, ''],\n skipFiltering: [Boolean, false]\n });\n\n options = scope.options;\n\n tagsInput = tagsInputCtrl.registerAutocomplete();\n scope.tagsInput = tagsInput;\n\n options.tagsInput = tagsInput.getOptions();\n\n if(options.minLength === 0/* && _.isArray(scope.source())*/) {\n options.tagsInput.dropdownIcon = true;\n if(options.tagsInput.maxTags === 1) {\n options.tagsInput.dropdownStyle = 'caret';\n }\n else {\n options.tagsInput.dropdownStyle = 'fa fa-plus';\n }\n }\n else {\n options.tagsInput.dropdownStyle = 'fa fa-search';\n }\n\n suggestionList = new SuggestionList(scope, options);\n tagsInput.registerSuggestionList(suggestionList);\n\n getItemText = options.tagsInput.itemFormatter || function(item) {\n return String(item[options.tagsInput.displayProperty]);\n };\n\n scope.suggestionList = suggestionList;\n\n var tagsValue = tagsInput.getModel();\n\n if(options.singleQuery && tagsValue && !angular.equals(tagsValue, [])) {\n suggestionList._load().then(results => {\n var tags = findTagsForValue(results, tagsValue, options.tagsInput);\n var curTags = tagsInput.getTags();\n if(!angular.equals(tags, curTags)) {\n curTags.length = 0; // hack to get event to retrigger\n tags.forEach(tag => tagsInput.addTag(tag));\n }\n });\n }\n\n scope.addSuggestion = function(e) {\n e.preventDefault();\n\n var added = false;\n\n if(suggestionList.selected) {\n tagsInput.addTag(angular.copy(suggestionList.selected));\n\n if(!options.tagsInput.maxTags || tagsInput.getTags().length < options.tagsInput.maxTags) {\n var i = suggestionList.items.indexOf(suggestionList.selected);\n suggestionList.items.splice(i, 1);\n suggestionList.select(i);\n tagsInput.focusInput();\n }\n else {\n suggestionList.reset();\n tagsInput.blurInput();\n }\n\n added = true;\n }\n return added;\n };\n\n scope.highlight = function(item, key) {\n var text = getItemText(item, key);\n if(suggestionList.query && options.highlightMatchedText) {\n text =\n _(text.match(/(<[^>]*>|[^<]*)/g)) // regex will create a list of all html and text nodes\n .map(s => s.length && s[0] !== '<' ? replaceAll(s, suggestionList.query, '$&') : s)\n .join('');\n }\n return $sce.trustAsHtml('' + text + '');\n };\n\n scope.track = function(item, key) {\n return getItemText(item, key);\n };\n\n scope.noResultsMessage = function({visible, query}) {\n if(!query) return 'No options...';\n return $sce.trustAsHtml(`No results for ${query}...`);\n };\n\n tagsInput.registerProcessBulk(function(bulkTags) {\n var tags = bulkTags.split(options.tagsInput.bulkDelimiter);\n var addTags = function(i) {\n return function(data) {\n _.times(i, function(i) {\n if(data[i]) tagsInput.addTag(data[i]);\n });\n };\n };\n\n if (options.tagsInput.bulkSingleRequest) {\n let request_config = JSON.parse(options.tagsInput.bulkSingleRequest);\n console.log(request_config);\n return Api.post({\n url: request_config.url,\n data: {\n location_types: request_config.location_types,\n terms: tags,\n }\n }).then(response => {\n response.map(item => {\n console.log(item);\n tagsInput.addTag(item);\n });\n });\n }\n // in case a query is involved...doesn't hurt to use even if not\n return Api.batch(function() {\n for(var i = 0, l = tags.length; i < l; i++) {\n if(options.tagsInput.maxTags && tagsInput.getTags().length >= options.tagsInput.maxTags) break;\n var tag = tags[i];\n var times = 1;\n var multiple = tags[i].match(/(.*) ?\\[(\\d+)\\]$/);\n\n if(multiple) {\n tag = multiple[1];\n times = parseInt(multiple[2]);\n }\n\n var results = scope.source({$query: tag});\n\n if(_.isArray(results)) {\n if(results.length) {\n if(!options.skipFiltering) {\n var filterBy = tag;\n results = $filter('cnFilter')(results, filterBy);\n }\n if (options.tagsInput.sortFilteredResults) {\n results = sortResults(results, tag, options.tagsInput.displayProperty);\n }\n addTags(times)(results);\n }\n else if(!options.tagsInput.addFromAutocompleteOnly) {\n tagsInput.addTag({\n [options.tagsInput.displayProperty]: tag,\n [options.tagsInput.valueProperty]: tag\n });\n }\n }\n else if(results.then) {\n results.then(addTags(times));\n }\n }\n });\n });\n\n tagsInput\n .on('input-change', function(value) {\n if(value || !options.minLength) {\n suggestionList.load(value, tagsInput.getTags());\n }\n else {\n suggestionList.reset();\n }\n })\n .on('input-focus', function(value) {\n if(!suggestionList.visible) {\n suggestionList.load(value, tagsInput.getTags());\n }\n })\n .on('input-keydown', function(e) {\n var key, handled;\n\n if(hotkeys.indexOf(e.keyCode) === -1) {\n return;\n }\n\n // This hack is needed because jqLite doesn't implement stopImmediatePropagation properly.\n // I've sent a PR to Angular addressing this issue and hopefully it'll be fixed soon.\n // https://github.com/angular/angular.js/pull/4833\n var immediatePropagationStopped = false;\n e.stopImmediatePropagation = function() {\n immediatePropagationStopped = true;\n e.stopPropagation();\n };\n e.isImmediatePropagationStopped = function() {\n return immediatePropagationStopped;\n };\n\n if(suggestionList.visible) {\n key = e.keyCode;\n handled = false;\n\n if(key === KEYS.down) {\n suggestionList.selectNext();\n handled = true;\n }\n else if(key === KEYS.up) {\n suggestionList.selectPrior();\n handled = true;\n }\n else if(key === KEYS.escape) {\n suggestionList.reset();\n handled = true;\n }\n else if(key === KEYS.enter) {\n handled = scope.addSuggestion(e);\n }\n\n if(handled) {\n e.preventDefault();\n e.stopImmediatePropagation();\n scope.$apply();\n }\n }\n })\n .on('input-blur', function(e) {\n //changed to use document click or focus, as this fires too soon and cancels\n //automcomplete click events\n suggestionList.reset();\n });\n\n documentClick = function(e) {\n if(e.isDefaultPrevented()) return;\n\n if(suggestionList.visible) {\n // if autocomplete option was selected, or click/focus triggered outside of directive\n if(($(e.target).closest('.suggestion').length || !$(e.target).closest(element[0]).length) &&\n !(e.type === 'blur' && !/^(input|select|textarea|button|a)$/i.test(e.target.tagName))) {\n suggestionList.reset();\n if(!/apply|digest/.test(scope.$root.$$phase)) scope.$apply();\n }\n }\n };\n\n $document\n .on('click', documentClick)\n .on('blur', documentClick);\n\n scope.$on('$destroy', function() {\n $document\n .off('click', documentClick)\n .off('blur', documentClick);\n\n empty(tagsInput);\n tagsInput = null;\n\n empty(options);\n options = null;\n });\n }\n };\n }]);\n\n\n /**\n * @ngdoc directive\n * @name tiTranscludeAppend\n * @module cnTagsInput\n *\n * @description\n * Re-creates the old behavior of ng-transclude. Used internally by tagsInput directive.\n */\n tagsInput.directive('tiTranscludeAppend', function() {\n return function(scope, element, attrs, ctrl, transcludeFn) {\n transcludeFn(function(clone) {\n element.append(clone);\n });\n };\n });\n\n /**\n * @ngdoc directive\n * @name tiAutosize\n * @module cnTagsInput\n *\n * @description\n * Automatically sets the input's width so its content is always visible. Used internally by tagsInput directive.\n */\n tagsInput.directive('tiAutosize', function() {\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function(scope, element, attrs, ctrl) {\n var THRESHOLD = 3,\n span, resize;\n\n span = angular.element('');\n span.css('display', 'none')\n .css('visibility', 'hidden')\n .css('width', 'auto')\n .css('white-space', 'pre');\n\n element.parent().append(span);\n\n resize = function(originalValue) {\n var value = originalValue, width;\n\n if(angular.isString(value) && value.length === 0) {\n value = attrs.placeholder;\n }\n\n if(value) {\n span.text(value);\n span.css('display', '');\n width = span.prop('offsetWidth');\n span.css('display', 'none');\n }\n\n element.css('width', width ? width + THRESHOLD + 'px' : '');\n\n return originalValue;\n };\n\n ctrl.$parsers.unshift(resize);\n ctrl.$formatters.unshift(resize);\n\n attrs.$observe('placeholder', function(value) {\n if(!ctrl.$modelValue) {\n resize(value);\n }\n });\n }\n };\n });\n\n /**\n * @ngdoc service\n * @name tagsInputConfig\n * @module cnTagsInput\n *\n * @description\n * Sets global configuration settings for both tagsInput and autoComplete directives. It's also used internally to parse and\n * initialize options from HTML attributes.\n */\n tagsInput.provider('tagsInputConfig', function() {\n var globalDefaults = {}, interpolationStatus = {};\n\n /**\n * @ngdoc method\n * @name setDefaults\n * @description Sets the default configuration option for a directive.\n * @methodOf tagsInputConfig\n *\n * @param {string} directive Name of the directive to be configured. Must be either 'tagsInput' or 'autoComplete'.\n * @param {object} defaults Object containing options and their values.\n *\n * @returns {object} The service itself for chaining purposes.\n */\n this.setDefaults = function(directive, defaults) {\n globalDefaults[directive] = defaults;\n return this;\n };\n\n /***\n * @ngdoc method\n * @name setActiveInterpolation\n * @description Sets active interpolation for a set of options.\n * @methodOf tagsInputConfig\n *\n * @param {string} directive Name of the directive to be configured. Must be either 'tagsInput' or 'autoComplete'.\n * @param {object} options Object containing which options should have interpolation turned on at all times.\n *\n * @returns {object} The service itself for chaining purposes.\n */\n this.setActiveInterpolation = function(directive, options) {\n interpolationStatus[directive] = options;\n return this;\n };\n\n this.$get = [\"$interpolate\", function($interpolate) {\n var converters = {};\n converters[String] = function(value) {\n return value;\n };\n converters[Number] = function(value) {\n return parseInt(value, 10);\n };\n converters[Boolean] = function(value) {\n return value.toLowerCase() === 'true';\n };\n converters[RegExp] = function(value) {\n return new RegExp(value);\n };\n converters[Object] = function(value) {\n return typeof value === 'object' ? value : Object(value);\n };\n\n return {\n load: function(directive, scope, attrs, options) {\n scope.options = {};\n scope.attrs = attrs;\n scope.uid = _.uniqueId();\n\n angular.forEach(options, function(value, key) {\n var type, localDefault, converter, getDefault, updateValue;\n\n type = value[0];\n localDefault = value[1];\n converter = converters[type];\n\n getDefault = function() {\n var globalValue = globalDefaults[directive] && globalDefaults[directive][key];\n return angular.isDefined(globalValue) ? globalValue : localDefault;\n };\n\n updateValue = function(value) {\n scope.options[key] = value ? converter(value) : getDefault();\n };\n\n if(scope[key]) {\n updateValue(scope[key]);\n }\n else if(interpolationStatus[directive] && interpolationStatus[directive][key]) {\n attrs.$observe(key, function(value) {\n updateValue(value);\n });\n }\n else {\n updateValue(attrs[key] && $interpolate(attrs[key])(scope.$parent));\n }\n });\n }\n };\n }];\n });\n\n\n /* HTML templates */\n tagsInput.run([\"$templateCache\", function($templateCache) {\n $templateCache.put('cnTagsInput/tags-input.html', `\n
    \n
  • \n \n \n
  • \n
\n
\n \n \n \n
\n \n \n \n \n ×\n \n \n \n \n
\n
\n
\n Batch\n \n Clear\n \n Update Data\n \n Copy\n \n
\n
\n \n

\n Press \"Enter\" to submit, \"Shift+Enter\" to add a new line\n

\n

\n Add multiple with brackets, eg. \"citizennet[10]\"\n

\n
\n \n
\n
`\n );\n\n $templateCache.put('cnTagsInput/auto-complete.html', `\n
\n
    \n
  • \n
\n
\n
\n
    \n
  • No results...
  • \n
  • \n
  • {{group.label | titleCase}}
  • \n
  • \n
  • \n
  • \n
  • \n
\n
\n
\n
    \n
  • \n
  • \n
\n
\n
\n
    \n
  • \n
  • {{group | titleCase}}
  • \n
  • \n
  • \n
  • \n
  • \n
\n
`\n );\n }]);\n})();\n"]} \ No newline at end of file +{"version":3,"sources":["all.js","cn-tags-input.js"],"names":["_defineProperty","obj","key","value","Object","defineProperty","enumerable","configurable","writable","_typeof","Symbol","iterator","constructor","prototype","empty","_","forOwn","_value","coll","set","SimplePubSub","events","on","names","handler","split","forEach","name","push","this","trigger","args","angular","call","destroy","makeObjectArray","array","key2","length","isObject","item","index","getArrayModelVal","options","arrayValueType","map","valueProperty","pluck","findInObjectArray","i","l","isFunction","objVal","has","toJson","toLowerCase","replaceAll","str","substr","newSubstr","expression","replace","RegExp","matchTagsWithModel","tags","model","isArray","equals","some","tag","findTagsForValue","matches","filter","find","val","matchTag","addFromAutocompleteOnly","each","v","m","modelType","tagValue","objectContains","small","large","every","selectAll","input","setSelectionRange","sortResults","results","displayProperty","valueFor","first","remove","result","startsWith","sortBy","reTag","second","test","search","third","concat","KEYS","backspace","tab","enter","escape","space","up","down","comma","tagsInput","module","directive","$timeout","$document","tagsInputConfig","$sce","$rootScope","TagList","getTagText","setTagText","tagIsValid","self","itemFormatter","text","tagText","minLength","maxLength","allowedTagsPattern","items","addText","add","disabled","trim","replaceSpacesWithDashes","maxTags","pop","$tag","$event","splice","removeLast","lastTagIndex","enableEditingLastTag","selected","removeAll","e","preventDefault","copyToClipboard","copyElement","document","createElement","style","position","opacity","textContent","join","body","getElementsByTagName","appendChild","select","execCommand","removeChild","restrict","require","scope","ngDisabled","onBeforeTagAdded","onBeforeTagRemoved","onBeforeTagChanged","onTagAdded","onTagRemoved","onTagChanged","onInit","newTag","transclude","templateUrl","controller","$scope","$attrs","$element","handleKeydown","load","placeholder","String","tabindex","Number","removeTagSymbol","fromCharCode","Boolean","addOnEnter","addOnSpace","addOnComma","addOnBlur","clearOnBlur","required","minTags","allowLeftoverText","tagClass","hideTags","dropdownIcon","tagsStyle","allowBulk","bulkSingleRequest","bulkDelimiter","bulkPlaceholder","sortFilteredResults","showClearAll","showClearCache","showButton","$on","off","tagList","processBulk","registerAutocomplete","addTag","focusInput","focus","blurInput","blur","getTags","getModel","getOptions","registerProcessBulk","fn","bulkTags","then","showBulk","registerSuggestionList","suggestionList","link","element","attrs","ngModelCtrl","tagsInputTag","beforeAndAfter","before","after","arguments","apply","inlineChangeTags","newTags","isObjectArray","handleInputKeydown","isImmediatePropagationStopped","shouldAdd","shouldRemove","keyCode","isModifier","shiftKey","altKey","ctrlKey","metaKey","addKeys","hotkeys","indexOf","$apply","handleInputBlur","blurTimeout","activeElement","prop","lostFocusToBrowserWindow","lostFocusToChildElement","contains","hasFocus","handleInputFocus","target","cancel","$root","$$phase","handleTextareaKeydown","handleDivClick","$target","$","closest","parent","hasClass","__tag","textarea","div","inputId","$name","$setValidity","undefined","invalid","getDisplayText","getDisplayHtml","trustAsHtml","track","newTagChange","triggerInit","prev","criteria","$prev","$setter","_ref2","$watch","changed","init","isUndefined","isDefined","$setDirty","uglyHackTimeout","$filter","$parse","Api","$q","SuggestionList","debouncedLoadId","getDifference","lastPromise","groupList","splitListItems","formatItemText","mapIndexes","list","groupBy","keys","filtered","group","indexes","groups","formatter","addItem","toAdd","childKey","searchKeys","child","array1","array2","reset","visible","query","show","promise","filterBy","processItems","isGroups","label","reconciliateItems","idx","__uniqueid","uniqueId","cloneDeep","ref","slice","maxResultsToShow","itemMap","data","skipFiltering","_load","debounceDelay","clearCache","event","_source","source","$query","refreshData","d","defer","resolve","selectNext","selectPrior","elem","customTemplateUrl","tagsInputCtrl","autoCompleteTag","getItemText","documentClick","singleQuery","highlightMatchedText","dropdownStyle","tagsValue","curTags","addSuggestion","added","copy","highlight","match","s","noResultsMessage","_ref3","addTags","times","request_config","JSON","parse","post","url","location_types","terms","response","batch","multiple","parseInt","_tagsInput$addTag","handled","immediatePropagationStopped","stopImmediatePropagation","stopPropagation","isDefaultPrevented","type","tagName","ctrl","transcludeFn","clone","append","span","resize","THRESHOLD","css","originalValue","width","isString","$parsers","unshift","$formatters","$observe","$modelValue","provider","globalDefaults","interpolationStatus","setDefaults","defaults","setActiveInterpolation","$get","$interpolate","converters","uid","localDefault","converter","getDefault","updateValue","globalValue","$parent","run","$templateCache","put"],"mappings":"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","file":"all.min.js","sourcesContent":["'use strict';\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n/*!;\n tagsInput = null;\n * ngTagsInput v2.0.1\n * http://mbenford.github.io/ngTagsInput\n *\n * Copyright (c) 2013-2014 Michael Benford\n * License: MIT\n *\n * Generated at 2014-04-13 21:25:38 -0300\n */\n(function () {\n 'use strict';\n\n var KEYS = {\n backspace: 8,\n tab: 9,\n enter: 13,\n escape: 27,\n space: 32,\n up: 38,\n down: 40,\n comma: 188\n };\n\n function empty(obj) {\n _.forOwn(obj, function (_value, key, coll) {\n _.set(coll, key, null);\n });\n }\n\n function SimplePubSub() {\n var events = {};\n return {\n on: function on(names, handler) {\n names.split(' ').forEach(function (name) {\n if (!events[name]) {\n events[name] = [];\n }\n events[name].push(handler);\n });\n return this;\n },\n trigger: function trigger(name, args) {\n angular.forEach(events[name], function (handler) {\n handler.call(null, args);\n });\n return this;\n },\n destroy: function destroy() {\n empty(events);\n events = null;\n }\n };\n }\n\n function makeObjectArray(array, key, key2) {\n array = array || [];\n if (array.length > 0 && !angular.isObject(array[0])) {\n array.forEach(function (item, index) {\n array[index] = _defineProperty({}, key, item);\n if (key2) array[index][key2] = item;\n });\n }\n return array;\n }\n\n function getArrayModelVal(array, options) {\n if (options.arrayValueType === 'object') {\n return (array || []).map(function (item) {\n return _.isObject(item && item[options.valueProperty]) ? item[options.valueProperty] : item;\n });\n } else {\n return _.pluck(array, options.valueProperty);\n }\n }\n\n function findInObjectArray(array, obj, key) {\n var item = null;\n var i = 0;\n var l = array.length;\n\n if (_.isFunction(key)) {\n var objVal = key(obj);\n if (!objVal) return null;\n for (; i < l; i++) {\n if (objVal === key(array[i])) {\n item = array[i];\n break;\n }\n }\n } else {\n for (; i < l; i++) {\n // I'm aware of the internationalization issues regarding toLowerCase()\n // but I couldn't come up with a better solution right now\n if (_.has(obj, key) && _.has(array[i], key) && (angular.toJson(array[i][key]) + '').toLowerCase() === (angular.toJson(obj[key]) + '').toLowerCase()) {\n item = array[i];\n break;\n }\n }\n }\n return item;\n }\n\n function replaceAll(str, substr, newSubstr) {\n var expression = substr.replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n return str.replace(new RegExp(expression, 'gi'), newSubstr);\n }\n\n function matchTagsWithModel(tags, model, options) {\n if (!model || !tags || !tags.length) return false;\n\n if (!_.isArray(model)) {\n return angular.equals(model, tags[0][options.valueProperty]) || angular.equals(model, tags[0]);\n }\n\n var array = getArrayModelVal(tags, options);\n return _.some(array, function (tag, i) {\n return angular.equals(model[i], tag) || angular.equals(model[i], tag[options.valueProperty]);\n });\n }\n\n function findTagsForValue(tags, value, options) {\n if (_.isArray(value)) {\n var matches = _.filter(tags, function (tag) {\n return _.find(value, function (val) {\n return matchTag(tag, val, options.valueProperty, options.arrayValueType);\n });\n });\n\n if (!options.addFromAutocompleteOnly && matches.length < value.length) {\n _.each(value, function (v) {\n if (!_.find(matches, function (m) {\n return matchTag(m, v, options.valueProperty, options.arrayValueType);\n })) matches.push(v);\n });\n }\n\n return matches;\n }\n\n return _.filter(tags, function (tag) {\n return matchTag(tag, value, options.valueProperty, options.modelType);\n });\n }\n\n function matchTag(tag, value, valueProperty, modelType) {\n var tagValue = valueProperty ? tag[valueProperty] : tag;\n return modelType === 'object' ? objectContains(value, tagValue) : value == tagValue;\n }\n\n function objectContains(small, large) {\n if (angular.isArray(small)) {\n return angular.equals(small, large);\n }\n return _.every(small, function (val, key) {\n return key === '$$hashKey' || (angular.isObject(val) ? objectContains(val, large[key]) : val == large[key]);\n });\n }\n\n function selectAll(input) {\n if (input.value) {\n input.setSelectionRange(0, input.value.length);\n }\n }\n\n function sortResults(results, tag, displayProperty) {\n var valueFor = function valueFor(val) {\n return displayProperty && val[displayProperty] ? val[displayProperty] : val;\n };\n var first = _.remove(results, function (result) {\n return _.startsWith(valueFor(result), valueFor(tag));\n });\n first = _.sortBy(first, [function (result) {\n return valueFor(result).length;\n }]);\n var reTag = new RegExp(valueFor(tag), \"i\");\n var second = _.remove(results, function (result) {\n return reTag.test(valueFor(result));\n });\n second = _.sortBy(second, [function (result) {\n return valueFor(result).search(reTag);\n }, function (result) {\n return valueFor(result).length;\n }]);\n var third = _.sortBy(results, [function (result) {\n return valueFor(result).length;\n }]);\n return first.concat(second, third);\n }\n\n var tagsInput = angular.module('cnTagsInput', []);\n\n /**\n * @ngdoc directive\n * @name tagsInput\n * @module cnTagsInput\n *\n * @description\n * Renders an input box with tag editing support.\n *\n * @param {string} ngModel Assignable angular expression to data-bind to.\n * @param {string=} [displayProperty=text] Property to be rendered as the tag label.\n * @param {string=} [valueProperty=value] Property to be used as the value when modelType is not array/object.\n * @param {number=} tabindex Tab order of the control.\n * @param {string=} [placeholder=Add a tag] Placeholder text for the control.\n * @param {number=} [minLength=3] Minimum length for a new tag.\n * @param {number=} maxLength Maximum length allowed for a new tag.\n * @param {boolean=} required Sets required validation error key.\n * @param {number=} minTags Sets minTags validation error key if the number of tags added is less than minTags.\n * @param {number=} maxTags Sets maxTags validation error key if the number of tags added is greater than maxTags.\n * @param {boolean=} [allowLeftoverText=false] Sets leftoverText validation error key if there is any leftover text in\n * the input element when the directive loses focus.\n * @param {string=} [removeTagSymbol=×] Symbol character for the remove tag button.\n * @param {boolean=} [addOnEnter=true] Flag indicating that a new tag will be added on pressing the ENTER key.\n * @param {boolean=} [addOnSpace=false] Flag indicating that a new tag will be added on pressing the SPACE key.\n * @param {boolean=} [addOnComma=true] Flag indicating that a new tag will be added on pressing the COMMA key.\n * @param {boolean=} [addOnBlur=false] Flag indicating that a new tag will be added when the input field loses focus.\n * @param {boolean=} [clearOnBlur=false] Flag indicating whether to clear the typed text when the input field loses focus.\n * @param {boolean=} [replaceSpacesWithDashes=false] Flag indicating that spaces will be replaced with dashes.\n * @param {string=} [allowedTagsPattern=.+] Regular expression that determines whether a new tag is valid.\n * @param {boolean=} [enableEditingLastTag=false] Flag indicating that the last tag will be moved back into\n * the new tag input box instead of being removed when the backspace key\n * is pressed and the input box is empty.\n * @param {boolean=} [addFromAutocompleteOnly=false] Flag indicating that only tags coming from the autocomplete list will be allowed.\n * When this flag is true, addOnEnter, addOnComma, addOnSpace, addOnBlur and\n * allowLeftoverText values are ignored.\n * @param {expression} onBeforeTagAdded Expression to evaluate upon adding a new tag. The new tag is available as $tag.\n * @param {expression} onBeforeTagRemoved Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.\n * @param {expression} onBeforeTagChanged Expression to evaluate upon adding or removing a tag. The affected tag is available as $tag. Prev value avialble as $prev.\n * @param {expression} onTagAdded Expression to evaluate upon adding a new tag. The new tag is available as $tag.\n * @param {expression} onTagRemoved Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.\n * @param {expression} onTagChanged Expression to evaluate upon adding or removing a tag. The affected tag is available as $tag. Prev value avialble as $prev.\n * @param {expression} onInit Expression to evaluate upon initializing model value.\n * @param {string} modelType Defines ngModel type, if anything other than array, model is set to first tag in list\n * @param {string} arrayValueType Defines ngModel[] type, if anything other than object, value is set mapped from object's values\n * @param {boolean=} [hideTags=false] Flag indicating whether to hide tag list (for manually displaying tag list in other way)\n * @param {boolean=} [dropdownIcon=false] Flag to show icon on right side\n * @param {string=} [tagsStyle='tags'] Default tags style\n * @param {boolean=} sortFilteredResults Flag to set whether to sort autocomplete list\n */\n tagsInput.directive('tagsInput', [\"$timeout\", \"$document\", \"tagsInputConfig\", \"$sce\", \"$rootScope\", function ($timeout, $document, tagsInputConfig, $sce, $rootScope) {\n function TagList(options, events) {\n var self = {},\n getTagText,\n setTagText,\n tagIsValid;\n\n getTagText = options.getTagText = function (tag) {\n if (!_.isObject(tag)) return tag;\n return options.itemFormatter ? options.itemFormatter(tag) : tag[options.displayProperty];\n };\n\n setTagText = function setTagText(tag, text) {\n // only create tag object when not adding from auto-complete\n if (tag[options.displayProperty]) return;\n\n tag[options.displayProperty] = text;\n if (options.valueProperty && !_.has(tag, options.valueProperty)) {\n tag[options.valueProperty] = text;\n }\n };\n\n tagIsValid = function tagIsValid(tag) {\n var tagText = getTagText(tag) + '';\n\n return (!options.minLength || tagText.length >= options.minLength) && (!options.maxLength || tagText.length <= options.maxLength) && options.allowedTagsPattern.test(tagText) && !findInObjectArray(self.items, tag, options.valueProperty || getTagText);\n };\n\n self.items = [];\n\n self.addText = function (text) {\n var tag = {};\n setTagText(tag, text);\n self.add(tag);\n };\n\n self.add = function (tag) {\n if (tag.disabled) return;\n\n var tagText = getTagText(tag);\n\n if (tagText.trim) tagText = tagText.trim();\n\n if (options.replaceSpacesWithDashes) {\n tagText = tagText.replace(/\\s/g, '-');\n }\n\n setTagText(tag, tagText);\n\n if (tagIsValid(tag)) {\n if (options.maxTags && self.items.length >= options.maxTags) {\n self.items.pop();\n events.trigger('tag-removed', { $tag: tag, $event: 'tag-removed' });\n }\n self.items.push(tag);\n events.trigger('tag-added', { $tag: tag, $event: 'tag-added' });\n } else {\n events.trigger('invalid-tag', { $tag: tag, $event: 'invalid-tag' });\n }\n return tag;\n };\n\n self.remove = function (index) {\n var tag = self.items.splice(index, 1)[0];\n events.trigger('tag-removed', { $tag: tag, $event: 'tag-removed' });\n return tag;\n };\n\n self.removeLast = function () {\n var tag,\n lastTagIndex = self.items.length - 1;\n\n if (options.enableEditingLastTag || self.selected) {\n self.selected = null;\n tag = self.remove(lastTagIndex);\n } else if (!self.selected) {\n self.selected = self.items[lastTagIndex];\n }\n\n return tag;\n };\n\n self.removeAll = function (e) {\n e.preventDefault();\n var tags = self.items.splice(0, self.items.length);\n tags.forEach(function (tag) {\n events.trigger('tag-removed', { $tag: tag, $event: 'tag-removed' });\n });\n };\n\n self.copyToClipboard = function () {\n var copyElement = document.createElement(\"textarea\");\n copyElement.style.position = 'fixed';\n copyElement.style.opacity = '0';\n copyElement.textContent = self.items.map(function (e) {\n return options.displayProperty && e[options.displayProperty] ? e[options.displayProperty] : e;\n }).join('\\n');\n var body = document.getElementsByTagName('body')[0];\n body.appendChild(copyElement);\n copyElement.select();\n document.execCommand('copy');\n body.removeChild(copyElement);\n };\n\n self.destroy = function () {\n empty(self);\n self = null;\n };\n\n return self;\n }\n\n return {\n restrict: 'E',\n require: 'ngModel',\n scope: {\n tags: '=ngModel',\n itemFormatter: '=',\n ngDisabled: '=',\n onBeforeTagAdded: '&',\n onBeforeTagRemoved: '&',\n onBeforeTagChanged: '&',\n onTagAdded: '&',\n onTagRemoved: '&',\n onTagChanged: '&',\n onInit: '&',\n newTag: '=?'\n },\n replace: false,\n transclude: true,\n templateUrl: 'cnTagsInput/tags-input.html',\n controller: [\"$scope\", \"$attrs\", \"$element\", function ($scope, $attrs, $element) {\n tagsInputConfig.load('tagsInput', $scope, $attrs, {\n placeholder: [String, ''],\n tabindex: [Number],\n removeTagSymbol: [String, String.fromCharCode(215)],\n replaceSpacesWithDashes: [Boolean, false],\n minLength: [Number, 2],\n maxLength: [Number],\n addOnEnter: [Boolean, true],\n addOnSpace: [Boolean, false],\n addOnComma: [Boolean, true],\n addOnBlur: [Boolean, false],\n clearOnBlur: [Boolean, false],\n allowedTagsPattern: [RegExp, /.+/],\n enableEditingLastTag: [Boolean, false],\n required: [Boolean, false],\n minTags: [Number],\n maxTags: [Number],\n displayProperty: [String, 'text'],\n valueProperty: [String],\n allowLeftoverText: [Boolean, false],\n addFromAutocompleteOnly: [Boolean, false],\n tagClass: [String, ''],\n modelType: [String, 'array'],\n arrayValueType: [String, 'object'],\n hideTags: [Boolean, false],\n dropdownIcon: [Boolean, false],\n tagsStyle: [String, 'tags'],\n allowBulk: [Boolean, false],\n bulkSingleRequest: [String, ''],\n bulkDelimiter: [RegExp, /, ?|\\n/],\n bulkPlaceholder: [String, 'Enter a list separated by commas or new lines'],\n sortFilteredResults: [Boolean, false],\n showClearAll: [Boolean, false],\n showClearCache: [Boolean, false],\n showButton: [Boolean, false]\n });\n\n var options = $scope.options;\n var input = options.input = $element.find('input.input');\n\n function handleKeydown(e) {\n $scope.events.trigger('input-keydown', e);\n }\n\n input.on('keydown', handleKeydown);\n\n $scope.$on('$destroy', function () {\n input.off('keydown', handleKeydown);\n input = null;\n empty(options);\n options = null;\n $scope.events.destroy();\n $scope.tagList.destroy();\n $scope.processBulk = null;\n });\n\n if (!options.valueProperty && (!/object|array/.test(options.modelType) || options.arrayValueType !== 'object')) {\n options.valueProperty = 'value';\n }\n\n if ($scope.itemFormatter) options.itemFormatter = $scope.itemFormatter;\n\n if (options.tagsStyle === 'tags') {\n options.tagClass = options.tagClass || 'label-primary';\n }\n\n if (options.allowBulk && (options.modelType !== 'array' || options.maxTags === 1)) {\n options.allowBulk = false;\n }\n\n $scope.events = new SimplePubSub();\n $scope.tagList = new TagList(options, $scope.events);\n\n this.registerAutocomplete = function () {\n return {\n addTag: function addTag(tag) {\n return $scope.tagList.add(tag);\n },\n focusInput: function focusInput() {\n input[0].focus();\n },\n blurInput: function blurInput() {\n input[0].blur();\n },\n getTags: function getTags() {\n return $scope.tagList.items;\n },\n getModel: function getModel() {\n return $scope.tags;\n },\n getOptions: function getOptions() {\n return options;\n },\n on: function on(name, handler) {\n $scope.events.on(name, handler);\n return this;\n },\n registerProcessBulk: function registerProcessBulk(fn) {\n $scope.processBulk = function () {\n fn($scope.bulkTags).then(function () {\n $scope.showBulk = false;\n $scope.bulkTags = '';\n });\n };\n },\n registerSuggestionList: function registerSuggestionList(suggestionList) {\n $scope.tagList.suggestionList = suggestionList;\n }\n };\n };\n }],\n link: function link(scope, element, attrs, ngModelCtrl) {\n function tagsInputTag() {}\n scope.__tag = new tagsInputTag();\n\n var hotkeys = [KEYS.enter, KEYS.comma, KEYS.space, KEYS.backspace],\n tagList = scope.tagList,\n events = scope.events,\n options = scope.options,\n input = element.find('input.input'),\n textarea = element.find('textarea'),\n div = element.find('div'),\n blurTimeout;\n\n if (attrs.inputId && !ngModelCtrl.$name) {\n ngModelCtrl.$name = attrs.inputId;\n }\n\n // before callbacks allow code to modify tag before it's added\n // after callback fired after ngModel has chance to update\n function beforeAndAfter(before, after) {\n return function () {\n var args = arguments;\n before.apply(this, args);\n $timeout(function () {\n after.apply(this, args);\n });\n };\n }\n\n function inlineChangeTags() {\n return function () {\n if (arguments.length > 0 && _.isArray(arguments[0].$tag)) {\n var newTags = arguments[0].$tag;\n var isObjectArray = _.every(newTags, function (v) {\n return (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object' && v !== null && options.displayProperty && v[options.displayProperty];\n });\n if (isObjectArray) {\n if (scope.tagList && scope.tagList.items && newTags) {\n scope.tagList.items = newTags;\n }\n }\n }\n };\n }\n\n events.on('tag-added', beforeAndAfter(scope.onBeforeTagAdded, scope.onTagAdded)).on('tag-removed', beforeAndAfter(scope.onBeforeTagRemoved, scope.onTagRemoved)).on('tag-changed', beforeAndAfter(scope.onBeforeTagChanged, scope.onTagChanged)).on('tag-changed', inlineChangeTags()).on('tag-init', scope.onInit).on('tag-added tag-removed', function (e) {\n if (!options.maxTags || options.maxTags > scope.tagList.items.length) {\n selectAll(options.input[0]);\n } else {\n scope.newTag.text = '';\n }\n if (options.modelType === 'array') {\n if (!options.valueProperty) {\n scope.tags = scope.tagList.items;\n } else {\n scope.tags = getArrayModelVal(scope.tagList.items, options);\n }\n if (scope.tagList.items.length >= options.minTags) {\n ngModelCtrl.$setValidity('tv4-400', true);\n }\n } else {\n if (e.$event === 'tag-removed') {\n scope.tags = undefined;\n } else {\n if (!options.valueProperty) {\n scope.tags = e.$tag;\n } else {\n scope.tags = _.has(e.$tag, options.valueProperty) ? e.$tag[options.valueProperty] : e.$tag[options.displayProperty];\n }\n }\n }\n }).on('invalid-tag', function () {\n scope.newTag.invalid = true;\n }).on('input-change', function () {\n tagList.selected = null;\n scope.newTag.invalid = null;\n }).on('input-focus', function () {\n ngModelCtrl.$setValidity('leftoverText', true);\n }).on('input-blur', function () {\n if (!options.addFromAutocompleteOnly) {\n if (options.addOnBlur && scope.newTag.text) {\n tagList.addText(scope.newTag.text);\n }\n }\n\n // Reset newTag\n if (options.clearOnBlur) {\n scope.newTag.text = '';\n scope.newTag.invalid = null;\n }\n });\n\n scope.newTag = { text: '', invalid: null };\n\n scope.getDisplayText = scope.itemFormatter || function (tag) {\n return tag && ((tag[options.displayProperty] || 'undefined') + '').trim();\n };\n\n scope.getDisplayHtml = function (tag) {\n return $sce.trustAsHtml(scope.getDisplayText(tag));\n };\n\n scope.track = function (tag) {\n return tag[options.displayProperty];\n };\n\n scope.newTagChange = function () {\n events.trigger('input-change', scope.newTag.text);\n };\n\n scope.processBulk = scope.processBulk || function () {\n var tags = scope.bulkTags.split(options.bulkDelimiter);\n _.each(tags, function (text) {\n var tag = {};\n tag[options.displayProperty] = text;\n scope.tagList.add(tag);\n });\n scope.showBulk = false;\n scope.bulkTags = '';\n };\n\n var first = true;\n\n scope.triggerInit = function (value, prev) {\n var criteria = options.valueProperty ? _defineProperty({}, options.valueProperty, value) : value;\n if (!tagList.items.length || !_.find(tagList.items, criteria)) {\n events.trigger('tag-init', {\n $tag: value,\n $prev: prev,\n $event: 'tag-init',\n $setter: function $setter(val) {\n if (val && !_.isObject(val)) {\n var _ref2;\n\n tagList.items = [(_ref2 = {}, _defineProperty(_ref2, options.displayProperty, val), _defineProperty(_ref2, options.valueProperty, val), _ref2)];\n } else {\n tagList.items = _.isArray(val) ? val : [val];\n }\n return tagList.items;\n }\n });\n }\n };\n\n scope.$watch('tags', function (value, prev) {\n var changed = !angular.equals(value, prev);\n var init = !changed && first;\n\n if (init) {\n scope.triggerInit(value, prev);\n }\n if (changed) {\n events.trigger('tag-changed', {\n $tag: value,\n $prev: prev,\n $event: 'tag-changed'\n });\n }\n\n if (options.modelType === 'array') {\n if (_.isArray(value)) {\n if (value.length) {\n if (!matchTagsWithModel(tagList.items, scope.tags, options)) {\n scope.triggerInit(value, prev);\n }\n if (!matchTagsWithModel(tagList.items, scope.tags, options) || tagList.items.length !== scope.tags.length) {\n tagList.items = makeObjectArray(value, options.displayProperty, options.valueProperty);\n scope.tags = getArrayModelVal(tagList.items, options);\n return;\n }\n } else {\n tagList.items = [];\n if (angular.isUndefined(prev)) return;\n }\n } else if (value === undefined) {\n tagList.items = [];\n scope.tags = [];\n return;\n }\n } else if (angular.isDefined(value)) {\n if (_.isArray(value)) {\n if (value.length) {\n //if(options.modelType === 'object') {\n if (!options.valueProperty) {\n scope.tags = value[0];\n } else {\n scope.tags = value[0][options.valueProperty];\n }\n\n return;\n } else {\n scope.tags = undefined;\n }\n } else {\n if (options.modelType === 'object') {\n if (value !== null) tagList.items = [value];\n } else {\n if (_.isObject(value)) {\n tagList.items = [value];\n\n var val = value[options.valueProperty];\n if (_.isUndefined(val)) val = value[options.displayProperty];\n scope.tags = val;\n\n return;\n } else if (!_.isUndefined(value) && (!tagList.items.length || tagList.items[0][options.valueProperty] !== value)) {\n scope.triggerInit(value, prev);\n }\n }\n }\n } else if (!value && tagList.items.length) {\n tagList.items = [];\n }\n\n if (!init && changed) {\n ngModelCtrl.$setDirty();\n }\n\n // hack because schemaForm is incorrectly invalidating model sometimes\n ngModelCtrl.$setValidity('schemaForm', true);\n if (options.modelType === 'array') {\n ngModelCtrl.$setValidity('tv4-401', value && options.maxTags ? value.length <= options.maxTags : true);\n ngModelCtrl.$setValidity('tv4-302', value ? angular.isDefined(options.minTags) ? value.length >= options.minTags : true : false);\n } else {\n ngModelCtrl.$setValidity('tv4-302', !options.required || !angular.isUndefined(value));\n }\n\n first = false;\n }, true);\n\n function handleInputKeydown(e) {\n // This hack is needed because jqLite doesn't implement stopImmediatePropagation properly.\n // I've sent a PR to Angular addressing this issue and hopefully it'll be fixed soon.\n // https://github.com/angular/angular.js/pull/4833\n if (e.isImmediatePropagationStopped && e.isImmediatePropagationStopped()) {\n return;\n }\n\n var key = e.keyCode,\n isModifier = e.shiftKey || e.altKey || e.ctrlKey || e.metaKey,\n addKeys = {},\n shouldAdd,\n shouldRemove;\n\n if (isModifier || hotkeys.indexOf(key) === -1) {\n return;\n }\n\n addKeys[KEYS.enter] = options.addOnEnter;\n addKeys[KEYS.comma] = options.addOnComma;\n addKeys[KEYS.space] = options.addOnSpace;\n\n shouldAdd = !options.addFromAutocompleteOnly && addKeys[key];\n shouldRemove = !shouldAdd && key === KEYS.backspace && scope.newTag.text.length === 0;\n\n if (shouldAdd) {\n tagList.addText(scope.newTag.text);\n\n scope.$apply();\n e.preventDefault();\n } else if (shouldRemove) {\n var tag = tagList.removeLast();\n if (tag && options.enableEditingLastTag) {\n scope.newTag.text = tag[options.displayProperty];\n }\n\n scope.$apply();\n e.preventDefault();\n }\n }\n\n function handleInputBlur(e) {\n blurTimeout = $timeout(function () {\n // race condition can cause input to be destroyed before timeout ends\n if (!input) return false;\n var activeElement = $document.prop('activeElement'),\n lostFocusToBrowserWindow = activeElement === input[0],\n lostFocusToChildElement = element.find('.host')[0].contains(activeElement);\n\n if (lostFocusToBrowserWindow || !lostFocusToChildElement) {\n scope.hasFocus = false;\n events.trigger('input-blur', e);\n }\n }, 150); // timeout so that click event triggers first\n }\n\n function handleInputFocus(e) {\n if (e) e.preventDefault();\n if (scope.ngDisabled) return;\n\n selectAll(e.target);\n\n if (blurTimeout) $timeout.cancel(blurTimeout);\n\n scope.hasFocus = true;\n events.trigger('input-focus', input.val());\n\n if (!/apply|digest/.test(scope.$root.$$phase)) scope.$apply();\n }\n\n function handleTextareaKeydown(e) {\n if (e.keyCode === KEYS.enter) {\n if (!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {\n e.preventDefault();\n scope.processBulk();\n }\n }\n }\n\n function handleDivClick(e) {\n var $target = $(e.target);\n if (!$target.closest('.suggestion').length &&\n // we don't want any of the buttons underneath to trigger\n !$target.parent().hasClass('help-block')) {\n e.preventDefault();\n input[0].focus();\n }\n }\n\n // stupid ugly hack to fix order between input and autocomplete events\n var uglyHackTimeout = $timeout(function () {\n input.on('keydown', handleInputKeydown).on('focus', handleInputFocus).on('blur', handleInputBlur);\n });\n\n textarea.on('keydown', handleTextareaKeydown);\n\n div.on('click', handleDivClick);\n\n scope.$on('$destroy', function () {\n input.off('keydown', handleInputKeydown).off('focus', handleInputFocus).off('blur', handleInputBlur);\n\n textarea.off('keydown', handleTextareaKeydown);\n div.off('click', handleDivClick);\n input = null;\n textarea = null;\n div = null;\n events.destroy();\n events = null;\n first = null;\n hotkeys = null;\n options = null;\n tagList = null;\n $timeout.cancel(uglyHackTimeout);\n });\n }\n };\n }]);\n\n /**\n * @ngdoc directive\n * @name autoComplete\n * @module cnTagsInput\n *\n * @description\n * Provides autocomplete support for the tagsInput directive.\n *\n * @param {expression} source Expression to evaluate upon changing the input content. The input value is available as\n * $query. The result of the expression must be a promise that eventually resolves to an\n * array of strings.\n * @param {number=} [debounceDelay=100] Amount of time, in milliseconds, to wait before evaluating the expression in\n * the source option after the last keystroke.\n * @param {number=} [minLength=3] Minimum number of characters that must be entered before evaluating the expression\n * in the source option.\n * @param {boolean=} [highlightMatchedText=true] Flag indicating that the matched text will be highlighted in the\n * suggestions list.\n * @param {number=} [maxResultsToShow=10] Maximum number of results to be displayed at a time.\n */\n tagsInput.directive('autoComplete', [\"$document\", \"$timeout\", \"$filter\", \"$sce\", \"tagsInputConfig\", \"$parse\", 'Api', '$q', function ($document, $timeout, $filter, $sce, tagsInputConfig, $parse, Api, $q) {\n function SuggestionList(scope, options) {\n var self = {},\n debouncedLoadId,\n getDifference,\n lastPromise,\n groupList,\n splitListItems,\n formatItemText,\n mapIndexes;\n\n groupList = function groupList(list, groupBy) {\n var filtered = {},\n map = [],\n index = 0,\n keys;\n\n // loop through each item in the list\n _.each(list, function (item) {\n keys = $parse(groupBy)(item);\n if (!_.isArray(keys)) keys = [keys];\n _.each(keys, function (key) {\n if (!filtered[key]) {\n filtered[key] = [];\n }\n filtered[key].push(item);\n });\n });\n\n _.each(filtered, function (group) {\n group.indexes = [];\n _.each(group, function (item) {\n group.indexes.push(index++);\n map.push(item);\n });\n });\n\n return {\n groups: filtered,\n map: map\n };\n };\n\n formatItemText = function formatItemText(item, formatter) {\n if (formatter) {\n if (!_.isArray(formatter)) {\n formatter = [formatter, {}];\n }\n return $parse(formatter[0])((formatter[1].val = item) && formatter[1]);\n }\n\n return item;\n };\n\n splitListItems = function splitListItems(items) {\n var keys = [];\n\n function addItem(key, item, group, prop) {\n var text = _.isObject(item) ? item[prop || options.tagsInput.displayProperty] : item,\n toAdd = {\n text: formatItemText(text, group.formatter),\n value: text,\n key: key,\n childKey: prop /*,\n tagClass: options.tagClasses && options.tagClasses[key] || options.tagClass*/\n };\n\n if (!_.find(group.items, toAdd)) {\n group.items.push(toAdd);\n }\n }\n\n _.each(scope.searchKeys, function (group) {\n var key = group.key;\n group.items = [];\n\n _.each(items, function (item) {\n if (item[key]) {\n if (_.isArray(item[key])) {\n _.each(item[key], function (child) {\n addItem(key, child, group, group.childKey);\n });\n } else {\n addItem(key, item[key], group, group.childKey);\n }\n }\n });\n keys.push(group);\n });\n\n return keys;\n };\n\n mapIndexes = function mapIndexes(items) {\n var map = [],\n index = 0;\n\n _.each(items, function (group) {\n group.indexes = [];\n _.each(group.items, function (item) {\n group.indexes.push(index++);\n map.push(item);\n });\n });\n\n return map;\n };\n\n getDifference = function getDifference(array1, array2) {\n if (!array2.length) {\n return array1.filter(function (item) {\n return item[options.tagsInput.displayProperty] !== '';\n });\n }\n return array1.filter(function (item) {\n return !findInObjectArray(array2, item, options.tagsInput.valueProperty || options.tagsInput.getTagText);\n });\n };\n\n self.reset = function () {\n lastPromise = null;\n\n self.items = [];\n self.visible = false;\n self.index = -1;\n self.selected = null;\n self.query = null;\n\n $timeout.cancel(debouncedLoadId);\n };\n\n self.show = function () {\n self.selected = null;\n self.visible = true;\n self.select(0);\n };\n\n self.load = function (query, tags) {\n if (query.length < options.minLength) {\n self.reset();\n return;\n }\n\n var promise,\n\n //filterBy = {},\n filterBy = query,\n groups,\n processItems = function processItems(items) {\n if (promise && promise !== lastPromise) {\n return;\n }\n\n if (scope.searchKeys) {\n scope.isGroups = true;\n //filterBy = query;\n items = splitListItems(items);\n }\n if (_.isObject(items) && !_.isArray(items)) {\n scope.isGroups = true;\n items = _.map(items, function (list, group) {\n return {\n items: list,\n label: group\n };\n });\n }\n if (scope.isGroups) {\n _.each(items, function (group) {\n group.items = getDifference(group.items, tags);\n if (query) {\n var reconciliateItems = {};\n group.items.map(function (item, idx) {\n item.__uniqueid = _.uniqueId('__uniqueid');\n reconciliateItems[item.__uniqueid] = _.cloneDeep(item);\n if ('key' in item) delete item.key;\n if ('childKey' in item) delete item.childKey;\n });\n group.items = $filter('cnFilter')(group.items, filterBy);\n if (options.tagsInput.sortFilteredResults) {\n group.items = sortResults(group.items, filterBy, options.tagsInput.displayProperty);\n }\n group.items.map(function (item) {\n var ref = reconciliateItems[item.__uniqueid];\n if ('key' in ref) item.key = ref.key;\n if ('childKey' in ref) item.childKey = ref.childKey;\n delete item.__uniqueid;\n });\n }\n\n group.items = group.items.slice(0, options.maxResultsToShow);\n });\n self.itemMap = mapIndexes(items);\n } else {\n //filterBy[options.tagsInput.displayProperty] = query;\n items = makeObjectArray(items.data || items, options.tagsInput.displayProperty);\n items = getDifference(items, tags);\n if (query && !options.skipFiltering) {\n items = $filter('cnFilter')(items, filterBy);\n }\n\n if (options.tagsInput.sortFilteredResults) {\n items = sortResults(items, filterBy, options.tagsInput.displayProperty);\n }\n\n items = items.slice(0, options.maxResultsToShow);\n\n if (options.groupBy) {\n groups = groupList(items, options.groupBy);\n items = groups.groups;\n self.itemMap = groups.map;\n }\n }\n\n self.items = items;\n self.show();\n };\n\n $timeout.cancel(debouncedLoadId);\n self.query = query;\n debouncedLoadId = $timeout(function () {\n self._load(query, promise).then(processItems);\n }, options.minLength ? options.debounceDelay : 0, false);\n };\n\n self.clearCache = function (event, query) {\n event.preventDefault();\n if (scope._source) scope.source = scope._source;\n var source = scope.source;\n source({ $query: query, options: { refreshData: true } }).then(function (results) {\n scope._source = source;\n scope.source = function () {\n return results;\n };\n scope.tagsInput.focusInput();\n });\n };\n\n self._load = function (query, promise) {\n var d = $q.defer();\n var source = scope.source({ $query: query });\n if (_.isArray(source)) {\n $timeout(function () {\n d.resolve(source || []);\n });\n } else {\n promise = source;\n lastPromise = promise;\n return promise;\n }\n return d.promise;\n };\n\n self.selectNext = function () {\n self.select(++self.index);\n };\n\n self.selectPrior = function () {\n self.select(--self.index);\n };\n\n self.select = function (index) {\n var list = self.itemMap || self.items;\n if (index < 0) {\n index = list.length - 1;\n } else if (index >= list.length) {\n index = 0;\n }\n self.index = index;\n if (self.itemMap) {\n self.selected = self.itemMap[index];\n } else {\n self.selected = self.items[index];\n }\n };\n\n return self;\n }\n\n function encodeHTML(value) {\n return value ? value.replace(/&/g, '&').replace(//g, '>') : '';\n }\n\n return {\n restrict: 'E',\n require: '^tagsInput',\n scope: {\n source: '&',\n searchKeys: '=?'\n },\n templateUrl: function templateUrl(elem, attrs) {\n return attrs.customTemplateUrl || 'cnTagsInput/auto-complete.html';\n },\n link: function link(scope, element, attrs, tagsInputCtrl) {\n var hotkeys = [KEYS.enter, KEYS.tab, KEYS.escape, KEYS.up, KEYS.down],\n suggestionList,\n tagsInput,\n options,\n getItemText,\n documentClick;\n\n function autoCompleteTag() {}\n scope.__tag = new autoCompleteTag();\n\n tagsInputConfig.load('autoComplete', scope, attrs, {\n debounceDelay: [Number, 250],\n minLength: [Number, 3],\n singleQuery: [Boolean, false],\n highlightMatchedText: [Boolean, true],\n maxResultsToShow: [Number, 75],\n groupBy: [String, ''],\n skipFiltering: [Boolean, false]\n });\n\n options = scope.options;\n\n tagsInput = tagsInputCtrl.registerAutocomplete();\n scope.tagsInput = tagsInput;\n\n options.tagsInput = tagsInput.getOptions();\n\n if (options.minLength === 0 /* && _.isArray(scope.source())*/) {\n options.tagsInput.dropdownIcon = true;\n if (options.tagsInput.maxTags === 1) {\n options.tagsInput.dropdownStyle = 'caret';\n } else {\n options.tagsInput.dropdownStyle = 'fa fa-plus';\n }\n } else {\n options.tagsInput.dropdownStyle = 'fa fa-search';\n }\n\n suggestionList = new SuggestionList(scope, options);\n tagsInput.registerSuggestionList(suggestionList);\n\n getItemText = options.tagsInput.itemFormatter || function (item) {\n return String(item[options.tagsInput.displayProperty]);\n };\n\n scope.suggestionList = suggestionList;\n\n var tagsValue = tagsInput.getModel();\n\n if (options.singleQuery && tagsValue && !angular.equals(tagsValue, [])) {\n suggestionList._load().then(function (results) {\n var tags = findTagsForValue(results, tagsValue, options.tagsInput);\n var curTags = tagsInput.getTags();\n if (!angular.equals(tags, curTags)) {\n curTags.length = 0; // hack to get event to retrigger\n tags.forEach(function (tag) {\n return tagsInput.addTag(tag);\n });\n }\n });\n }\n\n scope.addSuggestion = function (e) {\n e.preventDefault();\n\n var added = false;\n\n if (suggestionList.selected) {\n tagsInput.addTag(angular.copy(suggestionList.selected));\n\n if (!options.tagsInput.maxTags || tagsInput.getTags().length < options.tagsInput.maxTags) {\n var i = suggestionList.items.indexOf(suggestionList.selected);\n suggestionList.items.splice(i, 1);\n suggestionList.select(i);\n tagsInput.focusInput();\n } else {\n suggestionList.reset();\n tagsInput.blurInput();\n }\n\n added = true;\n }\n return added;\n };\n\n scope.highlight = function (item, key) {\n var text = getItemText(item, key);\n if (suggestionList.query && options.highlightMatchedText) {\n text = _(text.match(/(<[^>]*>|[^<]*)/g)) // regex will create a list of all html and text nodes\n .map(function (s) {\n return s.length && s[0] !== '<' ? replaceAll(s, suggestionList.query, '$&') : s;\n }).join('');\n }\n return $sce.trustAsHtml('' + text + '');\n };\n\n scope.track = function (item, key) {\n return getItemText(item, key);\n };\n\n scope.noResultsMessage = function (_ref3) {\n var visible = _ref3.visible,\n query = _ref3.query;\n\n if (!query) return 'No options...';\n return $sce.trustAsHtml('No results for ' + query + '...');\n };\n\n tagsInput.registerProcessBulk(function (bulkTags) {\n var tags = bulkTags.split(options.tagsInput.bulkDelimiter);\n var addTags = function addTags(i) {\n return function (data) {\n _.times(i, function (i) {\n if (data[i]) tagsInput.addTag(data[i]);\n });\n };\n };\n\n if (options.tagsInput.bulkSingleRequest) {\n var request_config = JSON.parse(options.tagsInput.bulkSingleRequest);\n return Api.post({\n url: request_config.url,\n data: {\n location_types: request_config.location_types,\n terms: tags\n }\n }).then(function (response) {\n response.map(function (item) {\n tagsInput.addTag(item);\n });\n });\n }\n // in case a query is involved...doesn't hurt to use even if not\n return Api.batch(function () {\n for (var i = 0, l = tags.length; i < l; i++) {\n if (options.tagsInput.maxTags && tagsInput.getTags().length >= options.tagsInput.maxTags) break;\n var tag = tags[i];\n var times = 1;\n var multiple = tags[i].match(/(.*) ?\\[(\\d+)\\]$/);\n\n if (multiple) {\n tag = multiple[1];\n times = parseInt(multiple[2]);\n }\n\n var results = scope.source({ $query: tag });\n\n if (_.isArray(results)) {\n if (results.length) {\n if (!options.skipFiltering) {\n var filterBy = tag;\n results = $filter('cnFilter')(results, filterBy);\n }\n if (options.tagsInput.sortFilteredResults) {\n results = sortResults(results, tag, options.tagsInput.displayProperty);\n }\n addTags(times)(results);\n } else if (!options.tagsInput.addFromAutocompleteOnly) {\n var _tagsInput$addTag;\n\n tagsInput.addTag((_tagsInput$addTag = {}, _defineProperty(_tagsInput$addTag, options.tagsInput.displayProperty, tag), _defineProperty(_tagsInput$addTag, options.tagsInput.valueProperty, tag), _tagsInput$addTag));\n }\n } else if (results.then) {\n results.then(addTags(times));\n }\n }\n });\n });\n\n tagsInput.on('input-change', function (value) {\n if (value || !options.minLength) {\n suggestionList.load(value, tagsInput.getTags());\n } else {\n suggestionList.reset();\n }\n }).on('input-focus', function (value) {\n if (!suggestionList.visible) {\n suggestionList.load(value, tagsInput.getTags());\n }\n }).on('input-keydown', function (e) {\n var key, handled;\n\n if (hotkeys.indexOf(e.keyCode) === -1) {\n return;\n }\n\n // This hack is needed because jqLite doesn't implement stopImmediatePropagation properly.\n // I've sent a PR to Angular addressing this issue and hopefully it'll be fixed soon.\n // https://github.com/angular/angular.js/pull/4833\n var immediatePropagationStopped = false;\n e.stopImmediatePropagation = function () {\n immediatePropagationStopped = true;\n e.stopPropagation();\n };\n e.isImmediatePropagationStopped = function () {\n return immediatePropagationStopped;\n };\n\n if (suggestionList.visible) {\n key = e.keyCode;\n handled = false;\n\n if (key === KEYS.down) {\n suggestionList.selectNext();\n handled = true;\n } else if (key === KEYS.up) {\n suggestionList.selectPrior();\n handled = true;\n } else if (key === KEYS.escape) {\n suggestionList.reset();\n handled = true;\n } else if (key === KEYS.enter) {\n handled = scope.addSuggestion(e);\n }\n\n if (handled) {\n e.preventDefault();\n e.stopImmediatePropagation();\n scope.$apply();\n }\n }\n }).on('input-blur', function (e) {\n //changed to use document click or focus, as this fires too soon and cancels\n //automcomplete click events\n suggestionList.reset();\n });\n\n documentClick = function documentClick(e) {\n if (e.isDefaultPrevented()) return;\n\n if (suggestionList.visible) {\n // if autocomplete option was selected, or click/focus triggered outside of directive\n if (($(e.target).closest('.suggestion').length || !$(e.target).closest(element[0]).length) && !(e.type === 'blur' && !/^(input|select|textarea|button|a)$/i.test(e.target.tagName))) {\n suggestionList.reset();\n if (!/apply|digest/.test(scope.$root.$$phase)) scope.$apply();\n }\n }\n };\n\n $document.on('click', documentClick).on('blur', documentClick);\n\n scope.$on('$destroy', function () {\n $document.off('click', documentClick).off('blur', documentClick);\n\n empty(tagsInput);\n tagsInput = null;\n\n empty(options);\n options = null;\n });\n }\n };\n }]);\n\n /**\n * @ngdoc directive\n * @name tiTranscludeAppend\n * @module cnTagsInput\n *\n * @description\n * Re-creates the old behavior of ng-transclude. Used internally by tagsInput directive.\n */\n tagsInput.directive('tiTranscludeAppend', function () {\n return function (scope, element, attrs, ctrl, transcludeFn) {\n transcludeFn(function (clone) {\n element.append(clone);\n });\n };\n });\n\n /**\n * @ngdoc directive\n * @name tiAutosize\n * @module cnTagsInput\n *\n * @description\n * Automatically sets the input's width so its content is always visible. Used internally by tagsInput directive.\n */\n tagsInput.directive('tiAutosize', function () {\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function link(scope, element, attrs, ctrl) {\n var THRESHOLD = 3,\n span,\n resize;\n\n span = angular.element('');\n span.css('display', 'none').css('visibility', 'hidden').css('width', 'auto').css('white-space', 'pre');\n\n element.parent().append(span);\n\n resize = function resize(originalValue) {\n var value = originalValue,\n width;\n\n if (angular.isString(value) && value.length === 0) {\n value = attrs.placeholder;\n }\n\n if (value) {\n span.text(value);\n span.css('display', '');\n width = span.prop('offsetWidth');\n span.css('display', 'none');\n }\n\n element.css('width', width ? width + THRESHOLD + 'px' : '');\n\n return originalValue;\n };\n\n ctrl.$parsers.unshift(resize);\n ctrl.$formatters.unshift(resize);\n\n attrs.$observe('placeholder', function (value) {\n if (!ctrl.$modelValue) {\n resize(value);\n }\n });\n }\n };\n });\n\n /**\n * @ngdoc service\n * @name tagsInputConfig\n * @module cnTagsInput\n *\n * @description\n * Sets global configuration settings for both tagsInput and autoComplete directives. It's also used internally to parse and\n * initialize options from HTML attributes.\n */\n tagsInput.provider('tagsInputConfig', function () {\n var globalDefaults = {},\n interpolationStatus = {};\n\n /**\n * @ngdoc method\n * @name setDefaults\n * @description Sets the default configuration option for a directive.\n * @methodOf tagsInputConfig\n *\n * @param {string} directive Name of the directive to be configured. Must be either 'tagsInput' or 'autoComplete'.\n * @param {object} defaults Object containing options and their values.\n *\n * @returns {object} The service itself for chaining purposes.\n */\n this.setDefaults = function (directive, defaults) {\n globalDefaults[directive] = defaults;\n return this;\n };\n\n /***\n * @ngdoc method\n * @name setActiveInterpolation\n * @description Sets active interpolation for a set of options.\n * @methodOf tagsInputConfig\n *\n * @param {string} directive Name of the directive to be configured. Must be either 'tagsInput' or 'autoComplete'.\n * @param {object} options Object containing which options should have interpolation turned on at all times.\n *\n * @returns {object} The service itself for chaining purposes.\n */\n this.setActiveInterpolation = function (directive, options) {\n interpolationStatus[directive] = options;\n return this;\n };\n\n this.$get = [\"$interpolate\", function ($interpolate) {\n var converters = {};\n converters[String] = function (value) {\n return value;\n };\n converters[Number] = function (value) {\n return parseInt(value, 10);\n };\n converters[Boolean] = function (value) {\n return value.toLowerCase() === 'true';\n };\n converters[RegExp] = function (value) {\n return new RegExp(value);\n };\n converters[Object] = function (value) {\n return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' ? value : Object(value);\n };\n\n return {\n load: function load(directive, scope, attrs, options) {\n scope.options = {};\n scope.attrs = attrs;\n scope.uid = _.uniqueId();\n\n angular.forEach(options, function (value, key) {\n var type, localDefault, converter, getDefault, updateValue;\n\n type = value[0];\n localDefault = value[1];\n converter = converters[type];\n\n getDefault = function getDefault() {\n var globalValue = globalDefaults[directive] && globalDefaults[directive][key];\n return angular.isDefined(globalValue) ? globalValue : localDefault;\n };\n\n updateValue = function updateValue(value) {\n scope.options[key] = value ? converter(value) : getDefault();\n };\n\n if (scope[key]) {\n updateValue(scope[key]);\n } else if (interpolationStatus[directive] && interpolationStatus[directive][key]) {\n attrs.$observe(key, function (value) {\n updateValue(value);\n });\n } else {\n updateValue(attrs[key] && $interpolate(attrs[key])(scope.$parent));\n }\n });\n }\n };\n }];\n });\n\n /* HTML templates */\n tagsInput.run([\"$templateCache\", function ($templateCache) {\n $templateCache.put('cnTagsInput/tags-input.html', '\\n
    \\n
  • \\n \\n \\n
  • \\n
\\n
\\n \\n \\n \\n
\\n \\n \\n \\n \\n ×\\n \\n \\n \\n \\n
\\n
\\n
\\n Batch\\n \\n Clear\\n \\n Update Data\\n \\n Copy\\n \\n
\\n
\\n \\n

\\n Press \"Enter\" to submit, \"Shift+Enter\" to add a new line\\n

\\n

\\n Add multiple with brackets, eg. \"citizennet[10]\"\\n

\\n
\\n \\n
\\n
');\n\n $templateCache.put('cnTagsInput/auto-complete.html', '\\n
\\n
    \\n
  • \\n
\\n
\\n
\\n
    \\n
  • No results...
  • \\n
  • \\n
  • {{group.label | titleCase}}
  • \\n
  • \\n
  • \\n
  • \\n
  • \\n
\\n
\\n
\\n
    \\n
  • \\n
  • \\n
\\n
\\n
\\n
    \\n
  • \\n
  • {{group | titleCase}}
  • \\n
  • \\n
  • \\n
  • \\n
  • \\n
\\n
');\n }]);\n})();","/*!;\n tagsInput = null;\n * ngTagsInput v2.0.1\n * http://mbenford.github.io/ngTagsInput\n *\n * Copyright (c) 2013-2014 Michael Benford\n * License: MIT\n *\n * Generated at 2014-04-13 21:25:38 -0300\n */\n(function() {\n 'use strict';\n\n var KEYS = {\n backspace: 8,\n tab: 9,\n enter: 13,\n escape: 27,\n space: 32,\n up: 38,\n down: 40,\n comma: 188\n };\n\n function empty(obj) {\n _.forOwn(obj, function(_value, key, coll) {\n _.set(coll, key, null);\n });\n }\n\n function SimplePubSub() {\n var events = {};\n return {\n on: function(names, handler) {\n names.split(' ').forEach(function(name) {\n if(!events[name]) {\n events[name] = [];\n }\n events[name].push(handler);\n });\n return this;\n },\n trigger: function(name, args) {\n angular.forEach(events[name], function(handler) {\n handler.call(null, args);\n });\n return this;\n },\n destroy: function() {\n empty(events);\n events = null;\n }\n };\n }\n\n function makeObjectArray(array, key, key2) {\n array = array || [];\n if(array.length > 0 && !angular.isObject(array[0])) {\n array.forEach(function(item, index) {\n array[index] = {\n [key]: item\n };\n if(key2) array[index][key2] = item;\n });\n }\n return array;\n }\n\n function getArrayModelVal(array, options) {\n if(options.arrayValueType === 'object') {\n return (array || []).map(item => _.isObject(item && item[options.valueProperty]) ? item[options.valueProperty] : item);\n }\n else {\n return _.pluck(array, options.valueProperty);\n }\n }\n\n function findInObjectArray(array, obj, key) {\n var item = null;\n var i = 0;\n var l = array.length;\n\n if(_.isFunction(key)) {\n var objVal = key(obj);\n if(!objVal) return null;\n for(; i < l; i++) {\n if(objVal === key(array[i])) {\n item = array[i];\n break;\n }\n }\n }\n else {\n for(; i < l; i++) {\n // I'm aware of the internationalization issues regarding toLowerCase()\n // but I couldn't come up with a better solution right now\n if(_.has(obj, key) &&\n _.has(array[i], key) &&\n (angular.toJson(array[i][key]) + '').toLowerCase() === (angular.toJson(obj[key]) + '').toLowerCase()) {\n item = array[i];\n break;\n }\n }\n }\n return item;\n }\n\n function replaceAll(str, substr, newSubstr) {\n var expression = substr.replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n return str.replace(new RegExp(expression, 'gi'), newSubstr);\n }\n\n function matchTagsWithModel(tags, model, options) {\n if(!model || !tags || !tags.length) return false;\n\n if(!_.isArray(model)) {\n return angular.equals(model, tags[0][options.valueProperty]) || angular.equals(model, tags[0]);\n }\n\n let array = getArrayModelVal(tags, options);\n return _.some(array, (tag, i) => {\n return angular.equals(model[i], tag) || angular.equals(model[i], tag[options.valueProperty]);\n });\n }\n\n function findTagsForValue(tags, value, options) {\n if(_.isArray(value)) {\n var matches = _.filter(tags, tag => _.find(value, val =>\n matchTag(tag, val, options.valueProperty, options.arrayValueType)));\n\n if(!options.addFromAutocompleteOnly && matches.length < value.length) {\n _.each(value, v => {\n if(!_.find(matches, m => matchTag(m, v, options.valueProperty, options.arrayValueType))) matches.push(v);\n });\n }\n\n return matches;\n }\n\n return _.filter(tags, tag => matchTag(tag, value, options.valueProperty, options.modelType));\n }\n\n function matchTag(tag, value, valueProperty, modelType) {\n var tagValue = valueProperty ? tag[valueProperty] : tag;\n return modelType === 'object' ?\n objectContains(value, tagValue) :\n value == tagValue;\n }\n\n function objectContains(small, large) {\n if(angular.isArray(small)) {\n return angular.equals(small, large);\n }\n return _.every(small, (val, key) => {\n return key === '$$hashKey' || (\n angular.isObject(val) ?\n objectContains(val, large[key]) :\n val == large[key]\n );\n });\n }\n\n function selectAll(input) {\n if(input.value) {\n input.setSelectionRange(0, input.value.length);\n }\n }\n\n function sortResults(results, tag, displayProperty) {\n const valueFor = val => {\n return displayProperty && val[displayProperty] ? val[displayProperty] : val;\n };\n var first = _.remove(results, result => {\n return _.startsWith(valueFor(result), valueFor(tag));\n });\n first = _.sortBy(first, [\n result => { return valueFor(result).length; }\n ]);\n const reTag = new RegExp(valueFor(tag), \"i\");\n var second = _.remove(results, result => {\n return reTag.test(valueFor(result));\n });\n second = _.sortBy(second, [\n result => { return valueFor(result).search(reTag);},\n result => { return valueFor(result).length; }\n ]);\n var third = _.sortBy(results, [\n result => { return valueFor(result).length; }\n ]);\n return first.concat(second, third);\n }\n\n var tagsInput = angular.module('cnTagsInput', []);\n\n /**\n * @ngdoc directive\n * @name tagsInput\n * @module cnTagsInput\n *\n * @description\n * Renders an input box with tag editing support.\n *\n * @param {string} ngModel Assignable angular expression to data-bind to.\n * @param {string=} [displayProperty=text] Property to be rendered as the tag label.\n * @param {string=} [valueProperty=value] Property to be used as the value when modelType is not array/object.\n * @param {number=} tabindex Tab order of the control.\n * @param {string=} [placeholder=Add a tag] Placeholder text for the control.\n * @param {number=} [minLength=3] Minimum length for a new tag.\n * @param {number=} maxLength Maximum length allowed for a new tag.\n * @param {boolean=} required Sets required validation error key.\n * @param {number=} minTags Sets minTags validation error key if the number of tags added is less than minTags.\n * @param {number=} maxTags Sets maxTags validation error key if the number of tags added is greater than maxTags.\n * @param {boolean=} [allowLeftoverText=false] Sets leftoverText validation error key if there is any leftover text in\n * the input element when the directive loses focus.\n * @param {string=} [removeTagSymbol=×] Symbol character for the remove tag button.\n * @param {boolean=} [addOnEnter=true] Flag indicating that a new tag will be added on pressing the ENTER key.\n * @param {boolean=} [addOnSpace=false] Flag indicating that a new tag will be added on pressing the SPACE key.\n * @param {boolean=} [addOnComma=true] Flag indicating that a new tag will be added on pressing the COMMA key.\n * @param {boolean=} [addOnBlur=false] Flag indicating that a new tag will be added when the input field loses focus.\n * @param {boolean=} [clearOnBlur=false] Flag indicating whether to clear the typed text when the input field loses focus.\n * @param {boolean=} [replaceSpacesWithDashes=false] Flag indicating that spaces will be replaced with dashes.\n * @param {string=} [allowedTagsPattern=.+] Regular expression that determines whether a new tag is valid.\n * @param {boolean=} [enableEditingLastTag=false] Flag indicating that the last tag will be moved back into\n * the new tag input box instead of being removed when the backspace key\n * is pressed and the input box is empty.\n * @param {boolean=} [addFromAutocompleteOnly=false] Flag indicating that only tags coming from the autocomplete list will be allowed.\n * When this flag is true, addOnEnter, addOnComma, addOnSpace, addOnBlur and\n * allowLeftoverText values are ignored.\n * @param {expression} onBeforeTagAdded Expression to evaluate upon adding a new tag. The new tag is available as $tag.\n * @param {expression} onBeforeTagRemoved Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.\n * @param {expression} onBeforeTagChanged Expression to evaluate upon adding or removing a tag. The affected tag is available as $tag. Prev value avialble as $prev.\n * @param {expression} onTagAdded Expression to evaluate upon adding a new tag. The new tag is available as $tag.\n * @param {expression} onTagRemoved Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.\n * @param {expression} onTagChanged Expression to evaluate upon adding or removing a tag. The affected tag is available as $tag. Prev value avialble as $prev.\n * @param {expression} onInit Expression to evaluate upon initializing model value.\n * @param {string} modelType Defines ngModel type, if anything other than array, model is set to first tag in list\n * @param {string} arrayValueType Defines ngModel[] type, if anything other than object, value is set mapped from object's values\n * @param {boolean=} [hideTags=false] Flag indicating whether to hide tag list (for manually displaying tag list in other way)\n * @param {boolean=} [dropdownIcon=false] Flag to show icon on right side\n * @param {string=} [tagsStyle='tags'] Default tags style\n * @param {boolean=} sortFilteredResults Flag to set whether to sort autocomplete list\n */\n tagsInput.directive('tagsInput', [\n \"$timeout\", \"$document\", \"tagsInputConfig\", \"$sce\", \"$rootScope\",\n function($timeout, $document, tagsInputConfig, $sce, $rootScope) {\n function TagList(options, events) {\n var self = {}, getTagText, setTagText, tagIsValid;\n\n getTagText = options.getTagText = function(tag) {\n if(!_.isObject(tag)) return tag;\n return options.itemFormatter ? options.itemFormatter(tag) : tag[options.displayProperty];\n };\n\n setTagText = function(tag, text) {\n // only create tag object when not adding from auto-complete\n if(tag[options.displayProperty]) return;\n\n tag[options.displayProperty] = text;\n if(options.valueProperty && !_.has(tag, options.valueProperty)) {\n tag[options.valueProperty] = text;\n }\n };\n\n tagIsValid = function(tag) {\n var tagText = getTagText(tag) + '';\n\n return (!options.minLength || tagText.length >= options.minLength) &&\n (!options.maxLength || tagText.length <= options.maxLength) &&\n options.allowedTagsPattern.test(tagText) &&\n !findInObjectArray(\n self.items,\n tag,\n options.valueProperty || getTagText\n );\n };\n\n self.items = [];\n\n self.addText = function(text) {\n var tag = {};\n setTagText(tag, text);\n self.add(tag);\n };\n\n self.add = function(tag) {\n if(tag.disabled) return;\n\n var tagText = getTagText(tag);\n\n if(tagText.trim) tagText = tagText.trim();\n\n if(options.replaceSpacesWithDashes) {\n tagText = tagText.replace(/\\s/g, '-');\n }\n\n setTagText(tag, tagText);\n\n if(tagIsValid(tag)) {\n if(options.maxTags && self.items.length >= options.maxTags) {\n self.items.pop();\n events.trigger('tag-removed', {$tag: tag, $event: 'tag-removed'});\n }\n self.items.push(tag);\n events.trigger('tag-added', {$tag: tag, $event: 'tag-added'});\n }\n else {\n events.trigger('invalid-tag', {$tag: tag, $event: 'invalid-tag'});\n }\n return tag;\n };\n\n self.remove = function(index) {\n var tag = self.items.splice(index, 1)[0];\n events.trigger('tag-removed', {$tag: tag, $event: 'tag-removed'});\n return tag;\n };\n\n self.removeLast = function() {\n var tag, lastTagIndex = self.items.length - 1;\n\n if(options.enableEditingLastTag || self.selected) {\n self.selected = null;\n tag = self.remove(lastTagIndex);\n }\n else if(!self.selected) {\n self.selected = self.items[lastTagIndex];\n }\n\n return tag;\n };\n\n self.removeAll = function(e) {\n e.preventDefault();\n var tags = self.items.splice(0, self.items.length);\n tags.forEach(function(tag) {\n events.trigger('tag-removed', {$tag: tag, $event: 'tag-removed'});\n });\n };\n\n self.copyToClipboard = function() {\n var copyElement = document.createElement(\"textarea\");\n copyElement.style.position = 'fixed';\n copyElement.style.opacity = '0';\n copyElement.textContent = self.items.map(\n e => options.displayProperty && e[options.displayProperty] ? e[options.displayProperty] : e\n ).join('\\n');\n var body = document.getElementsByTagName('body')[0];\n body.appendChild(copyElement);\n copyElement.select();\n document.execCommand('copy');\n body.removeChild(copyElement);\n };\n\n self.destroy = function() {\n empty(self);\n self = null;\n };\n\n return self;\n }\n\n return {\n restrict: 'E',\n require: 'ngModel',\n scope: {\n tags: '=ngModel',\n itemFormatter: '=',\n ngDisabled: '=',\n onBeforeTagAdded: '&',\n onBeforeTagRemoved: '&',\n onBeforeTagChanged: '&',\n onTagAdded: '&',\n onTagRemoved: '&',\n onTagChanged: '&',\n onInit: '&',\n newTag: '=?'\n },\n replace: false,\n transclude: true,\n templateUrl: 'cnTagsInput/tags-input.html',\n controller: [\"$scope\", \"$attrs\", \"$element\", function($scope, $attrs, $element) {\n tagsInputConfig.load('tagsInput', $scope, $attrs, {\n placeholder: [String, ''],\n tabindex: [Number],\n removeTagSymbol: [String, String.fromCharCode(215)],\n replaceSpacesWithDashes: [Boolean, false],\n minLength: [Number, 2],\n maxLength: [Number],\n addOnEnter: [Boolean, true],\n addOnSpace: [Boolean, false],\n addOnComma: [Boolean, true],\n addOnBlur: [Boolean, false],\n clearOnBlur: [Boolean, false],\n allowedTagsPattern: [RegExp, /.+/],\n enableEditingLastTag: [Boolean, false],\n required: [Boolean, false],\n minTags: [Number],\n maxTags: [Number],\n displayProperty: [String, 'text'],\n valueProperty: [String],\n allowLeftoverText: [Boolean, false],\n addFromAutocompleteOnly: [Boolean, false],\n tagClass: [String, ''],\n modelType: [String, 'array'],\n arrayValueType: [String, 'object'],\n hideTags: [Boolean, false],\n dropdownIcon: [Boolean, false],\n tagsStyle: [String, 'tags'],\n allowBulk: [Boolean, false],\n bulkSingleRequest: [String, ''],\n bulkDelimiter: [RegExp, /, ?|\\n/],\n bulkPlaceholder: [String, 'Enter a list separated by commas or new lines'],\n sortFilteredResults: [Boolean, false],\n showClearAll: [Boolean, false],\n showClearCache: [Boolean, false],\n showButton: [Boolean, false]\n });\n\n var options = $scope.options;\n var input = options.input = $element.find('input.input');\n\n function handleKeydown(e) {\n $scope.events.trigger('input-keydown', e);\n }\n\n input.on('keydown', handleKeydown);\n\n $scope.$on('$destroy', function() {\n input.off('keydown', handleKeydown);\n input = null;\n empty(options);\n options = null;\n $scope.events.destroy();\n $scope.tagList.destroy();\n $scope.processBulk = null;\n });\n\n if(!options.valueProperty &&\n (!/object|array/.test(options.modelType) || options.arrayValueType !== 'object')) {\n options.valueProperty = 'value';\n }\n\n if($scope.itemFormatter) options.itemFormatter = $scope.itemFormatter;\n\n if(options.tagsStyle === 'tags') {\n options.tagClass = options.tagClass || 'label-primary';\n }\n\n if(options.allowBulk && (options.modelType !== 'array' || options.maxTags === 1)) {\n options.allowBulk = false;\n }\n\n $scope.events = new SimplePubSub();\n $scope.tagList = new TagList(options, $scope.events);\n\n this.registerAutocomplete = function() {\n return {\n addTag: function(tag) {\n return $scope.tagList.add(tag);\n },\n focusInput: function() {\n input[0].focus();\n },\n blurInput: function() {\n input[0].blur();\n },\n getTags: function() {\n return $scope.tagList.items;\n },\n getModel: function() {\n return $scope.tags;\n },\n getOptions: function() {\n return options;\n },\n on: function(name, handler) {\n $scope.events.on(name, handler);\n return this;\n },\n registerProcessBulk: function(fn) {\n $scope.processBulk = function() {\n fn($scope.bulkTags).then(function() {\n $scope.showBulk = false;\n $scope.bulkTags = '';\n });\n };\n },\n registerSuggestionList: function(suggestionList) {\n $scope.tagList.suggestionList = suggestionList;\n }\n };\n };\n }],\n link: function(scope, element, attrs, ngModelCtrl) {\n function tagsInputTag() {}\n scope.__tag = new tagsInputTag();\n\n var hotkeys = [KEYS.enter, KEYS.comma, KEYS.space, KEYS.backspace],\n tagList = scope.tagList,\n events = scope.events,\n options = scope.options,\n input = element.find('input.input'),\n textarea = element.find('textarea'),\n div = element.find('div'),\n blurTimeout;\n\n if(attrs.inputId && !ngModelCtrl.$name) {\n ngModelCtrl.$name = attrs.inputId;\n }\n\n // before callbacks allow code to modify tag before it's added\n // after callback fired after ngModel has chance to update\n function beforeAndAfter(before, after) {\n return function() {\n var args = arguments;\n before.apply(this, args);\n $timeout(function(){\n after.apply(this, args);\n });\n };\n }\n\n function inlineChangeTags() {\n return function() {\n if (arguments.length > 0 && _.isArray(arguments[0].$tag)) {\n let newTags = arguments[0].$tag;\n const isObjectArray = _.every(newTags, (v) => typeof v === 'object' && v !== null && options.displayProperty && v[options.displayProperty]);\n if (isObjectArray) {\n if (scope.tagList && scope.tagList.items && newTags) {\n scope.tagList.items = newTags;\n }\n }\n }\n };\n }\n\n events\n .on('tag-added', beforeAndAfter(scope.onBeforeTagAdded, scope.onTagAdded))\n .on('tag-removed', beforeAndAfter(scope.onBeforeTagRemoved, scope.onTagRemoved))\n .on('tag-changed', beforeAndAfter(scope.onBeforeTagChanged, scope.onTagChanged))\n .on('tag-changed', inlineChangeTags())\n .on('tag-init', scope.onInit)\n .on('tag-added tag-removed', function(e) {\n if(!options.maxTags || options.maxTags > scope.tagList.items.length) {\n selectAll(options.input[0]);\n }\n else {\n scope.newTag.text = '';\n }\n if(options.modelType === 'array') {\n if(!options.valueProperty) {\n scope.tags = scope.tagList.items;\n }\n else {\n scope.tags = getArrayModelVal(scope.tagList.items, options);\n }\n if (scope.tagList.items.length >= options.minTags) {\n ngModelCtrl.$setValidity('tv4-400', true);\n }\n }\n else {\n if(e.$event === 'tag-removed') {\n scope.tags = undefined;\n }\n else {\n if(!options.valueProperty) {\n scope.tags = e.$tag;\n }\n else {\n scope.tags = _.has(e.$tag, options.valueProperty) ?\n e.$tag[options.valueProperty] : e.$tag[options.displayProperty];\n }\n }\n }\n })\n .on('invalid-tag', function() {\n scope.newTag.invalid = true;\n })\n .on('input-change', function() {\n tagList.selected = null;\n scope.newTag.invalid = null;\n })\n .on('input-focus', function() {\n ngModelCtrl.$setValidity('leftoverText', true);\n })\n .on('input-blur', function() {\n if(!options.addFromAutocompleteOnly) {\n if(options.addOnBlur && scope.newTag.text) {\n tagList.addText(scope.newTag.text);\n }\n }\n\n // Reset newTag\n if(options.clearOnBlur) {\n scope.newTag.text = '';\n scope.newTag.invalid = null;\n }\n });\n\n scope.newTag = {text: '', invalid: null};\n\n scope.getDisplayText = scope.itemFormatter || function(tag) {\n return tag && ((tag[options.displayProperty] || 'undefined') + '').trim();\n };\n\n scope.getDisplayHtml = function(tag) {\n return $sce.trustAsHtml(scope.getDisplayText(tag));\n };\n\n scope.track = function(tag) {\n return tag[options.displayProperty];\n };\n\n scope.newTagChange = function() {\n events.trigger('input-change', scope.newTag.text);\n };\n\n scope.processBulk = scope.processBulk || function() {\n var tags = scope.bulkTags.split(options.bulkDelimiter);\n _.each(tags, function(text) {\n var tag = {};\n tag[options.displayProperty] = text;\n scope.tagList.add(tag);\n });\n scope.showBulk = false;\n scope.bulkTags = '';\n };\n\n var first = true;\n\n scope.triggerInit = function(value, prev) {\n var criteria = options.valueProperty ? {[options.valueProperty]: value} : value;\n if(!tagList.items.length || !_.find(tagList.items, criteria)) {\n events.trigger('tag-init', {\n $tag: value,\n $prev: prev,\n $event: 'tag-init',\n $setter: function(val) {\n if(val && !_.isObject(val)) {\n tagList.items = [{\n [options.displayProperty]: val,\n [options.valueProperty]: val\n }];\n }\n else {\n tagList.items = _.isArray(val) ? val : [val];\n }\n return tagList.items;\n }\n });\n }\n };\n\n scope.$watch('tags', function(value, prev) {\n var changed = !angular.equals(value, prev);\n var init = !changed && first;\n\n if(init) {\n scope.triggerInit(value, prev);\n }\n if(changed) {\n events.trigger('tag-changed', {\n $tag: value,\n $prev: prev,\n $event: 'tag-changed'\n });\n }\n\n if(options.modelType === 'array') {\n if(_.isArray(value)) {\n if(value.length) {\n if(!matchTagsWithModel(tagList.items, scope.tags, options)) {\n scope.triggerInit(value, prev);\n }\n if(!matchTagsWithModel(tagList.items, scope.tags, options) || tagList.items.length !== scope.tags.length) {\n tagList.items = makeObjectArray(value, options.displayProperty, options.valueProperty);\n scope.tags = getArrayModelVal(tagList.items, options);\n return;\n }\n }\n else {\n tagList.items = [];\n if(angular.isUndefined(prev)) return;\n }\n }\n else if(value === undefined) {\n tagList.items = [];\n scope.tags = [];\n return;\n }\n }\n else if(angular.isDefined(value)) {\n if(_.isArray(value)) {\n if(value.length) {\n //if(options.modelType === 'object') {\n if(!options.valueProperty) {\n scope.tags = value[0];\n }\n else {\n scope.tags = value[0][options.valueProperty];\n }\n\n return;\n }\n else {\n scope.tags = undefined;\n }\n }\n else {\n if(options.modelType === 'object') {\n if(value !== null) tagList.items = [value];\n }\n else {\n if(_.isObject(value)) {\n tagList.items = [value];\n\n var val = value[options.valueProperty];\n if(_.isUndefined(val)) val = value[options.displayProperty];\n scope.tags = val;\n\n return;\n }\n else if(!_.isUndefined(value) &&\n (!tagList.items.length || tagList.items[0][options.valueProperty] !== value)) {\n scope.triggerInit(value, prev);\n }\n }\n }\n }\n else if(!value && tagList.items.length) {\n tagList.items = [];\n }\n\n if(!init && changed) {\n ngModelCtrl.$setDirty();\n }\n\n // hack because schemaForm is incorrectly invalidating model sometimes\n ngModelCtrl.$setValidity('schemaForm', true);\n if(options.modelType === 'array') {\n ngModelCtrl.$setValidity('tv4-401', value && options.maxTags ? value.length <= options.maxTags : true);\n ngModelCtrl.$setValidity('tv4-302', value ? angular.isDefined(options.minTags) ? value.length >= options.minTags : true : false);\n }\n else {\n ngModelCtrl.$setValidity('tv4-302', !options.required || !(angular.isUndefined(value)));\n }\n\n first = false;\n\n }, true);\n\n function handleInputKeydown(e) {\n // This hack is needed because jqLite doesn't implement stopImmediatePropagation properly.\n // I've sent a PR to Angular addressing this issue and hopefully it'll be fixed soon.\n // https://github.com/angular/angular.js/pull/4833\n if(e.isImmediatePropagationStopped && e.isImmediatePropagationStopped()) {\n return;\n }\n\n var key = e.keyCode,\n isModifier = e.shiftKey || e.altKey || e.ctrlKey || e.metaKey,\n addKeys = {},\n shouldAdd, shouldRemove;\n\n if(isModifier || hotkeys.indexOf(key) === -1) {\n return;\n }\n\n addKeys[KEYS.enter] = options.addOnEnter;\n addKeys[KEYS.comma] = options.addOnComma;\n addKeys[KEYS.space] = options.addOnSpace;\n\n shouldAdd = !options.addFromAutocompleteOnly && addKeys[key];\n shouldRemove = !shouldAdd && key === KEYS.backspace && scope.newTag.text.length === 0;\n\n if(shouldAdd) {\n tagList.addText(scope.newTag.text);\n\n scope.$apply();\n e.preventDefault();\n }\n else if(shouldRemove) {\n var tag = tagList.removeLast();\n if(tag && options.enableEditingLastTag) {\n scope.newTag.text = tag[options.displayProperty];\n }\n\n scope.$apply();\n e.preventDefault();\n }\n }\n\n function handleInputBlur(e) {\n blurTimeout = $timeout(function() {\n // race condition can cause input to be destroyed before timeout ends\n if(!input) return false;\n var activeElement = $document.prop('activeElement'),\n lostFocusToBrowserWindow = activeElement === input[0],\n lostFocusToChildElement = element.find('.host')[0].contains(activeElement);\n\n if(lostFocusToBrowserWindow || !lostFocusToChildElement) {\n scope.hasFocus = false;\n events.trigger('input-blur', e);\n }\n }, 150); // timeout so that click event triggers first\n }\n\n function handleInputFocus(e) {\n if(e) e.preventDefault();\n if(scope.ngDisabled) return;\n\n selectAll(e.target);\n\n if(blurTimeout) $timeout.cancel(blurTimeout);\n\n scope.hasFocus = true;\n events.trigger('input-focus', input.val());\n\n if(!/apply|digest/.test(scope.$root.$$phase)) scope.$apply();\n }\n\n function handleTextareaKeydown(e) {\n if(e.keyCode === KEYS.enter) {\n if(!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {\n e.preventDefault();\n scope.processBulk();\n }\n }\n }\n\n function handleDivClick(e) {\n var $target = $(e.target);\n if(!$target.closest('.suggestion').length &&\n // we don't want any of the buttons underneath to trigger\n !$target.parent().hasClass('help-block')) {\n e.preventDefault();\n input[0].focus();\n }\n }\n\n // stupid ugly hack to fix order between input and autocomplete events\n let uglyHackTimeout = $timeout(function() {\n input\n .on('keydown', handleInputKeydown)\n .on('focus', handleInputFocus)\n .on('blur', handleInputBlur);\n });\n\n textarea.on('keydown', handleTextareaKeydown);\n\n div.on('click', handleDivClick);\n\n scope.$on('$destroy', function() {\n input\n .off('keydown', handleInputKeydown)\n .off('focus', handleInputFocus)\n .off('blur', handleInputBlur);\n\n textarea.off('keydown', handleTextareaKeydown);\n div.off('click', handleDivClick);\n input = null;\n textarea = null;\n div = null;\n events.destroy();\n events = null;\n first = null;\n hotkeys = null;\n options = null;\n tagList = null;\n $timeout.cancel(uglyHackTimeout);\n });\n }\n };\n }]);\n\n /**\n * @ngdoc directive\n * @name autoComplete\n * @module cnTagsInput\n *\n * @description\n * Provides autocomplete support for the tagsInput directive.\n *\n * @param {expression} source Expression to evaluate upon changing the input content. The input value is available as\n * $query. The result of the expression must be a promise that eventually resolves to an\n * array of strings.\n * @param {number=} [debounceDelay=100] Amount of time, in milliseconds, to wait before evaluating the expression in\n * the source option after the last keystroke.\n * @param {number=} [minLength=3] Minimum number of characters that must be entered before evaluating the expression\n * in the source option.\n * @param {boolean=} [highlightMatchedText=true] Flag indicating that the matched text will be highlighted in the\n * suggestions list.\n * @param {number=} [maxResultsToShow=10] Maximum number of results to be displayed at a time.\n */\n tagsInput.directive('autoComplete', [\n \"$document\", \"$timeout\", \"$filter\", \"$sce\", \"tagsInputConfig\", \"$parse\", 'Api', '$q',\n function($document, $timeout, $filter, $sce, tagsInputConfig, $parse, Api, $q) {\n function SuggestionList(scope, options) {\n var self = {}, debouncedLoadId, getDifference, lastPromise, groupList,\n splitListItems, formatItemText, mapIndexes;\n\n groupList = function(list, groupBy) {\n var filtered = {},\n map = [],\n index = 0,\n keys;\n\n // loop through each item in the list\n _.each(list, function(item) {\n keys = $parse(groupBy)(item);\n if(!_.isArray(keys)) keys = [keys];\n _.each(keys, function(key) {\n if(!filtered[key]) {\n filtered[key] = [];\n }\n filtered[key].push(item);\n });\n });\n\n _.each(filtered, function(group) {\n group.indexes = [];\n _.each(group, function(item) {\n group.indexes.push(index++);\n map.push(item);\n });\n });\n\n return {\n groups: filtered,\n map: map\n };\n };\n\n formatItemText = function(item, formatter) {\n if(formatter) {\n if(!_.isArray(formatter)) {\n formatter = [formatter, {}];\n }\n return $parse(formatter[0])((formatter[1].val = item) && formatter[1]);\n }\n\n return item;\n };\n\n splitListItems = function(items) {\n var keys = [];\n\n function addItem(key, item, group, prop) {\n var text = _.isObject(item) ? item[prop || options.tagsInput.displayProperty] : item,\n toAdd = {\n text: formatItemText(text, group.formatter),\n value: text,\n key: key,\n childKey: prop/*,\n tagClass: options.tagClasses && options.tagClasses[key] || options.tagClass*/\n };\n\n if(!_.find(group.items, toAdd)) {\n group.items.push(toAdd);\n }\n }\n\n _.each(scope.searchKeys, function(group) {\n var key = group.key;\n group.items = [];\n\n _.each(items, function(item) {\n if(item[key]) {\n if(_.isArray(item[key])) {\n _.each(item[key], function(child) {\n addItem(key, child, group, group.childKey);\n });\n }\n else {\n addItem(key, item[key], group, group.childKey);\n }\n }\n });\n keys.push(group);\n });\n\n return keys;\n };\n\n mapIndexes = function(items) {\n var map = [],\n index = 0;\n\n _.each(items, function(group) {\n group.indexes = [];\n _.each(group.items, function(item) {\n group.indexes.push(index++);\n map.push(item);\n });\n });\n\n return map;\n };\n\n getDifference = function(array1, array2) {\n if(!array2.length) {\n return array1.filter(function(item) {\n return item[options.tagsInput.displayProperty] !== '';\n });\n }\n return array1.filter(function(item) {\n return !findInObjectArray(\n array2,\n item,\n options.tagsInput.valueProperty || options.tagsInput.getTagText\n );\n });\n };\n\n self.reset = function() {\n lastPromise = null;\n\n self.items = [];\n self.visible = false;\n self.index = -1;\n self.selected = null;\n self.query = null;\n\n $timeout.cancel(debouncedLoadId);\n };\n\n self.show = function() {\n self.selected = null;\n self.visible = true;\n self.select(0);\n };\n\n self.load = function(query, tags) {\n if(query.length < options.minLength) {\n self.reset();\n return;\n }\n\n var promise,\n //filterBy = {},\n filterBy = query,\n groups,\n processItems = function(items) {\n if(promise && promise !== lastPromise) {\n return;\n }\n\n if(scope.searchKeys) {\n scope.isGroups = true;\n //filterBy = query;\n items = splitListItems(items);\n }\n if(_.isObject(items) && !_.isArray(items)) {\n scope.isGroups = true;\n items = _.map(items, function(list, group) {\n return {\n items: list,\n label: group\n };\n });\n }\n if(scope.isGroups) {\n _.each(items, function(group) {\n group.items = getDifference(group.items, tags);\n if(query) {\n let reconciliateItems = {};\n group.items.map((item, idx) => {\n item.__uniqueid = _.uniqueId('__uniqueid');\n reconciliateItems[item.__uniqueid] =_.cloneDeep(item);\n if ('key' in item) delete item.key;\n if ('childKey' in item) delete item.childKey;\n });\n group.items = $filter('cnFilter')(group.items, filterBy);\n if (options.tagsInput.sortFilteredResults) {\n group.items = sortResults(group.items, filterBy, options.tagsInput.displayProperty);\n }\n group.items.map((item) => {\n let ref = reconciliateItems[item.__uniqueid];\n if ('key' in ref) item.key = ref.key;\n if ('childKey' in ref) item.childKey = ref.childKey;\n delete item.__uniqueid;\n });\n }\n\n group.items = group.items.slice(0, options.maxResultsToShow);\n });\n self.itemMap = mapIndexes(items);\n }\n else {\n //filterBy[options.tagsInput.displayProperty] = query;\n items = makeObjectArray(items.data || items, options.tagsInput.displayProperty);\n items = getDifference(items, tags);\n if(query && !options.skipFiltering) {\n items = $filter('cnFilter')(items, filterBy);\n }\n\n if (options.tagsInput.sortFilteredResults) {\n items = sortResults(items, filterBy, options.tagsInput.displayProperty);\n }\n\n items = items.slice(0, options.maxResultsToShow);\n\n if(options.groupBy) {\n groups = groupList(items, options.groupBy);\n items = groups.groups;\n self.itemMap = groups.map;\n }\n }\n\n self.items = items;\n self.show();\n };\n\n $timeout.cancel(debouncedLoadId);\n self.query = query;\n debouncedLoadId = $timeout(function() {\n self._load(query, promise).then(processItems);\n }, options.minLength ? options.debounceDelay : 0, false);\n };\n\n self.clearCache = function(event, query) {\n event.preventDefault();\n if(scope._source) scope.source = scope._source;\n var source = scope.source;\n source({$query: query, options: { refreshData: true }})\n .then(function(results) {\n scope._source = source;\n scope.source = function() {\n return results;\n };\n scope.tagsInput.focusInput();\n });\n };\n\n self._load = function(query, promise) {\n var d = $q.defer();\n var source = scope.source({$query: query});\n if(_.isArray(source)) {\n $timeout(function() {\n d.resolve(source || []);\n });\n }\n else {\n promise = source;\n lastPromise = promise;\n return promise;\n }\n return d.promise;\n };\n\n self.selectNext = function() {\n self.select(++self.index);\n };\n\n self.selectPrior = function() {\n self.select(--self.index);\n };\n\n self.select = function(index) {\n var list = self.itemMap || self.items;\n if(index < 0) {\n index = list.length - 1;\n }\n else if(index >= list.length) {\n index = 0;\n }\n self.index = index;\n if(self.itemMap) {\n self.selected = self.itemMap[index];\n }\n else {\n self.selected = self.items[index];\n }\n };\n\n return self;\n }\n\n function encodeHTML(value) {\n return value ? value\n .replace(/&/g, '&')\n .replace(//g, '>') : '';\n }\n\n return {\n restrict: 'E',\n require: '^tagsInput',\n scope: {\n source: '&',\n searchKeys: '=?'\n },\n templateUrl: function(elem, attrs) {\n return attrs.customTemplateUrl || 'cnTagsInput/auto-complete.html';\n },\n link: function(scope, element, attrs, tagsInputCtrl) {\n var hotkeys = [KEYS.enter, KEYS.tab, KEYS.escape, KEYS.up, KEYS.down],\n suggestionList, tagsInput, options, getItemText, documentClick;\n\n function autoCompleteTag() {}\n scope.__tag = new autoCompleteTag();\n\n tagsInputConfig.load('autoComplete', scope, attrs, {\n debounceDelay: [Number, 250],\n minLength: [Number, 3],\n singleQuery: [Boolean, false],\n highlightMatchedText: [Boolean, true],\n maxResultsToShow: [Number, 75],\n groupBy: [String, ''],\n skipFiltering: [Boolean, false]\n });\n\n options = scope.options;\n\n tagsInput = tagsInputCtrl.registerAutocomplete();\n scope.tagsInput = tagsInput;\n\n options.tagsInput = tagsInput.getOptions();\n\n if(options.minLength === 0/* && _.isArray(scope.source())*/) {\n options.tagsInput.dropdownIcon = true;\n if(options.tagsInput.maxTags === 1) {\n options.tagsInput.dropdownStyle = 'caret';\n }\n else {\n options.tagsInput.dropdownStyle = 'fa fa-plus';\n }\n }\n else {\n options.tagsInput.dropdownStyle = 'fa fa-search';\n }\n\n suggestionList = new SuggestionList(scope, options);\n tagsInput.registerSuggestionList(suggestionList);\n\n getItemText = options.tagsInput.itemFormatter || function(item) {\n return String(item[options.tagsInput.displayProperty]);\n };\n\n scope.suggestionList = suggestionList;\n\n var tagsValue = tagsInput.getModel();\n\n if(options.singleQuery && tagsValue && !angular.equals(tagsValue, [])) {\n suggestionList._load().then(results => {\n var tags = findTagsForValue(results, tagsValue, options.tagsInput);\n var curTags = tagsInput.getTags();\n if(!angular.equals(tags, curTags)) {\n curTags.length = 0; // hack to get event to retrigger\n tags.forEach(tag => tagsInput.addTag(tag));\n }\n });\n }\n\n scope.addSuggestion = function(e) {\n e.preventDefault();\n\n var added = false;\n\n if(suggestionList.selected) {\n tagsInput.addTag(angular.copy(suggestionList.selected));\n\n if(!options.tagsInput.maxTags || tagsInput.getTags().length < options.tagsInput.maxTags) {\n var i = suggestionList.items.indexOf(suggestionList.selected);\n suggestionList.items.splice(i, 1);\n suggestionList.select(i);\n tagsInput.focusInput();\n }\n else {\n suggestionList.reset();\n tagsInput.blurInput();\n }\n\n added = true;\n }\n return added;\n };\n\n scope.highlight = function(item, key) {\n var text = getItemText(item, key);\n if(suggestionList.query && options.highlightMatchedText) {\n text =\n _(text.match(/(<[^>]*>|[^<]*)/g)) // regex will create a list of all html and text nodes\n .map(s => s.length && s[0] !== '<' ? replaceAll(s, suggestionList.query, '$&') : s)\n .join('');\n }\n return $sce.trustAsHtml('' + text + '');\n };\n\n scope.track = function(item, key) {\n return getItemText(item, key);\n };\n\n scope.noResultsMessage = function({visible, query}) {\n if(!query) return 'No options...';\n return $sce.trustAsHtml(`No results for ${query}...`);\n };\n\n tagsInput.registerProcessBulk(function(bulkTags) {\n var tags = bulkTags.split(options.tagsInput.bulkDelimiter);\n var addTags = function(i) {\n return function(data) {\n _.times(i, function(i) {\n if(data[i]) tagsInput.addTag(data[i]);\n });\n };\n };\n\n if (options.tagsInput.bulkSingleRequest) {\n let request_config = JSON.parse(options.tagsInput.bulkSingleRequest);\n return Api.post({\n url: request_config.url,\n data: {\n location_types: request_config.location_types,\n terms: tags,\n }\n }).then(response => {\n response.map(item => {\n tagsInput.addTag(item);\n });\n });\n }\n // in case a query is involved...doesn't hurt to use even if not\n return Api.batch(function() {\n for(var i = 0, l = tags.length; i < l; i++) {\n if(options.tagsInput.maxTags && tagsInput.getTags().length >= options.tagsInput.maxTags) break;\n var tag = tags[i];\n var times = 1;\n var multiple = tags[i].match(/(.*) ?\\[(\\d+)\\]$/);\n\n if(multiple) {\n tag = multiple[1];\n times = parseInt(multiple[2]);\n }\n\n var results = scope.source({$query: tag});\n\n if(_.isArray(results)) {\n if(results.length) {\n if(!options.skipFiltering) {\n var filterBy = tag;\n results = $filter('cnFilter')(results, filterBy);\n }\n if (options.tagsInput.sortFilteredResults) {\n results = sortResults(results, tag, options.tagsInput.displayProperty);\n }\n addTags(times)(results);\n }\n else if(!options.tagsInput.addFromAutocompleteOnly) {\n tagsInput.addTag({\n [options.tagsInput.displayProperty]: tag,\n [options.tagsInput.valueProperty]: tag\n });\n }\n }\n else if(results.then) {\n results.then(addTags(times));\n }\n }\n });\n });\n\n tagsInput\n .on('input-change', function(value) {\n if(value || !options.minLength) {\n suggestionList.load(value, tagsInput.getTags());\n }\n else {\n suggestionList.reset();\n }\n })\n .on('input-focus', function(value) {\n if(!suggestionList.visible) {\n suggestionList.load(value, tagsInput.getTags());\n }\n })\n .on('input-keydown', function(e) {\n var key, handled;\n\n if(hotkeys.indexOf(e.keyCode) === -1) {\n return;\n }\n\n // This hack is needed because jqLite doesn't implement stopImmediatePropagation properly.\n // I've sent a PR to Angular addressing this issue and hopefully it'll be fixed soon.\n // https://github.com/angular/angular.js/pull/4833\n var immediatePropagationStopped = false;\n e.stopImmediatePropagation = function() {\n immediatePropagationStopped = true;\n e.stopPropagation();\n };\n e.isImmediatePropagationStopped = function() {\n return immediatePropagationStopped;\n };\n\n if(suggestionList.visible) {\n key = e.keyCode;\n handled = false;\n\n if(key === KEYS.down) {\n suggestionList.selectNext();\n handled = true;\n }\n else if(key === KEYS.up) {\n suggestionList.selectPrior();\n handled = true;\n }\n else if(key === KEYS.escape) {\n suggestionList.reset();\n handled = true;\n }\n else if(key === KEYS.enter) {\n handled = scope.addSuggestion(e);\n }\n\n if(handled) {\n e.preventDefault();\n e.stopImmediatePropagation();\n scope.$apply();\n }\n }\n })\n .on('input-blur', function(e) {\n //changed to use document click or focus, as this fires too soon and cancels\n //automcomplete click events\n suggestionList.reset();\n });\n\n documentClick = function(e) {\n if(e.isDefaultPrevented()) return;\n\n if(suggestionList.visible) {\n // if autocomplete option was selected, or click/focus triggered outside of directive\n if(($(e.target).closest('.suggestion').length || !$(e.target).closest(element[0]).length) &&\n !(e.type === 'blur' && !/^(input|select|textarea|button|a)$/i.test(e.target.tagName))) {\n suggestionList.reset();\n if(!/apply|digest/.test(scope.$root.$$phase)) scope.$apply();\n }\n }\n };\n\n $document\n .on('click', documentClick)\n .on('blur', documentClick);\n\n scope.$on('$destroy', function() {\n $document\n .off('click', documentClick)\n .off('blur', documentClick);\n\n empty(tagsInput);\n tagsInput = null;\n\n empty(options);\n options = null;\n });\n }\n };\n }]);\n\n\n /**\n * @ngdoc directive\n * @name tiTranscludeAppend\n * @module cnTagsInput\n *\n * @description\n * Re-creates the old behavior of ng-transclude. Used internally by tagsInput directive.\n */\n tagsInput.directive('tiTranscludeAppend', function() {\n return function(scope, element, attrs, ctrl, transcludeFn) {\n transcludeFn(function(clone) {\n element.append(clone);\n });\n };\n });\n\n /**\n * @ngdoc directive\n * @name tiAutosize\n * @module cnTagsInput\n *\n * @description\n * Automatically sets the input's width so its content is always visible. Used internally by tagsInput directive.\n */\n tagsInput.directive('tiAutosize', function() {\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function(scope, element, attrs, ctrl) {\n var THRESHOLD = 3,\n span, resize;\n\n span = angular.element('');\n span.css('display', 'none')\n .css('visibility', 'hidden')\n .css('width', 'auto')\n .css('white-space', 'pre');\n\n element.parent().append(span);\n\n resize = function(originalValue) {\n var value = originalValue, width;\n\n if(angular.isString(value) && value.length === 0) {\n value = attrs.placeholder;\n }\n\n if(value) {\n span.text(value);\n span.css('display', '');\n width = span.prop('offsetWidth');\n span.css('display', 'none');\n }\n\n element.css('width', width ? width + THRESHOLD + 'px' : '');\n\n return originalValue;\n };\n\n ctrl.$parsers.unshift(resize);\n ctrl.$formatters.unshift(resize);\n\n attrs.$observe('placeholder', function(value) {\n if(!ctrl.$modelValue) {\n resize(value);\n }\n });\n }\n };\n });\n\n /**\n * @ngdoc service\n * @name tagsInputConfig\n * @module cnTagsInput\n *\n * @description\n * Sets global configuration settings for both tagsInput and autoComplete directives. It's also used internally to parse and\n * initialize options from HTML attributes.\n */\n tagsInput.provider('tagsInputConfig', function() {\n var globalDefaults = {}, interpolationStatus = {};\n\n /**\n * @ngdoc method\n * @name setDefaults\n * @description Sets the default configuration option for a directive.\n * @methodOf tagsInputConfig\n *\n * @param {string} directive Name of the directive to be configured. Must be either 'tagsInput' or 'autoComplete'.\n * @param {object} defaults Object containing options and their values.\n *\n * @returns {object} The service itself for chaining purposes.\n */\n this.setDefaults = function(directive, defaults) {\n globalDefaults[directive] = defaults;\n return this;\n };\n\n /***\n * @ngdoc method\n * @name setActiveInterpolation\n * @description Sets active interpolation for a set of options.\n * @methodOf tagsInputConfig\n *\n * @param {string} directive Name of the directive to be configured. Must be either 'tagsInput' or 'autoComplete'.\n * @param {object} options Object containing which options should have interpolation turned on at all times.\n *\n * @returns {object} The service itself for chaining purposes.\n */\n this.setActiveInterpolation = function(directive, options) {\n interpolationStatus[directive] = options;\n return this;\n };\n\n this.$get = [\"$interpolate\", function($interpolate) {\n var converters = {};\n converters[String] = function(value) {\n return value;\n };\n converters[Number] = function(value) {\n return parseInt(value, 10);\n };\n converters[Boolean] = function(value) {\n return value.toLowerCase() === 'true';\n };\n converters[RegExp] = function(value) {\n return new RegExp(value);\n };\n converters[Object] = function(value) {\n return typeof value === 'object' ? value : Object(value);\n };\n\n return {\n load: function(directive, scope, attrs, options) {\n scope.options = {};\n scope.attrs = attrs;\n scope.uid = _.uniqueId();\n\n angular.forEach(options, function(value, key) {\n var type, localDefault, converter, getDefault, updateValue;\n\n type = value[0];\n localDefault = value[1];\n converter = converters[type];\n\n getDefault = function() {\n var globalValue = globalDefaults[directive] && globalDefaults[directive][key];\n return angular.isDefined(globalValue) ? globalValue : localDefault;\n };\n\n updateValue = function(value) {\n scope.options[key] = value ? converter(value) : getDefault();\n };\n\n if(scope[key]) {\n updateValue(scope[key]);\n }\n else if(interpolationStatus[directive] && interpolationStatus[directive][key]) {\n attrs.$observe(key, function(value) {\n updateValue(value);\n });\n }\n else {\n updateValue(attrs[key] && $interpolate(attrs[key])(scope.$parent));\n }\n });\n }\n };\n }];\n });\n\n\n /* HTML templates */\n tagsInput.run([\"$templateCache\", function($templateCache) {\n $templateCache.put('cnTagsInput/tags-input.html', `\n
    \n
  • \n \n \n
  • \n
\n
\n \n \n \n
\n \n \n \n \n ×\n \n \n \n \n
\n
\n
\n Batch\n \n Clear\n \n Update Data\n \n Copy\n \n
\n
\n \n

\n Press \"Enter\" to submit, \"Shift+Enter\" to add a new line\n

\n

\n Add multiple with brackets, eg. \"citizennet[10]\"\n

\n
\n \n
\n
`\n );\n\n $templateCache.put('cnTagsInput/auto-complete.html', `\n
\n
    \n
  • \n
\n
\n
\n
    \n
  • No results...
  • \n
  • \n
  • {{group.label | titleCase}}
  • \n
  • \n
  • \n
  • \n
  • \n
\n
\n
\n
    \n
  • \n
  • \n
\n
\n
\n
    \n
  • \n
  • {{group | titleCase}}
  • \n
  • \n
  • \n
  • \n
  • \n
\n
`\n );\n }]);\n})();\n"]} \ No newline at end of file