scratch – Blame information for rev 125
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
125 | office | 1 | /* |
2 | * bootstrap-tagsinput v0.8.0 |
||
3 | * |
||
4 | */ |
||
5 | |||
6 | angular.module('bootstrap-tagsinput', []) |
||
7 | .directive('bootstrapTagsinput', [function() { |
||
8 | |||
9 | function getItemProperty(scope, property) { |
||
10 | if (!property) |
||
11 | return undefined; |
||
12 | |||
13 | if (angular.isFunction(scope.$parent[property])) |
||
14 | return scope.$parent[property]; |
||
15 | |||
16 | return function(item) { |
||
17 | return item[property]; |
||
18 | }; |
||
19 | } |
||
20 | |||
21 | return { |
||
22 | restrict: 'EA', |
||
23 | scope: { |
||
24 | model: '=ngModel' |
||
25 | }, |
||
26 | template: '<select multiple></select>', |
||
27 | replace: false, |
||
28 | link: function(scope, element, attrs) { |
||
29 | $(function() { |
||
30 | if (!angular.isArray(scope.model)) |
||
31 | scope.model = []; |
||
32 | |||
33 | var select = $('select', element); |
||
34 | var typeaheadSourceArray = attrs.typeaheadSource ? attrs.typeaheadSource.split('.') : null; |
||
35 | var typeaheadSource = typeaheadSourceArray ? |
||
36 | (typeaheadSourceArray.length > 1 ? |
||
37 | scope.$parent[typeaheadSourceArray[0]][typeaheadSourceArray[1]] |
||
38 | : scope.$parent[typeaheadSourceArray[0]]) |
||
39 | : null; |
||
40 | |||
41 | select.tagsinput(scope.$parent[attrs.options || ''] || { |
||
42 | typeahead : { |
||
43 | source : angular.isFunction(typeaheadSource) ? typeaheadSource : null |
||
44 | }, |
||
45 | itemValue: getItemProperty(scope, attrs.itemvalue), |
||
46 | itemText : getItemProperty(scope, attrs.itemtext), |
||
47 | confirmKeys : getItemProperty(scope, attrs.confirmkeys) ? JSON.parse(attrs.confirmkeys) : [13], |
||
48 | tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ? scope.$parent[attrs.tagclass] : function(item) { return attrs.tagclass; } |
||
49 | }); |
||
50 | |||
51 | for (var i = 0; i < scope.model.length; i++) { |
||
52 | select.tagsinput('add', scope.model[i]); |
||
53 | } |
||
54 | |||
55 | select.on('itemAdded', function(event) { |
||
56 | if (scope.model.indexOf(event.item) === -1) |
||
57 | scope.model.push(event.item); |
||
58 | }); |
||
59 | |||
60 | select.on('itemRemoved', function(event) { |
||
61 | var idx = scope.model.indexOf(event.item); |
||
62 | if (idx !== -1) |
||
63 | scope.model.splice(idx, 1); |
||
64 | }); |
||
65 | |||
66 | // create a shallow copy of model's current state, needed to determine |
||
67 | // diff when model changes |
||
68 | var prev = scope.model.slice(); |
||
69 | scope.$watch("model", function() { |
||
70 | var added = scope.model.filter(function(i) {return prev.indexOf(i) === -1;}), |
||
71 | removed = prev.filter(function(i) {return scope.model.indexOf(i) === -1;}), |
||
72 | i; |
||
73 | |||
74 | prev = scope.model.slice(); |
||
75 | |||
76 | // Remove tags no longer in binded model |
||
77 | for (i = 0; i < removed.length; i++) { |
||
78 | select.tagsinput('remove', removed[i]); |
||
79 | } |
||
80 | |||
81 | // Refresh remaining tags |
||
82 | select.tagsinput('refresh'); |
||
83 | |||
84 | // Add new items in model as tags |
||
85 | for (i = 0; i < added.length; i++) { |
||
86 | select.tagsinput('add', added[i]); |
||
87 | } |
||
88 | }, true); |
||
89 | }); |
||
90 | } |
||
91 | }; |
||
92 | }]); |