PageSourceSearch

https://www.vas2025.org/resources/static/js/angular-module/tt-data.js

js vas2025.org collected 2026-10-08 11:02:12 UTC 61,953 bytes, 1,894 lines download raw bytes

1
2var files = {};
3
4var ttData = angular.module('ttData', ['ngRoute', 'ngResource', 'ngAnimate', 'ngMaterial', 'ngMessages', /* 'ngMdIcons', */ 'ngCookies' ]);
5
6ttData.service('ttDataAPI', ttDataAPI);
7ttDataAPI.$inject = ['$q', '$parse', '$rootScope', '$resource', '$http', '$cookies'];
8    
9function ttDataAPI($q, $parse, $rootScope, $resource, $http, $cookies) { 
10    	
11	return {
12		putCookie: putCookie,
13		removeCookie: removeCookie,
14		resolveCookie: resolveCookie,
15    	getAPI: getAPI,
16    	getNew: getNew,
17    	getAllPageable: getAllPageable,
18    	getDataPageable: getDataPageable,
19    	getDataArray: getDataArray,
20    	remove: remove,
21    	save: save,
22    	// saveWithParams: saveWithParams,
23    	savePut: savePut,
24    	copy: copy,
25    }
26    
27	function removeCookie(objectName) {
28		$cookies.remove(objectName + 'ID');
29	}
30	
31	function putCookie(objectName, object) {
32		$cookies.put(objectName + 'ID', object.id, {'expires': $rootScope.expireDate});
33	}
34	
35	function resolveCookie(objectName, domains) {
36		var sdeferred = $q.defer();
37		
38		var objectID = $cookies.get(objectName + 'ID');
39		if (objectID) {
40			getAPI(domains).get({ id: objectID }).$promise.then(
41				function(result) { 
42					sdeferred.resolve(result);
43				},
44				function(result) { 
45					sdeferred.reject(result);
46				}
47			);
48		} else {
49			sdeferred.reject(null);
50		}
51		return sdeferred.promise;
52	}
53	
54	function getAPI(domains) {
55		return $resource("/api/" + domains + "/:id", null, { 'put': { method:'PUT' } });
56	}
57     
58    function getNew(domains) {
59    	return $resource("/api/" + domains + "/new").get().$promise;
60    }
61    
62    function getAllPageable(domains, params, $scope) {
63    	var sdeferred = $q.defer();
64    	if (!params) {
65    		params = { pagination: { offset: 0, limit: 0, orders: [{field: 'id', dir: 'ASC'}] }};
66    	}
67    	if (!params.pagination.orders) {
68    		params.pagination.orders = [{field: 'id', dir: 'ASC'}];
69    	}	
70    	
71//    	var $paginationParams = $parse(domains + 'PaginationParams');
72//		$paginationParams.assign($scope, params);
73    	
74    	$scope[domains + 'PaginationParams'] = params;
75    	
76//		getAPI(domains).get(params).$promise.then(
77		$resource('/api/' + domains, {}, {
78		    get: {
79		        method: 'GET',
80		        headers: { 'pagination' : angular.toJson(params.pagination) }
81		    }
82		}).get().$promise.then(		
83				
84			function(data) { 
85				
86				if ($scope) {
87					
88					var pagination = { 
89						first: data.first,
90						last: data.last,
91						number: data.number,
92						numberOfElements: data.numberOfElements,
93						size: data.size,
94						sort: data.sort,
95						totalElements: data.totalElements,
96						totalPages: data.totalPages
97					};					
98					
99//    				var pagination = angular.copy(data);
100//    				delete pagination.content;
101    				
102//    				var $pagination = $parse(domains + 'Pagination');
103//    				$pagination.assign($scope, pagination);
104    				
105    				$scope[domains + 'Pagination'] = pagination;
106    				$rootScope.$broadcast('new-pagination', { name: domains + 'Pagination',  data: pagination, params: params });
107				}
108				
109				sdeferred.resolve(data.content);
110			},
111			function(response) {
112				sdeferred.reject(response);
113			}
114		);
115    	
116    	return sdeferred.promise;
117    }
118    
119    function getDataPageable(url, paginationPrefix, params, $scope) {
120//    	return $resource(url).query().$promise;
121     	var sdeferred = $q.defer();
122     	if (!params) {
123    		params = { pagination: { offset: 0, limit: 0, orders: [{field: 'id', dir: 'ASC'}] }};
124    	}
125    	if (!params.pagination.orders) {
126    		params.pagination.orders = [{field: 'id', dir: 'ASC'}];
127    	}	
128
129//    	var $paginationParams = $parse(paginationPrefix + 'PaginationParams');
130//		$paginationParams.assign($scope, params);
131    	
132		$scope[paginationPrefix + 'PaginationParams'] = params;
133		
134//		$resource(url).get(params).$promise.then(
135		$resource(url, {}, {
136		    get: {
137		        method: 'GET',
138		        headers: { 'pagination' : angular.toJson(params.pagination) }
139		    }
140		}).get().$promise.then(	
141			function(data) {
142				
143				if ($scope) {
144					
145//    				var pagination = angular.copy(data);
146//    				delete pagination.content;
147    				
148					var pagination = { 
149						first: data.first,
150						last: data.last,
151						number: data.number,
152						numberOfElements: data.numberOfElements,
153						size: data.size,
154						sort: data.sort,
155						totalElements: data.totalElements,
156						totalPages: data.totalPages
157					};	
158					
159//    				var $pagination = $parse(paginationPrefix + 'Pagination');
160//    				$pagination.assign($scope, pagination);
161    				
162    				$scope[paginationPrefix + 'Pagination'] = pagination;
163    				$rootScope.$broadcast('new-pagination', { name: paginationPrefix + 'Pagination',  data: pagination, params: params });    				
164
165				}
166				
167				sdeferred.resolve(data.content);
168			},
169			function(response) {
170				sdeferred.reject(response);
171			}
172		);
173    		    	
174    	return sdeferred.promise;
175    }
176    
177    function getDataArray(url) {
178    	return $resource(url).query().$promise;
179    }
180    
181    function remove(domains, item) {
182    	return getAPI(domains).delete({ id: item.id }).$promise;
183    }
184    
185    function save(domains, item) {
186    	saveWithParams(domains, item, null);
187    }
188    
189    function save(domains, item, parameters) {
190    	var deferred = $q.defer();
191		
192		$http({
193			method: 'POST',
194			url: "/api/" + domains,
195			headers: { 'Content-Type': undefined },
196			transformRequest: function (data) {                
197				var formData = new FormData();
198				formData.append("item", angular.toJson(data.item));
199                
200				for (var bind in data.files) {
201					formData.append(bind, files[bind]);
202				}
203				if (parameters) {
204					for (var param in parameters) {
205						formData.append(param, parameters[param]);
206					}
207				}
208                
209				return formData;
210			},
211			data: { item: item, files: files }
212		}).then(function(response) { files = {}; deferred.resolve(response.data); },
213		        function(response) { deferred.reject(response); }
214		);
215		
216		return deferred.promise;
217    }
218    
219    function savePut(domains, item) {
220    	var deferred = $q.defer();
221		
222		$http({
223			method: 'PUT',
224			url: "/api/" + domains,
225			data: item
226		}).then(function(response) { deferred.resolve(response.data); },
227		        function(response) { deferred.reject(response); }
228		);
229		
230		return deferred.promise;
231    }
232    
233    function copy(domains, item, data) {
234    	var deferred = $q.defer();
235		
236    	if (!data) {
237    		data = {};
238    	}
239    	
240		$http({
241			method: 'POST',
242			url: "/api/" + domains + '/' + item.id + '/copy',
243			timeout: (10 * 60 * 1000), // 10 minutes !
244			headers: (data ? { 'Content-Type': 'application/x-www-form-urlencoded' } : { 'Content-Type': 'application/json' }),
245			data: $.param(data),
246		}).then(function(response) { deferred.resolve(response.data); },
247		        function(response) { deferred.reject(response); }
248		);
249		
250		return deferred.promise;
251    }
252  
253}
254    
255ttData.service('ttDataUI', ttDataUI);
256ttDataUI.$inject = [ '$rootScope', '$http', '$mdDialog', '$mdToast', '$q', '$parse', '$sce', 'ttDataAPI'];
257function ttDataUI($rootScope, $http, $mdDialog, $mdToast, $q, $parse, $sce, ttDataAPI) { 
258 
259	return {
260		makeControllerSequenceable: makeControllerSequenceable,
261		resequenceModel: resequenceModel,
262		editDialog: editDialog,
263		removeDialog: removeDialog,
264		copyDialog: copyDialog,
265		childrenListDialog: childrenListDialog
266	}
267    
268	function resequenceModel(model, itemIndex, updateVersions) {
269		
270		if (itemIndex >= 0 && model[itemIndex].hasOwnProperty('sequence')) {
271		
272			var newSequence = model[itemIndex].sequence;
273				
274			// console.log('new sequence', newSequence);
275			
276			// resequence lower
277			var idxl = newSequence - 1;
278			if (itemIndex - 1 >= 0) {
279	    		for (var i = itemIndex - 1; i >= 0; i--) { 
280	    			// console.log('lower', model[i].sequence, '>', idxl);
281	    			if (model[i].sequence !== idxl) {
282	    				model[i].sequence = idxl;
283	    				if (updateVersions) { model[i].optlock = model[i].optlock + 1; }
284	    			}
285	    			idxl = idxl - 1;
286	    		}
287			}
288			// resequence higher
289			var idxh = newSequence + 1;
290			if (itemIndex + 1 < model.length) {
291	    		for (var i = itemIndex + 1; i < model.length; i++) { 
292	    			// console.log('higher', model[i].sequence, '>', idxh);
293	    			if (model[i].sequence !== idxh) {
294		    			model[i].sequence = idxh;
295		    			if (updateVersions) { model[i].optlock = model[i].optlock + 1; }
296	    			}
297	    			idxh = idxh + 1;
298	    		}
299			}
300		}
301	}
302	
303	function makeControllerSequenceable($scope) {
304		$scope.sequenceableListOptions = {
305				disabled: false,
306				axis: 'y',
307				start: function(e, ui) {
308//					console.log(ui);
309				},
310			    stop: function(e, ui) {
311			    	
312//			    	console.log(ui.item.sortable.index, ui.item.sortable.dropindex);
313			    	
314			    	if (ui.item.sortable.dropindex >= 0 && ui.item.sortable.index !== ui.item.sortable.dropindex) { // && ui.item.sortable.dropindex >= 0) { 		
315			    		
316			    		var domains = $(ui.item).closest('[ui-sortable]').attr('tt-sortable-domain');
317			    		if (domains) {
318				    		
319			    			var model = ui.item.sortable.sourceModel;
320			    			var dropIndex = ui.item.sortable.dropindex;
321			    			
322				    		var newSequence = dropIndex + 1			    		
323				    		var itemForUpdate = model[dropIndex];
324				    		itemForUpdate.sequence = newSequence; 
325				    		
326				    		ttDataAPI.save(domains, itemForUpdate, { onlySort: true }).then(
327				    			function(response) {  
328				    				
329				    				model[dropIndex] = response;
330				    				resequenceModel(model, dropIndex, true);
331						    		
332				    			},
333				    		    function(response) {  }
334				    		);
335				    		
336			    		}
337			    		
338			    	}
339			    }
340			}
341	}
342	
343	function editDialog(domains, $scope, options) {
344		
345		var $controllerScope = $scope;
346		
347		var ev				= options.ev;
348		var index 			= options.index;
349		var item 			= options.item;
350		var submitCallback 	= options.submitCB;
351		var cancelCallback 	= options.cancelCB;
352		var closeCallback  	= options.closeCB;
353		var hideCallback  	= options.hideCB;
354		var method			= options.method;
355		var noClearFiles	= options.noClearFiles;
356		var dialogTemplate	= options.dialogTemplate;
357		var noSave			= options.noSave;
358		// options.onResequence = function
359		// options.useFiles = object
360		
361		var addToEnd		= false;
362		if (options.addToEnd) {
363			addToEnd = options.addToEnd;
364		}
365		
366		// if (options.simpleList) {
367			var $scopedList = options.simpleList;
368		// }
369		
370		if (!submitCallback) {
371			submitCallback = function(item) {
372				var sdeferred = $q.defer();
373				
374				var saveSuccess = function(data) {
375		    		var savedItem = data;		
376		    		
377		    		if (options.onSuccess) {
378		    			options.onSuccess(savedItem);
379		    		}
380		    		
381		    		var $selectedItem = $scope.$eval(options.selectedItem);				
382					if ($selectedItem && $selectedItem.id === savedItem.id) {
383						var $selectedItemModel = $parse(options.selectedItem);
384						$selectedItemModel.assign($scope, savedItem);
385					}
386		    		
387					if ($scopedList) {
388				    	if (index >= 0) {
389				    		$scopedList[index] = savedItem;
390				    	} else {
391				    		index = 0;
392				    		var exists = false;
393				    		
394				    		var i = 0;
395							angular.forEach($scopedList, function(itemList, key) {
396								if (itemList.id == item.id) {
397									$scopedList[i] = savedItem;
398									exists = true;
399								}
400								i++;
401							});
402				    		
403				    		if (!exists) {
404				    			if (!addToEnd) {
405				    				$scopedList.unshift(savedItem);
406				    			} else {
407				    				$scopedList.push(savedItem);
408				    			}
409				    		}
410				    	}
411				    	
412				    	resequenceModel($scopedList, index, false);		
413					} else {
414						item = angular.extend({}, item, savedItem);
415					}
416			    	sdeferred.resolve(savedItem);
417				    	
418		    	}
419				var saveFailed = function(response) { sdeferred.reject(response); }
420				
421				if (item.hasOwnProperty('sequence')) {
422					if (!item.sequence || item.sequence < 1) {
423						if (!addToEnd) {
424							item.sequence = 1;
425						} else {
426							item.sequence = $scopedList.length + 1;
427						}
428					}
429					
430				}
431				
432				if (!noSave) {
433					if (method && method == 'PUT') {
434						ttDataAPI.savePut(domains, item).then(saveSuccess, saveFailed);
435					} else {
436						ttDataAPI.save(domains, item).then(saveSuccess, saveFailed);
437					}
438				} else {
439					saveSuccess(item);
440				}
441				
442				return sdeferred.promise;
443			}
444		}
445    	
446		var needCompany = function(item) {
447			
448			var deferred = $q.defer();
449			
450			if (item.hasOwnProperty('company') && !item.id) { 
451				
452				var companiesURL = undefined;
453				if (!$rootScope.authenticationInfo.authentication.principal.id || $rootScope.authenticationInfo.authentication.principal.userCompanies.length < 1) {
454					
455					if (!$rootScope.authenticationInfo.authentication.principal.supervisor) {
456						$mdToast.show( $mdToast.simple().action('Confirm').highlightAction(true).textContent('current nonsupervisor user does\'t set up any company').position('top right').hideDelay(3000) );
457						deferred.reject();
458						return;
459					}
460					
461					var companiesURL = $rootScope.application.authServer + '/api/companies';
462				} else if ($rootScope.authenticationInfo.authentication.principal.id && $rootScope.authenticationInfo.authentication.principal.userCompanies.length > 1) {
463					companiesURL = $rootScope.application.authServer + '/api/users/' + $rootScope.authenticationInfo.authentication.principal.id + '/companies';
464				}	
465				
466				if (companiesURL) { 
467					
468					ttDataAPI.getDataArray(companiesURL).then(
469						function(companies) { 
470							
471							var selectCompanyController = function ($scope, $mdDialog, availableCompanies, citem) { 	
472								
473			 			    	$scope.citem = citem;
474								$scope.availableCompanies = availableCompanies;
475								
476								$scope.cancel = function() {
477		 				    		$mdDialog.cancel();
478			 					};		 			    		
479			 					$scope.submit = function(citem) {
480			 						$mdDialog.hide(citem);
481			 					}
482							}
483							
484							$mdDialog.show({    	
485								controller: selectCompanyController,    
486								templateUrl: $sce.trustAsResourceUrl((!$rootScope.application.authServer ? '' : $rootScope.application.authServer) + '/dialog/_dialog-companies'),
487				 				//templateUrl: '/dialog/_dialog-companies',
488				 		        parent: angular.element(document.body),
489				 		        targetEvent: ev,
490				 		        locals : {
491				 		        	availableCompanies : companies,
492				 		        	citem : {}
493				 		        },
494				 		        fullscreen: true,
495				 		        multiple: false,
496				 		        clickOutsideToClose: true,
497				 		        escapeToClose: true,
498				 		        onComplete: function(scope, element) { element.draggable({ handle: 'md-toolbar', cursor: "move" }); }
499			 				})
500			 				.then(
501			 					function (citem) {
502			 						if (item.hasOwnProperty('company') && !item.id) {
503				 						item.company = citem.company.id; 
504			 						}
505			 						deferred.resolve(item);
506			 					},
507			 					function () {
508			 						deferred.reject();
509			 					}
510			 				);
511						
512						},
513						function(response) { deferred.reject(); /* fetch companies error */ }
514					);
515					
516				} else {
517					deferred.resolve(item);
518				}
519			
520			} else {
521				deferred.resolve(item);
522			}
523			
524			return deferred.promise;
525		}
526				
527    	var deferred = $q.defer();
528 		deferred.promise.then(
529 			function(item) {	
530
531// 				console.log('item with date fields', item);
532 				
533 				needCompany(item).then(
534 					function(item) {
535 				
536 						var dialogPromise;
537 						
538		 			    var editDialogController = function ($http, $q, $scope, $mdDialog, $mdToast, item, submitCallback, cancelCallback, parentScope) { 
539		 			    	$scope.parentScope = parentScope;
540		 			    	$scope.item = angular.copy(item);
541		 			    	
542		 			    	if (!noClearFiles) {
543		 			    		files = {};
544		 			    	}
545		 			    		
546		 			    	$scope.$on("file-selected", function (event, args) {       
547		 			    		files[args.bind] = args.file;
548		 			    	});
549		 			    	    
550		 			    	$scope.runParentFunction = function(parentFunction, argument) {
551		 			    		if (parentScope && angular.isFunction(parentScope[parentFunction])) {
552		 			    			parentScope[parentFunction]($scope.item, argument);
553		 			    		}
554		 			    	}
555		 			    		
556		 			    	$scope.cancel = function() {
557		 			    		if (cancelCallback) {
558		 			    			$q.when(cancelCallback(item)).then(function(item) { $mdDialog.cancel(); }, function(item) { /* do nothing - stay dialog opened */ });
559		 				    	} else {
560		 				    		$mdDialog.cancel();
561		 				    	}
562		 					};
563		 			    		
564		 					$scope.submit = function(item) { 
565		 			    		if (submitCallback) {
566		 			    			$scope.dialogProgress = true;
567		 			    	    	$q.when(submitCallback(item)).then(
568		 				    			function(savedItem) { 
569		 				    				
570		 				    				$rootScope.$broadcast('update-item', { item: savedItem });
571		 				    				
572		 				    				$scope.dialogProgress = null;
573		 				    				if (!$scope.stayDialogOpened) {
574		 				    					$mdDialog.hide(savedItem);
575		 				    				} else {
576		 				    					$scope.item = savedItem;
577		 				    					if (hideCallback) {
578		 					 						hideCallback(item);
579		 				 			    		}
580		 				    					if (closeCallback) {
581		 					 						closeCallback();
582		 				 			    		}
583		 				    					//TODO dialogPromise.resolve(savedItem);
584		 				    				}
585		 				    				$mdToast.show( $mdToast.simple().action('OK').highlightAction(true).textContent('successfuly processed').position('top right').hideDelay(3000) ); //.theme("success-toast")
586		 				    			
587		 				    				if (!item.id) {
588		 				    					$controllerScope[domains + 'Pagination'].numberOfElements = $controllerScope[domains + 'Pagination'].numberOfElements +1;
589		 					 					$controllerScope[domains + 'Pagination'].totalElements = $controllerScope[domains + 'Pagination'].totalElements +1;
590		 				    				}
591		 				    			}, 
592		 				    			function(response) { 
593		 					    			$scope.dialogProgress = null; 
594		 					    			$mdToast.show( $mdToast.simple().action('Confirm').highlightAction(true).textContent(response.data.message).position('top right').hideDelay(10000) ); //.theme("error-toast")	    			
595		 				    			});
596		 			    		} else {
597		 			    			$scope.dialogProgress = null;
598		 			    			if (!$scope.stayDialogOpened) {
599 				    					$mdDialog.hide(savedItem);
600 				    				} else {
601 				    					$scope.item = savedItem;
602 				    					if (hideCallback) {
603 					 						hideCallback(item);
604 				 			    		}
605 				    					if (closeCallback) {
606 					 						closeCallback();
607 				 			    		}
608 				    					//TODO dialogPromise.resolve(savedItem);
609 				    				}
610		 			    		}
611		 			    	}
612		 			    		
613		 			    	$scope.enums = new Object();
614		 			    	$scope.loadEnums = function(enumType) {
615		 						var deferred = $q.defer();
616		 						
617		 						$http({
618		 						    url: "/api/enums/" + enumType, 
619		 						    method: "GET",
620		 						 }).then( function sc(response) {
621		 							 $scope.enums[enumType] = response.data;
622		 							 deferred.resolve(response.data);
623		 						 });
624		 						
625		 						return deferred.promise;
626		 					}
627		 			    		
628		 					$scope.details = new Object();
629		 					$scope.loadDetails = function(detailType) {
630		 						var deferred = $q.defer();
631		 						
632		 						$http({
633		 						    url: "/api/" + detailType, 
634		 						    method: "GET",
635		 						 }).then( function sc(response) {
636		 							 $scope.details[detailType] = response.data;
637		 							 deferred.resolve(response.data);
638		 						 });
639		 						
640		 						return deferred.promise;
641		 					}
642		 			    		
643		 					$scope.resequenceList = function(list) {	
644 						    	var i = 1;
645 								angular.forEach(list, function(item, key) {					
646 									item.sequence = i;
647 									i++;
648 								});
649		 					}
650		 					
651		 					$scope.sequenceableOptions = {
652		 						handle: '.drag-handle',	
653		 						disabled: false,
654		 						axis: 'y',
655		 					    stop: function(e, ui) {
656		 					    	if (ui.item.sortable.dropindex >= 0) { 	
657		 					    		
658		 					    		angular.forEach(ui.item.sortable.sourceModel, function(item, key) {					
659		 									item.oldSequence = item.sequence;
660		 								});
661		 					    		
662		 					    		$scope.resequenceList(ui.item.sortable.sourceModel);
663		 					    		
664		 					    		if (options.onResequence) {
665			 					    		options.onResequence($scope.item, ui.item.sortable.sourceModel, ui.item.sortable.dropindex);
666		 					    		}
667		 					    		
668		 					    		// resequence files
669		 					    		var newFiles = {};
670			 					   		angular.forEach(ui.item.sortable.sourceModel, function(listitem, key) {					
671			 					   			if (listitem.oldSequence != listitem.sequence) {
672			 					   				for (var bind in files) {
673			 					   					if (bind.indexOf('[' + (listitem.oldSequence - 1) + ']') !== -1) {
674			 					   						var file = files[bind];
675			 					   						var newBind = bind.replace('[' + (listitem.oldSequence - 1 ) + ']', '[' + (listitem.sequence - 1) + ']');
676			 					   						delete files[bind];
677			 					   						newFiles[newBind] = file;
678			 					   					}
679			 					   				}
680			 					   			}
681			 					   		});			 					   		
682			 					   		files = angular.extend({}, files, newFiles);
683		 					    		
684		 					    	}
685		 					    }
686		 					}
687		 					
688		 					// children functions
689		 					
690		 					$scope.add = function($event, domains, child, list, options) {
691		 						var submitCB = function(child) {
692		 							child.sequence = list.length + 1;
693		 							list.push(child);
694		 						}
695		 						editDialog(domains, $scope, { ev: $event, index: -1, item: child, submitCB: submitCB, dialogTemplate: options.template, noSave: options.noSave, noClearFiles: options.noClearFiles });
696		 					}
697		 					
698		 					$scope.edit = function($event, $index, domains, child, list, options) {
699		 						var submitCB = function(child) {
700		 							list[$index] = child;
701		 						}
702		 						editDialog(domains, $scope, { ev: $event, index: $index, item: child, submitCB: submitCB, dialogTemplate: options.template, noSave: options.noSave, noClearFiles: options.noClearFiles });
703		 					}
704		 					
705		 					$scope.remove = function($event, $index, domains, child, list, options) {
706		 						removeDialog(domains, $scope, { doDelete: options.doDelete, identification: item.id, ev: $event, index: $index, item: child, simpleList: list });
707		 					}
708		 					
709		 			    		
710		 			    } 
711		 			
712		 			   dialogPromise = $mdDialog.show({    	
713			 		        controller: editDialogController,    	
714			 				templateUrl: (dialogTemplate ? dialogTemplate : '/dialog/dialog-' + domains),
715			 		        parent: angular.element(document.body),
716			 		        targetEvent: ev,
717			 		        fullscreen: true,
718			 		        multiple: true,
719			 		        locals: {
720			 		        	item: item,
721			 		        	parentScope: $scope,
722			 		        	submitCallback: submitCallback,
723			 		        	cancelCallback: cancelCallback,
724			 		        },
725			 		        clickOutsideToClose: true,
726			 		        escapeToClose: true,
727			 		        onComplete: function(scope, element) {
728			 		        	element.draggable({ handle: 'md-toolbar', cursor: "move" });
729			 		        }
730		 				});
731		 			   
732		 			    dialogPromise.then(
733		 					function(item) {
734			 					if (hideCallback) {
735			 						hideCallback(item);
736		 			    		}
737		 					},
738			 				function() {	
739		 				}).finally(function() {
740		 					if (closeCallback) {
741		 						closeCallback();
742	 			    		}		 					
743					    });
744 				
745 					},
746 					function(response) {
747 						// console.log('canceled need company dialog');
748 					}
749 				);
750 				
751 			}, 
752 			function(reason) { /* TODO 'toast' entity item for edit not exist */ }
753 		);
754    	
755 		if (!item) {
756 			ttDataAPI.getNew(domains).then( function success(response) { item = response; deferred.resolve(item); }, 
757 											function success(response) { deferred.reject(response); } );
758		} else {
759			deferred.resolve(item);
760		}	
761 		
762 		return deferred.promise;
763    }
764    
765	function removeDialog(domains, $scope, options) {
766		
767		var $controllerScope = $scope;
768		
769		var doDelete		= options.doDelete;
770		var ev				= options.ev;
771		var identification  = options.identification;
772		var index 			= options.index;
773		var item 			= options.item;
774		var submitCallback 	= options.submitCB;
775		var cancelCallback 	= options.cancelCB;
776		var closeCallback  	= options.closeCB;
777		var removeCallback  = options.removeCB;
778		
779		if (options.simpleList) {
780			var $scopedList = options.simpleList;
781			submitCallback = function(item) { 
782				$scopedList.splice(index, 1);	
783				
784				var $selectedItem = $scope.$eval(options.selectedItem);				
785				if ($selectedItem && $selectedItem.id === item.id) {
786					var $selectedItemModel = $parse(options.selectedItem);
787					$selectedItemModel.assign($scope, undefined);
788				}
789				
790				if ($scopedList[index] && $scopedList[index].hasOwnProperty('sequence')) {
791					
792					angular.forEach($scopedList, function(item, key) {					
793						item.oldSequence = item.sequence;
794					});
795					
796					$scopedList[index].sequence = item.sequence;
797					resequenceModel($scopedList, index, false);
798					
799					// resequence files
800		    		var newFiles = {};
801			   		angular.forEach($scopedList, function(listitem, key) {					
802			   			if (listitem.oldSequence != listitem.sequence) {
803			   				for (var bind in files) {
804			   					if (bind.indexOf('[' + (listitem.oldSequence - 1) + ']') !== -1) {
805			   						var file = files[bind];
806			   						var newBind = bind.replace('[' + (listitem.oldSequence - 1 ) + ']', '[' + (listitem.sequence - 1) + ']');
807			   						delete files[bind];
808			   						newFiles[newBind] = file;
809			   					}
810			   				}
811			   			}
812			   		});
813			   		
814			   		files = angular.extend({}, files, newFiles);
815					
816				}
817				
818			}
819		}
820		
821		var deferred = $q.defer();
822 		deferred.promise.then(
823 			function(item) {
824 				
825 				var removeDialogController = function ($http, $q, $scope, $mdDialog, $mdToast, doDelete, item, submitCallback, cancelCallback, parentScope) { 
826 					$scope.item = angular.copy(item);	
827 					$scope.identification = identification;
828 					
829 			    	$scope.cancel = function() {
830 			    		if (cancelCallback) {
831 			    			$q.when(cancelCallback(item)).then(function(item) { $mdDialog.cancel(); }, function(item) { /* do nothing - stay dialog opened */ });
832 				    	} else {
833 				    		$mdDialog.cancel();
834 				    	}
835 					};
836 			    		
837 					$scope.submit = function(item) {
838 						
839 						var ddeferred = $q.defer();
840 						
841 						ddeferred.promise.then(
842				 			function(item) {
843				 				// delete success or only dialog
844				 				if (submitCallback) { 
845		 			    	    	$q.when(submitCallback(item)).then( 
846		 				    			function(item) { // submit callback resolved
847		 				    				$scope.dialogProgress = null;
848		 				    				$mdDialog.hide(item);
849		 				    				
850		 				    				if (doDelete) {
851		 					 					$controllerScope[domains + 'Pagination'].numberOfElements = $controllerScope[domains + 'Pagination'].numberOfElements -1;
852		 					 					$controllerScope[domains + 'Pagination'].totalElements = $controllerScope[domains + 'Pagination'].totalElements -1;
853		 					 				}
854		 				    				
855		 				    			}, 
856		 				    			function(response) { // submit callback reject
857		 					    			$scope.dialogProgress = null; 
858		 				    			});
859		 			    		} else {
860		 			    			$scope.dialogProgress = null;
861		 			    			$mdDialog.hide(item);
862		 			    		}
863				 				
864				 			},
865				 			function(item) {
866				 				// delete failed
867				 				$scope.dialogProgress = null; 
868				 			}
869				 		);
870 						
871 						if (doDelete) {
872	 						$scope.dialogProgress = true;
873	 						ttDataAPI.remove(domains, item).then(
874	 							function() {
875 				    				// delete success
876			    					$mdToast.show( $mdToast.simple().action('OK').highlightAction(true).textContent('successfuly processed').position('top right').hideDelay(3000) ); //.theme("success-toast")
877	 								ddeferred.resolve(item);
878	 							},
879	 							function(response) {
880	 								// delete failed
881					    			$mdToast.show( $mdToast.simple().action('Confirm').highlightAction(true).textContent(response.data.message).position('top right').hideDelay(10000) ); //.theme("error-toast")
882 					    			ddeferred.reject(item);
883	 							}
884	 						);
885 						} else {
886 							// no action, only dialog
887 							ddeferred.resolve(item);
888 						}
889 			    		
890 			    		return ddeferred.promise;
891 			    	}
892 			    		
893 			    } 
894 			
895 				$mdDialog.show({    	
896	 		        controller: removeDialogController,    	
897	 				templateUrl: '/dialog/_dialog-remove',
898	 		        parent: angular.element(document.body),
899	 		        targetEvent: ev,
900	 		        fullscreen: true,
901	 		        multiple: true,
902	 		        locals: {
903	 		        	doDelete: doDelete,
904	 		        	item: item,
905	 		        	parentScope: $scope,
906	 		        	submitCallback: submitCallback,
907	 		        	cancelCallback: cancelCallback,
908	 		        },
909	 		        clickOutsideToClose: true,
910	 		        escapeToClose: true,
911	 		        onComplete: function(scope, element) {
912	 		        	element.draggable({ handle: 'md-toolbar', cursor: "move" });
913	 		        }
914 				})
915 				.then(function(data) {
916 					if (removeCallback) {
917 						removeCallback(item);
918 					}
919				  }, function(err) {
920				    // console.error(err);
921				  }).finally(function() {
922					  closeCallback(item);
923				  });
924 				
925 				
926//	 		    .finally(function() {
927//			        closeCallback(item);
928//			    });
929 				
930 			}, 
931 			function(reason) { /* TODO 'toast' entity item for delete not exist */ }
932 		);
933		
934 		if (!item) {
935 			deferred.reject(item);
936		} else {
937			deferred.resolve(item);
938		}
939 		
940 		return deferred.promise;
941	}
942	
943	function copyDialog(domains, $scope, options) {
944		
945		var $controllerScope = $scope;
946		
947		var ev				= options.ev;
948		var identification  = options.identification;
949		var index 			= options.index;
950		var item 			= options.item;
951		var submitCallback 	= options.submitCB;
952		var cancelCallback 	= options.cancelCB;
953		var closeCallback  	= options.closeCB;
954		
955		var addToEnd		= false;
956		if (options.addToEnd) {
957			addToEnd = options.addToEnd;
958		}
959		
960		if (options.simpleList) {
961			var $scopedList = options.simpleList;
962			submitCallback = function(item) {		
963
964    			if (!addToEnd) {
965    				$scopedList.unshift(item);
966    			} else {
967    				$scopedList.push(item);
968    			}
969				
970				var $selectedItem = $scope.$eval(options.selectedItem);				
971				if ($selectedItem && $selectedItem.id === item.id) {
972					var $selectedItemModel = $parse(options.selectedItem);
973					$selectedItemModel.assign($scope, undefined);
974				}
975				
976				if ($scopedList[index] && $scopedList[index].hasOwnProperty('sequence')) {
977					$scopedList[index].sequence = item.sequence;
978					resequenceModel($scopedList, index, false);
979				}
980				
981			}
982		}
983		
984		var deferred = $q.defer();
985 		deferred.promise.then(
986 			function(item) {
987 				
988 				var copyDialogController = function ($http, $q, $scope, $mdDialog, $mdToast, item, submitCallback, cancelCallback, parentScope) { 
989 					$scope.item = angular.copy(item);	
990 					$scope.identification = identification;
991 					
992 			    	$scope.cancel = function() {
993 			    		if (cancelCallback) {
994 			    			$q.when(cancelCallback(item)).then(function(item) { $mdDialog.cancel(); }, function(item) { /* do nothing - stay dialog opened */ });
995 				    	} else {
996 				    		$mdDialog.cancel();
997 				    	}
998 					};
999 			    		
1000 					$scope.submit = function(item) {
1001 						
1002 						var ddeferred = $q.defer();
1003 						
1004 						ddeferred.promise.then(
1005				 			function(item) {
1006				 				// copy success or only dialog
1007				 				if (submitCallback) { 
1008		 			    	    	$q.when(submitCallback(item)).then( 
1009		 				    			function(item) { // submit callback resolved
1010		 				    				$scope.dialogProgress = null;
1011		 				    				$mdDialog.hide(item);
1012		 				    				
1013		 				    				$controllerScope[domains + 'Pagination'].numberOfElements = $controllerScope[domains + 'Pagination'].numberOfElements +1;
1014	 					 					$controllerScope[domains + 'Pagination'].totalElements = $controllerScope[domains + 'Pagination'].totalElements +1;
1015		 				    				
1016		 				    			}, 
1017		 				    			function(response) { // submit callback reject
1018		 					    			$scope.dialogProgress = null; 
1019		 				    			});
1020		 			    		} else {
1021		 			    			$scope.dialogProgress = null;
1022		 			    			$mdDialog.hide(item);
1023		 			    		}
1024				 				
1025				 			},
1026				 			function(item) {
1027				 				// copy failed
1028				 				$scope.dialogProgress = null; 
1029				 			}
1030				 		);
1031 						
1032 						
1033 						$scope.dialogProgress = true;
1034 						ttDataAPI.copy(domains, item, options.submitParams).then(
1035 							function(item) {
1036			    				// copy success
1037		    					$mdToast.show( $mdToast.simple().action('OK').highlightAction(true).textContent('successfuly processed').position('top right').hideDelay(3000) ); //.theme("success-toast")
1038 								ddeferred.resolve(item);
1039 							},
1040 							function(response) { 
1041 								// copy failed
1042				    			$mdToast.show( $mdToast.simple().action('Confirm').highlightAction(true).textContent(response.data.message).position('top right').hideDelay(10000) ); //.theme("error-toast")
1043				    			ddeferred.reject(item);
1044 							}
1045 						);
1046 			    		
1047 			    		return ddeferred.promise;
1048 			    	}
1049 			    		
1050 			    } 
1051 			
1052 				$mdDialog.show({    	
1053	 		        controller: copyDialogController,    	
1054	 				templateUrl: '/dialog/_dialog-copy',
1055	 		        parent: angular.element(document.body),
1056	 		        targetEvent: ev,
1057	 		        fullscreen: true,
1058	 		        multiple: true,
1059	 		        locals: {
1060	 		        	item: item,
1061	 		        	parentScope: $scope,
1062	 		        	submitCallback: submitCallback,
1063	 		        	cancelCallback: cancelCallback,
1064	 		        },
1065	 		        clickOutsideToClose: true,
1066	 		        escapeToClose: true,
1067	 		        onComplete: function(scope, element) {
1068	 		        	element.draggable({ handle: 'md-toolbar', cursor: "move" });
1069	 		        }
1070 				})
1071	 		    .finally(function() {
1072			        closeCallback();
1073			    });
1074 				
1075 			}, 
1076 			function(reason) { /* TODO 'toast' entity item for copy not exist */ }
1077 		);
1078		
1079 		if (!item) {
1080 			deferred.reject(item);
1081		} else {
1082			deferred.resolve(item);
1083		}
1084 		
1085 		return deferred.promise;
1086	}
1087
1088	function childrenListDialog(domains, $scope, options) {
1089		
1090		var $controllerScope = $scope;
1091		
1092		var ev				= options.ev;
1093		var index 			= options.index;
1094		var item 			= options.item;
1095		var submitCallback 	= options.submitCB;
1096		var cancelCallback 	= options.cancelCB;
1097		var closeCallback  	= options.closeCB;
1098		var method			= options.method;
1099		
1100		var dialogTemplate  = options.dialogTemplate;
1101			
1102		if (!submitCallback) {
1103			submitCallback = function(savedList) {
1104						    		
1105	    		if (options.onSuccess) {
1106	    			options.onSuccess(savedList);
1107	    		}
1108
1109			}
1110		}
1111		
1112		var deferred = $q.defer();
1113 		deferred.promise.then(
1114 			function(item) {
1115 				
1116 				var childrenListDialogController = function ($http, $q, $scope, $mdDialog, $mdToast, item, submitCallback, cancelCallback, parentScope) { 
1117 					$scope.item = angular.copy(item);	
1118 					$scope.parentScope = parentScope;
1119 					
1120 					$scope.resequenceList = function(list) {	
1121				    	var i = 1;
1122						angular.forEach(list, function(item, key) {					
1123							item.sequence = i;
1124							i++;
1125						});
1126 					}
1127 					
1128 					$scope.sequenceableOptions = {
1129 						handle: '.drag-handle',	
1130 						disabled: false,
1131 						axis: 'y',
1132 					    stop: function(e, ui) {
1133 					    	if (ui.item.sortable.dropindex >= 0) { 		
1134 						    	$scope.resequenceList(ui.item.sortable.sourceModel);
1135 					    	}
1136 					    }
1137 					}
1138 					
1139 			    	$scope.cancel = function() {
1140 			    		if (cancelCallback) {
1141 			    			$q.when(cancelCallback(item)).then(function(item) { $mdDialog.cancel(); }, function(item) { /* do nothing - stay dialog opened */ });
1142 				    	} else {
1143 				    		$mdDialog.cancel();
1144 				    	}
1145 					};
1146 			    		
1147 					$scope.submit = function(item) {
1148 						
1149 						var ddeferred = $q.defer();
1150 						
1151 						ddeferred.promise.then(
1152				 			function(item) {
1153				 				// success or only dialog
1154				 				if (submitCallback) { 
1155		 			    	    	$q.when(submitCallback(item)).then( 
1156		 				    			function(item) { // submit callback resolved
1157		 				    				$scope.dialogProgress = null;
1158		 				    				$mdDialog.hide(item);	 				    				
1159		 				    			}, 
1160		 				    			function(response) { // submit callback reject
1161		 					    			$scope.dialogProgress = null; 
1162		 				    			});
1163		 			    		} else {
1164		 			    			$scope.dialogProgress = null;
1165		 			    			$mdDialog.hide(item);
1166		 			    		}
1167				 				
1168				 			},
1169				 			function(item) {
1170				 				// failed
1171				 				$scope.dialogProgress = null; 
1172				 			}
1173				 		);
1174 						
1175 						
1176 						$scope.dialogProgress = true;
1177 						
1178 						ttDataAPI.save(domains + '/list', item).then(
1179 							function(sitem) {
1180			    				// save list success
1181 								
1182// 								console.log(item.list);
1183// 								console.log(sitem);
1184 								
1185 								files = {};
1186 								
1187		    					$mdToast.show( $mdToast.simple().action('OK').highlightAction(true).textContent('successfuly processed').position('top right').hideDelay(3000) ); //.theme("success-toast")
1188 								ddeferred.resolve(sitem);
1189 							},
1190 							function(response) { 
1191 								// sve list failed
1192				    			$mdToast.show( $mdToast.simple().action('Confirm').highlightAction(true).textContent(response.data.message).position('top right').hideDelay(10000) ); //.theme("error-toast")
1193				    			ddeferred.reject(item);
1194 							}
1195 						);
1196 			    		
1197 			    		return ddeferred.promise;
1198 			    	}
1199 					
1200 					$scope.add = function($event, child, list) {
1201 						var submitCB = function(child) {
1202 							child.sequence = list.length + 1;
1203 							list.push(child);
1204 						}
1205 						editDialog(domains, $scope, { ev: $event, index: -1, item: child, submitCB: submitCB, noClearFiles: true });
1206 					}
1207 					
1208 					$scope.edit = function($event, $index, child, list) {
1209 						var submitCB = function(child) {
1210 							list[$index] = child;
1211 						}
1212 						editDialog(domains, $scope, { ev: $event, index: $index, item: child, submitCB: submitCB, noClearFiles: true });
1213 					}
1214 					
1215 					$scope.remove = function($event, $index, child, list) {
1216 						removeDialog(domains, $scope, { doDelete: true, identification: item.id, ev: $event, index: $index, item: child, simpleList: list });
1217 					}
1218 			    		
1219 			    } 
1220 			
1221 				$mdDialog.show({    	
1222	 		        controller: childrenListDialogController,    	
1223	 				templateUrl: '/dialog' + dialogTemplate,
1224	 		        parent: angular.element(document.body),
1225	 		        targetEvent: ev,
1226	 		        fullscreen: true,
1227	 		        multiple: true,
1228	 		        locals: {
1229	 		        	item: item,
1230	 		        	parentScope: $scope,
1231	 		        	submitCallback: submitCallback,
1232	 		        	cancelCallback: cancelCallback,
1233	 		        },
1234	 		        clickOutsideToClose: true,
1235	 		        escapeToClose: true,
1236	 		        onComplete: function(scope, element) {
1237	 		        	element.draggable({ handle: 'md-toolbar', cursor: "move" });
1238	 		        }
1239 				})
1240	 		    .finally(function() {
1241			        closeCallback();
1242			    });
1243 				
1244 			}, 
1245 			function(reason) { /* TODO 'toast' entity item for copy not exist */ }
1246 		);
1247		
1248 		if (!item) {
1249 			deferred.reject(item);
1250		} else {
1251			deferred.resolve(item);
1252		}
1253 		
1254 		return deferred.promise;
1255	}	
1256	
1257}
1258
1259ttData.directive('ttDataUnique', ttDataUniqueDirective);
1260function ttDataUniqueDirective($http, $q, $timeout, $parse) {
1261	return {
1262		restrict: 'A',
1263		require: 'ngModel',
1264		scope: { 
1265        	ttDataValue : '='
1266        },
1267		link: function(scope, element, attr, ngModel) {
1268						
1269			var serverAddr = attr.ttDataUnique;	// 'tt-data-unique' attribute
1270			var itemField = attr.ttDataField; // 'tt-data-field' attribute
1271			var itemValue = attr.ttDataValue; // 'tt-data-field' attribute
1272			
1273			ngModel.$asyncValidators.uniqueValue = function(modelValue, viewValue) {
1274				var deferred = $q.defer();
1275				
1276				var firstField = itemField.split(",")[0];
1277				
1278				var getter = $parse(firstField);
1279				getter.assign(scope.ttDataValue, viewValue);
1280				
1281				if (viewValue) {					
1282
1283					$http({
1284				      url: serverAddr,
1285				      method: 'POST',
1286					  headers: { 'Content-Type': undefined },
1287					  transformRequest: function (data) {                
1288						var formData = new FormData();
1289						formData.append("fields", data.fields);
1290						formData.append("value", angular.toJson(data.value));
1291						return formData;
1292					  },
1293					  data: { fields : itemField, value: scope.ttDataValue } 
1294					}).then(
1295			          function(response) {
1296			        	  if (response.data) { // = exists = not unique
1297			        		  deferred.reject();
1298			        	  } else {
1299			        		  deferred.resolve();
1300			        	  }
1301			          },
1302			          function(response) {
1303			        	  deferred.reject();
1304			          });
1305				} else {
1306					deferred.resolve();
1307				}
1308
1309		          
1310		        return deferred.promise;
1311		    }
1312		
1313		}
1314	}
1315}
1316
1317ttData.directive('ttDataExists', ttDataExistsDirective);
1318function ttDataExistsDirective($http, $q, $timeout, $parse) {
1319	return {
1320		restrict: 'A',
1321		require: 'ngModel',
1322		scope: { 
1323        	ttDataValue : '=',
1324        },
1325		link: function(scope, element, attr, ngModel) {
1326			
1327			// var errorExists = ngModel.$error.existsValue;
1328			 
1329			var serverAddr = attr.ttDataExists;	// 'tt-data-unique' attribute
1330			var itemField = attr.ttDataField; // 'tt-data-field' attribute
1331			var itemValue = attr.ttDataValue; // 'tt-data-field' attribute
1332			
1333			ngModel.$asyncValidators.existsValue = function(modelValue, viewValue) {
1334				var deferred = $q.defer();
1335				
1336				var firstField = itemField.split(",")[0];
1337				
1338				var getter = $parse(firstField);
1339				getter.assign(scope.ttDataValue, viewValue);
1340				
1341				if (viewValue) {					
1342
1343					$http({
1344				      url: serverAddr,
1345				      method: 'POST',
1346					  headers: { 'Content-Type': undefined },
1347					  transformRequest: function (data) {                
1348						var formData = new FormData();
1349						formData.append("fields", data.fields);
1350						formData.append("value", angular.toJson(data.value));
1351						return formData;
1352					  },
1353					  data: { fields : itemField, value: scope.ttDataValue } 
1354					}).then(
1355			          function(response) {
1356			        	  if (!response.data) { // = exists = not unique
1357			        		  deferred.reject();
1358			        	  } else {
1359			        		  deferred.resolve();
1360			        	  }
1361			          },
1362			          function(response) {
1363			        	  deferred.reject();
1364			          });
1365				} else {
1366					deferred.resolve();
1367				}
1368
1369		          
1370		        return deferred.promise;
1371		    }
1372
1373			
1374		}
1375	}
1376}
1377
1378ttData.directive('ttNotEmptyArray', function() {
1379	  return {
1380	    require: 'ngModel',
1381	    link: function(scope, element, attrs, ngModel) {
1382
1383	      scope.$watch(function () { return ngModel.$modelValue && ngModel.$modelValue.length; }, function() {
1384	        ngModel.$validate(); // validate again when array changes	        
1385	      });
1386	      
1387	      ngModel.$validators.emptyArray = function(modelValue, viewValue) {
1388//	    	  if(!modelValue) { return false; }
1389		      return !modelValue || modelValue.length > 0;
1390	      }
1391
1392	    }
1393	  };
1394});
1395
1396//ttData.directive('ttInfiniteScroll', function(ttDataAPI, $parse, $timeout) {
1397//    
1398//	return {
1399//		restrict: 'A',
1400//		scope: {
1401//			pagination: "=ttPagination",
1402//			ttInfiniteScroll: "="
1403//	    },
1404//		link: function($scope, element, attr, ngModel) {
1405//			var rawElement = element[0];
1406//	        
1407//	        element.bind('scroll', function() {
1408//	        	
1409//	            if (!$scope.loading && !$scope.pagination.last && rawElement.scrollTop + rawElement.offsetHeight >= rawElement.scrollHeight - (attr.ttOffset ? parseInt(attr.ttOffset) : 0)) {
1410//	            	
1411//	            	$scope.loading = true;
1412//	            	
1413//	            	if (!attr.ttApiUrl) {
1414//	            	
1415//		            	ttDataAPI.getAllPageable(attr.ttInfiniteScroll, { pagination: { offset: $scope.pagination.number + 1, limit: $scope.pagination.size }}, $scope).then(function(data) {
1416//		    				
1417//		    				$scope.pagination = $scope.$eval(attr.ttInfiniteScroll + 'Pagination');	    				
1418//		    				[].push.apply($scope.ttInfiniteScroll, data);
1419//		    				
1420//		    				$scope.loading = undefined;
1421//		    				
1422//		    			}, function(response) { $scope.loading = undefined; /* no data */ });
1423//		            	
1424//	            	} else {
1425//	            		
1426//		            	ttDataAPI.getDataPageable('/api' + attr.ttApiUrl, attr.ttInfiniteScroll, { pagination: { offset: $scope.pagination.number + 1, limit: $scope.pagination.size }}, $scope).then(function(data) {
1427//		            		
1428//		            		
1429////		            		var $pagination = $parse(attr.ttInfiniteScroll + 'Pagination');
1430////		    				$pagination.assign($scope.$parent, pagination);
1431//		            		
1432//		    				$scope.pagination = $scope.$eval(attr.ttInfiniteScroll + 'Pagination');	    				
1433//		    				[].push.apply($scope.ttInfiniteScroll, data);
1434//		    				
1435//		    				$scope.loading = undefined;
1436//
1437//		    				$scope.apply();
1438//		    				
1439//		    				
1440//		    			}, function(response) { $scope.loading = undefined; /* no data */ });
1441//		            	
1442//	            	}
1443//
1444//	            }
1445//	        });
1446//		}
1447//	}
1448//	
1449//});
1450
1451//ttData.directive('ttInfiniteScroll', function(ttDataAPI, $parse, $timeout) {
1452//    
1453//	return {
1454//		restrict: 'A',
1455//	    scope: false,
1456//		link: function($scope, $element, attr) {
1457//			
1458//			var $ppscope = $scope.$parent;
1459//			
1460//			$scope.$on('new-pagination', function(event, args) {		
1461//				if (args.name == (attr.ttInfiniteScroll + 'Pagination')) {
1462//					$ppscope[attr.ttInfiniteScroll + 'Pagination'] = args.data;	
1463//					$ppscope[attr.ttInfiniteScroll + 'PaginationParams'] = args.params;
1464//				}
1465//			});
1466//			
1467//			var rawElement = $element[0];
1468//	        $element.bind('scroll', function() {
1469//	        	
1470//				var $pagination 		= $ppscope[attr.ttInfiniteScroll + 'Pagination'];	
1471//				var $paginationParams 	= $ppscope[attr.ttInfiniteScroll + 'PaginationParams'];
1472//				
1473//	            if (!$ppscope.loading && !$pagination.last && rawElement.scrollTop + rawElement.offsetHeight >= rawElement.scrollHeight - (attr.ttOffset ? parseInt(attr.ttOffset) : 0)) {
1474//	            		            	
1475//	            	$paginationParams.pagination.offset = $pagination.number + 1;
1476//	            	
1477//	            	$ppscope.loading = true;	            	
1478//	            	if (!attr.ttApiUrl) {
1479//	            	
1480//		            	ttDataAPI.getAllPageable(attr.ttInfiniteScroll, $paginationParams, $ppscope).then(function(data) {
1481//		            		var $list = $ppscope[attr.ttInfiniteScroll];  			
1482//		    				[].push.apply($list, data);
1483//		    				$ppscope.loading = undefined;
1484//		    			}, function(response) { $ppscope.loading = undefined; /* no data */ });
1485//		            	
1486//	            	} else {
1487//	            		
1488//		            	ttDataAPI.getDataPageable('/api' + attr.ttApiUrl, attr.ttInfiniteScroll, $paginationParams, $ppscope).then(function(data) {		            				    				
1489//		            		var $list = $ppscope[attr.ttInfiniteScroll];
1490//		            		[].push.apply($list, data);
1491//		    				$ppscope.loading = undefined;		    				
1492//		    			}, function(response) { $ppscope.loading = undefined; /* no data */ });
1493//		            	
1494//	            	}
1495//
1496//	            }
1497//	        });
1498//		}
1499//	}
1500//	
1501//});
1502
1503ttData.directive('ttInfiniteScroll', function(ttDataAPI, $parse, $timeout) {
1504    
1505	return {
1506		restrict: 'A',
1507	    scope: {
1508	    	datalist: '=ttInfiniteScroll',
1509	    	loading: '=?ttLoading'	
1510	    },
1511		link: function(scope, $element, attr) {
1512			
1513			// var scope = $scope.$parent;
1514			
1515			var $pagination 	  = undefined;	
1516			var $paginationParams = undefined;			
1517			
1518			var firstLoad = false;
1519			
1520			scope.$on('new-pagination', function(event, args) {		
1521				if (args.name == (attr.ttInfiniteScroll + 'Pagination')) {
1522					scope[attr.ttInfiniteScroll + 'Pagination'] = args.data;	
1523					scope[attr.ttInfiniteScroll + 'PaginationParams'] = args.params;
1524
1525					$pagination 		= scope[attr.ttInfiniteScroll + 'Pagination'];	
1526					$paginationParams 	= scope[attr.ttInfiniteScroll + 'PaginationParams'];
1527					
1528					if (!firstLoad) {
1529						firstLoad = true;
1530						
1531						var doNext = true;
1532						
1533						var loadNext = function() {
1534							var images = $element.find('img');
1535					        var imagesCount = images.length;	
1536					        
1537					        // console.log(imagesCount);
1538					        
1539						    images.on('load', function() { 
1540						        if ( ! --imagesCount) {
1541						            // console.log('render done');
1542						            if (element.scrollHeight <= element.offsetHeight && !args.data.last) {
1543						            	// console.log('can not scroll');
1544						            	
1545						            	// var $pagination 		= scope[attr.ttInfiniteScroll + 'Pagination'];	
1546										// var $paginationParams 	= scope[attr.ttInfiniteScroll + 'PaginationParams'];
1547										
1548										$paginationParams.pagination.offset = $pagination.number + 1;
1549										
1550						            	scope.loading = true;                 	
1551						            	if (!attr.ttApiUrl) {
1552						            	
1553							            	ttDataAPI.getAllPageable(attr.ttInfiniteScroll, $paginationParams, scope).then(function(data) { 
1554							            		// var $list = scope[attr.ttInfiniteScroll];  			
1555							    				[].push.apply(scope.datalist, data);
1556							    				scope.loading = false;
1557							    			}, function(response) { scope.loading = false;
1557 /* no data */ });
1558							            	
1559						            	} else {
1560						            		
1561							            	ttDataAPI.getDataPageable('/api' + attr.ttApiUrl, attr.ttInfiniteScroll, $paginationParams, scope).then(function(data) {		            				    				
1562							            		// var $list = scope[attr.ttInfiniteScroll];
1563							            		[].push.apply(scope.datalist, data);
1564							    				scope.loading = false;		    				
1565							    			}, function(response) { scope.loading = false; /* no data */ });
1566							            	
1567						            	}
1568						            	
1569						            	// loadNext();
1570						            	
1571						            } 
1572						        }
1573						    });
1574						}
1575						
1576						var element = $element[0];
1577					    $timeout(function() {
1578					    	
1579					    	loadNext();
1580						    
1581					    });
1582					    
1583						
1584
1585					}
1586					
1587				}
1588			});
1589			
1590			var checkscroll = true;
1591			var offset = (attr.ttOffset ? parseInt(attr.ttOffset) : 0);
1592			var rawElement = $element[0];
1593	        $element.bind('scroll', function() {
1594	        	
1595	        	var onEnd = ((rawElement.scrollTop + rawElement.offsetHeight) >= (rawElement.scrollHeight - offset));
1596//	        	console.log(onEnd, rawElement.scrollTop);
1597	        	
1598				var $pagination 		= scope[attr.ttInfiniteScroll + 'Pagination'];	
1599				var $paginationParams 	= scope[attr.ttInfiniteScroll + 'PaginationParams'];
1600//				console.log($pagination, $paginationParams);
1601				
1602	            if (checkscroll && !scope.loading && $pagination && !$pagination.last && onEnd) {
1603	            	
1604	            	// console.log('do next work', $paginationParams);
1605	            	
1606	            	scope.loading = true; 
1607	            	checkscroll = false;
1608	            	
1609	            	$paginationParams.pagination.offset = $pagination.number + 1;        
1610	            	
1611	            	if (!attr.ttApiUrl) {
1612	            		
1613		            	ttDataAPI.getAllPageable(attr.ttInfiniteScroll, $paginationParams, scope).then(function(data) { 
1614		            		// var $list = scope[attr.ttInfiniteScroll]; 
1615		    				[].push.apply(scope.datalist, data);
1616		    				scope.loading = false;
1617		    				checkscroll = true;
1618		    			}, function(response) { scope.loading = false; checkscroll = true; /* no data */ });
1619		            	
1620	            	} else {
1621	            		
1622		            	ttDataAPI.getDataPageable('/api' + attr.ttApiUrl, attr.ttInfiniteScroll, $paginationParams, scope).then(function(data) {		            				    				
1623		            		// var $list = scope[attr.ttInfiniteScroll];
1624		            		[].push.apply(scope.datalist, data);
1625		    				scope.loading = false;		
1626		    				checkscroll = true;
1627		    			}, function(response) { scope.loading = false; checkscroll = true; /* no data */ });
1628		            	
1629	            	}
1630
1631	            }
1632	        });
1633		}
1634	}
1635	
1636});
1637
1638//ttData.directive('ttListPagination', function(){
1639//    return {
1640//        restrict: 'E',
1641//        transclude: true,
1642//        replace: true,
1643//        scope: { 
1644//        	pagination : '=pagination'
1645//        },
1646//        template: 
1647//        	'<md-toolbar layout="row" class="md-primary md-hue-1">' +
1648//			'  <div class="md-toolbar-tools">' +
1649//        	"    <div ng-if=\"pagination\"><small md-truncate class=\"light\">{{pagination.size * pagination.number  + pagination.numberOfElements}} items / {{pagination.totalElements}} total</small></div>" + 
1650//        	'  </div>' +
1651//        	'</md-toolbar>',
1652//        link: function(scope, element, attrs){        	
1653//        	//        	
1654//	    }
1655//    }  
1656//});
1657
1658ttData.directive('ttListPagination', function(){
1659    return {
1660        restrict: 'E',
1661        transclude: true,
1662        replace: true,
1663        scope: false,
1664        template: 
1665        	'<md-toolbar layout="row" class="md-primary md-hue-1" style="min-height: auto;">' +
1666			'  <div class="md-toolbar-tools" style="height: 40px;">' +
1667        	"    <div ng-if=\"pagination\"><small md-truncate class=\"light\">{{pagination.size * pagination.number  + pagination.numberOfElements}} items / {{pagination.totalElements}} total</small></div>" + 
1668        	'  </div>' +
1669        	'</md-toolbar>',
1670        link: function(scope, element, attrs){        	
1671        	
1672        	element.hide();
1673        	scope.$on('new-pagination', function(event, args) {		
1674				if (args.name == (attrs.pagination)) {
1675					scope.pagination = args.data;
1676					element.slideDown();
1677				}
1678			});
1679        	
1680	    }
1681    }  
1682});
1683
1684ttData.directive('ttListSearch', function(){
1685    return {
1686        restrict: 'EA',
1687        scope: {
1688        	searchEnabled : '=enabled',
1689        	searchTerm : '=term'	
1690        },
1691        templateUrl: '/template/_list-header',
1692        link: function(scope, element, attrs){
1693        	scope.searchTerm = {};
1694	    }
1695    }  
1696});
1697
1698ttData.directive('date', function (dateFilter) {
1699    return {
1700        require:'ngModel',
1701        link:function (scope, elm, attrs, ctrl) {
1702
1703            var dateFormat = attrs['date'] || 'yyyy-MM-dd';
1704           
1705            ctrl.$formatters.unshift(function (modelValue) {
1706                return dateFilter(modelValue, dateFormat);
1707            });
1708        }
1709    };
1710});
1711
1712ttData.directive('chooseFile', function($parse) {
1713    return {
1714    	restrict: 'E',
1715    	// scope: true,
1716    	scope: {
1717	      bind: "=",
1718	      name: "=",
1719	      filepreview: "@"
1720	    },
1721    	link: function (scope, elem, attrs) {
1722          var button = elem.find('input.file-name');
1723          var input  = elem.find('input.file-input');
1724          var clear  = elem.find('.md-choose-file-clear');
1725
1726          button.bind('click', function() {
1727        	  input[0].click();
1728          });
1729
1730          input.bind('change', function(e) {
1731              scope.$apply(function() {
1732            	
1733	              // var model = $parse(attrs.bind + ".name");
1734	              var files = e.target.files;
1735	              if (files[0]) {            	  
1736	            	  scope.$emit("file-selected", { file: files[0], bind: (attrs.name ? scope.name : attrs.bind.replace('$index', attrs.index)) });    
1737	            	  // model.assign(scope.$parent, files[0].name);
1738	            	  
1739	            	  if (!scope.bind) {
1740	            		  scope.bind = {};
1741	            	  }
1742	            	  
1743	            	  scope.bind.name = files[0].name;
1744	            	  
1745	            	  var reader = new FileReader();
1746	                  reader.onload = function(loadEvent) {
1747	                    scope.$apply(function() {
1748	                    	// if (scope.filepreview != undefined) {
1749	                    	
1750//	                    	scope.$parent[scope.filepreview] = 'aa';
1751//	                    	console.log(loadEvent.target.result);
1752	                    	
1753	                    	scope.$parent[scope.filepreview] = loadEvent.target.result;
1754//	                    	console.log('after');
1755	                    	
1756	                    	// }
1757	                    });
1758	                  }
1759	                  reader.readAsDataURL(files[0]);
1760	            	  
1761	              } else {
1762	            	  model.assign(scope.$parent, null);  
1763	              }
1764              });
1765          });
1766          
1767          scope.$parent.clearFile = function(file) {
1768//        	  file.name = null;
1769
1770//        	  var modelName = $parse(attrs.bind + ".name");
1771//        	  modelName.assign(scope.$parent, null);
1772//        	  
1773//        	  var modelUri = $parse(attrs.bind + ".uri");
1774//        	  modelUri.assign(scope.$parent, null);
1775        	  
1776        	  scope.bind.name = null;
1777        	  scope.bind.uri = null;
1778        	  
1779        	  // scope.$parent.filepreview = null;
1780        	  scope.$parent[scope.filepreview] = null;
1781        	  
1782        	  // console.log(scope.bind);
1783          }
1784          
1785          if (clear.length) {
1786        	  clear.bind('click', function() {
1787        		  scope.bind.name = null;
1788            	  scope.bind.uri = null;
1789            	  
1790            	  scope.$parent[scope.filepreview] = null;
1791              });
1792          }
1793          
1794    	}
1795    };
1796});
1797
1798ttData.directive('chooseIcon', function($parse, $http, $q, $mdDialog) {
1799    return {
1800    	scope: { icon: '=bind' },
1801    	link: function (scope, elem, attrs) {
1802          var button = elem.find('input.icon-input');
1803
1804          button.bind('click', function(ev) {
1805        	    $http({
1806		            method: 'GET',
1807		            url: '/icons/material'
1808				}).then(function(response){ 
1809					var icons = response.data;	
1810					
1811					var iconController = function ($q, $scope, $mdDialog, item, icons, successCallback, errorCallback, parentScope) {						
1812						$scope.item = item;
1813						$scope.icons = icons;
1814						$scope.parentScope = parentScope;
1815						$scope.successCallback = successCallback;
1816				    	$scope.errorCallback = errorCallback;
1817				    	
1818				    	$scope.cancel = function() {
1819				        	if ($scope.errorCallback) {
1820					        	$q.when($scope.errorCallback(item)).then(function(item) { $mdDialog.cancel(); }, function(item) {});
1821				        	} else {
1822				        		$mdDialog.cancel();
1823				        	}
1824				    	};
1825				    	$scope.submit = function(item) {
1826				    		if ($scope.successCallback) {
1827				    			$scope.dialogProgress = true;
1828					    		$q.when($scope.successCallback(item)).then(function(item) { $mdDialog.hide(item); $scope.dialogProgress = null; }, function(response) { $scope.dialogProgress = null; });
1829				    		} else {
1830				    			$mdDialog.hide(item);
1831				    		}
1832				    	};
1833					}
1834					
1835					var iconitem = { icon : scope.icon }
1836					
1837					var successCB = function(item) {
1838						scope.icon = item.icon;
1839					}
1840					
1841					$mdDialog.show({    	
1842				        controller: iconController,    	
1843						templateUrl: '/dialog/_dialog-icons',
1844				        parent: angular.element(document.body),
1845				        theme: 'adminTheme',
1846				        fullscreen: true,
1847				        multiple: true,
1848				        locals: {
1849				        	item: iconitem,
1850				        	icons: icons,
1851				        	parentScope: scope,
1852				        	successCallback: successCB,
1853				        	errorCallback: null
1854				        },
1855				        clickOutsideToClose: true,
1856				        escapeToClose: true,
1857				        onComplete: function(scope, element) {
1858				        	element.draggable({ handle: 'md-toolbar', cursor: "move" });
1859				        }
1860				    });
1861					
1862				}, function(response){ 
1863				});
1864          });
1865
1866    	}
1867    };
1868});
1869    
1870app.directive('updateListener', function($rootScope) {
1871	return {
1872	    restrict: 'A',
1873	    scope: { 
1874	    	     item:'=', 
1875	    	     list:'=' 
1876	    },
1877	    link: function($scope, element, attrs) {
1878	    	$scope.$on('update-item', function(event, args) {	
1879        		if (args.item && $scope.item && $scope.item.id == args.item.id) {
1880        			$scope.item = args.item;
1881        			if ($scope.list) {
1882        				var i = 0;
1883						angular.forEach($scope.list, function(itemList, key) {
1884							if (itemList.id == args.item.id) {
1885								$scope.list[i] = args.item;
1886							}
1887							i++;
1888						});
1889        			}
1890        		}
1891        	});
1892	    }
1893	}
1894});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.