forked from GUMGA/components
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathManyToMany.js
executable file
·248 lines (242 loc) · 10.6 KB
/
ManyToMany.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
(function(){
'use strict';
ManyMany.$inject = ['$uibModal','$compile','$timeout'];
/**
* @ngdoc directive
* @name gumga.core:gumgaManyToMany
* @restrict E
* @description
* O componente gumgaManyToMany é um componente que é utilizado para mostrar duas listas lado a lado, e permitir que um registro seja trocado de uma lista para outra,
* assim como também visualizado os seus valores(caso seja um objeto). Um exemplo do componente pode ser encontrado [aqui](http://embed.plnkr.co/gyrqAKQQGuEHwp2npv8G/).
*
* ---
* ## Configuração de como será mostrado o valor na lista
*
*Para que o programador possa escolher como os valores serão demonstrados, foram desenvolvidas duas tags que devem estar dentro do componente manyToMany.
* <pre> <left-field>{{$value}}</left-field>
* <right-field>{{$value}}</right-field></pre>
*
* @param {Array} left-list Parâmetro obrigatório que irá conter uma variável que possuirá um array, para ser mostrado na lista da esquerda.
* *A lista da esquerda será filtrada e não conterá resultados iguais a da lista da direita.*
* @param {Array} right-list Parâmetro obrigatório que irá conter uma variável que possuirá um array, para ser mostrado na lista da direita.
* @param {Function} left-search Parâmetro obrigatório que irá conter uma variável que possuirá uma função que irá ser executada toda vez
* que o usuário digitar algo no input acima da lista. Essa função terá o valor do input como parâmetro. O parâmetro deverá ser este: `left-search="doSearch(text)"`
* @param {Function} right-search Parâmetro obrigatório que irá conter uma variável que possuirá uma função que irá ser executada toda vez
* que o usuário digitar algo no input acima da lista. Essa função terá o valor do input como parâmetro. O parâmetro deverá ser este: `right-search="doSearch(text)"`
* @param {Function} post-method Parâmetro não obrigatório que irá conter uma variável que possuirá uma função que irá ser executada quando o usuário desejar adicionar um valor
* caso sua busca não tenha trazido resultados.
* @param {Function} on-list-change Parâmetro não obrigatório que irá conter uma variável que possuirá uma função que irá ser executada quando o usuário tiver clicado em um registro
* e o mesmo tiver trocado de lista.
* @param {Function} on-value-visualization-opened Parâmetro não obrigatório que irá conter uma variável que possuirá uma função que irá ser executada quando o usuário tiver aberto o modal
* para visualização de dados
* @param {Function} on-value-visualization-closed Parâmetro não obrigatório que irá conter uma variável que possuirá uma função que irá ser executada quando o usuário tiver fechado o modal
* para visualização de dados
* @param {Boolean} authorize-add Parâmetro não obrigatório que irá conter uma variável que possuirá um booleano que irá fazer o controle para mostrar o botão de adicionar um registro caso a busca não
* tenha retornado nenhum registro
* @param {String} left-label Parâmetro não obrigatório que irá conter uma String que irá aparecer acima do input e da lista.
* @param {String} right-label Parâmetro não obrigatório que irá conter uma String que irá aparecer acima do input e da lista.
*
*/
function ManyMany($uibModal,$compile,$timeout){
return {
restrict: 'E',
scope: {
left: '=leftList',
right: '=rightList',
leftFn: '&leftSearch',
rightFn: '&rightSearch',
postMethod: '&',
onListChange: '&?',
onNewValueAdded: '&?',
onValueVisualizationOpened: '&?',
onValueVisualizationClosed: '&?',
authorizeAdd: '=?'
},
transclude: true,
link: function (scope, elm, attrs, ctrl, transcludeFn) {
scope.left = scope.left || [];
scope.right = scope.right || [];
if (!attrs.authorizeAdd) scope.authorizeAdd = true;
var mockObject = {};
scope.texts = {left: '',right: ''};
scope.template = '';
scope.labels = {left: attrs.leftLabel,right: attrs.rightLabel};
var eventHandler = {
listChange: (attrs.onListChange? scope.onListChange : angular.noop),
newValueAdded: (attrs.onNewValueAdded ? scope.onNewValueAdded : angular.noop),
valueVisualizationOpened: (attrs.onValueVisualizationOpened ? scope.onValueVisualizationOpened :angular.noop),
valueVisualizationClosed: (attrs.onValueVisualizationClosed ? scope.onValueVisualizationClosed :angular.noop)
};
transcludeFn(scope,function(cloneEl){
angular.forEach(cloneEl,function(cl){
var element = angular.element(cl)[0];
switch(element.nodeName){
case 'LEFT-FIELD':
scope.texts.left = element.innerHTML;
break;
case 'RIGHT-FIELD':
scope.texts.right = element.innerHTML;
break;
}
});
checkErrors();
});
mountRenderedContent();
scope.$watch('left',function(){
checkErrors();
copyObject(scope.left[0]);
});
function copyObject(obj) {
for (var key in obj) if (obj.hasOwnProperty(key)) {
mockObject[key] = null;
}
}
function checkErrors(){
var errorTexts = [];
if(!scope.texts.left || !scope.texts.right){
errorTexts.push('You have\'nt provided the content to GumgaManyToMany directive');
}
errorTexts.forEach(function(txt){
throw txt;
});
removeDuplicates();
}
function removeDuplicates(){
function filterOnRight(text){
return scope.right.filter(function($elm){
return $elm[attrs.filterParameter] == text;
}).length
}
scope.leftAux = scope.left.filter(function(elm){
if(filterOnRight(elm[attrs.filterParameter]) == 0){
return elm;
}
});
}
function mountRenderedContent(){
var text =
'<div class="full-width-without-padding">\n'+
' <div class="col-md-6">\n'+
' <strong><small>{{::labels.left}}</small></strong>\n' +
' <div class="{{showClass()}}">'+
' <input type="text" name="manymanyleft" ng-model="leftFilter" novalidate class="form-control"' + doesItHaveFunction('left',0) + ' ng-change="leftFn({param: leftFilter})" ng-model-options="{ updateOn: \'default blur\', debounce: {\'default\': 300, \'blur\': 0} }"/>\n' +
' <span class="input-group-addon" ng-show="showPlus(leftFilter)"> ' +
' <button type="button" ng-click="addNew(leftFilter)"><i class="glyphicon glyphicon-plus"></i></button>' +
' </span>' +
' </div>' +
' <ul class="list-group">\n' +
' <li class="list-group-item" ng-repeat="$value in leftAux ' + doesItHaveFunction('left',1) + '" ng-cloak>' +
' <a class="inside-list-anchor" ng-click="removeFromAndAddTo(leftAux,right,$value)">' + scope.texts.left + '</a>' +
' <button class="badge" ng-click="halp($value)"><i class="glyphicon glyphicon-resize-full"></i></button>' +
' </li>\n'+
' </ul>'+
' </div>\n'+
' <div class="col-md-6">\n'+
' <strong><small>{{::labels.right}}</small></strong>\n'+
' <input type="text" name="manymanyleft" ng-model="rightFilter" novalidate class="form-control"' + doesItHaveFunction('right',0) + '/>\n'+
' <ul class="list-group">\n' +
' <li class="list-group-item" ng-repeat="$value in right ' + doesItHaveFunction('right',1) + '" ng-cloak>' +
' <a class="inside-list-anchor" ng-click="removeFromAndAddTo(right,leftAux,$value)">' + scope.texts.right + '</a>' +
' <button class="badge badge-helper" ng-click="halp($value)"><i class="glyphicon glyphicon-resize-full"></i></button>' +
' </li>\n'+
' </ul>\n'+
' </div>\n'+
'</div>\n';
elm.append($compile(text)(scope));
}
scope.removeFromAndAddTo = function(removeFrom,addTo,value){
removeFrom.splice(removeFrom.indexOf(value),1);
eventHandler.listChange({$value:value});
addTo.push(value);
};
scope.addNew = function(text){
scope.leftFilter = '';
scope.postMethod({value: text });
eventHandler.newValueAdded();
};
scope.showClass = function(){
if(scope.showPlus()){
return 'input-group';
}
return '';
};
scope.halp = function(obj){
scope.template =
'<div class="modal-body">\n';
for (var key in obj) if (obj.hasOwnProperty(key) && key != '$$hashKey' && key != 'oi' && key != 'version') {
scope.template += ' <div class="form-group">\n';
scope.template += ' <label><small>'+ key +'</small></label>\n';
scope.template += ' <input type="text" ng-model="$value.' + key +'" disabled class="form-control"/>\n';
scope.template += ' </div>\n';
}
scope.template += ' <div class="modal-footer">\n';
scope.template += ' <button type="button" class="btn btn-warning" ng-click="back()">Back</button>\n';
scope.template += ' </div>\n';
scope.template += '</div>\n';
eventHandler.valueVisualizationOpened();
var mi = $uibModal.open({
template: scope.template,
size: 'sm',
controller: function($scope,$value,$uibModalInstance){
$scope.$value = $value;
$scope.back = function(){
$uibModalInstance.dismiss();
}
},
resolve: {
$value: function(){
return obj;
}
}
});
mi.result.then(function(){
eventHandler.valueVisualizationClosed();
})
};
scope.showPlus = function(){
function filterLeft(){
return scope.leftAux.filter(function(el){
return el[attrs.filterParameter] == scope.leftFilter;
}).length < 1;
}
function filterRight(){
return scope.right.filter(function(el){
return el[attrs.filterParameter] == scope.leftFilter;
}).length < 1;
}
if(scope.authorizeAdd == true){
return filterLeft() && filterRight();
}
return false;
};
scope.doesItHaveClass = function(){
if(scope.left.length > 0){
return '';
}
return 'input-group';
};
function doesItHaveFunction(field,place){
if(place == 0){
if(field == 'left' && attrs.leftFn){
return 'ng-change= "' + attrs.leftFn +'({text: leftFilter})" ';
}
if(field == 'right' && attrs.rightFn){
return 'ng-change= "' + attrs.leftFn +'({text: rightFilter})" ';
}
return '';
} else {
if(field == 'left' && !attrs.leftFn){
return ' | filter: leftFilter';
}
if(field == 'right' && !attrs.rightFn){
return ' | filter: rightFilter'
}
return '';
}
}
}
}
}
angular.module('gumga.directives.manytomany',['ui.bootstrap'])
.directive('gumgaManyToMany',ManyMany)
})();