').html(e[key]).text();
if($scope.filter.filters[key] && $scope.filter.filters[key][value] && !$scope.filter.filters[key][value].checked && $scope.filter.filters[key][value].show) {
$scope.filter[key] = $scope.filter[key] ?? {};
$scope.filter[key]['is'] = true;
}
if ($scope.filter.filters[key] && $scope.filter.filters[key][value] && $scope.filter.filters[key][value].checked !== true) {
ret = false;
}
if (searchText && value && value.toString().toLowerCase().includes(searchText)) {
foundInSearch = true;
}
});
return ret && foundInSearch;
});
$scope.tmp.filtered = angular.copy(ret);
$scope.tmp.total = ret.length + 1;
if ($scope.data.pagination) {
$scope.page.change_limit();
ret = ret.slice($scope.page.from, $scope.page.from + $scope.page.limit);
}
$scope.tmp._cache.result = ret;
$scope.tmp._cache.inputHash = inputHash;
console.log("end");
return $scope.tmp._cache.result;
}
};
$scope.data.tmp = $scope.tmp;
$scope.filter = { show: {} ,search: '', filters: {} };
$scope.data.check = {
checked : { data : [], ids : []},
check:(i)=>{
alert(i);
$scope.tmp.data[i].checked = !($scope.tmp.data[i].checked);
$scope.data.check.reload();
},
reload:()=>{
$scope.data.check.checked = [];
$scope.data.check.ids = [];
angular.forEach($scope.data.tmp_data,(e)=>{
if(e.checked) {
$scope.data.check.checked.push(e);
$scope.data.check.ids.push(e.data.id);
}
})
}
}
initializeTable();
setupFiltering();
setupCheckFunctions();
setupResizer();
setupPagination();
$scope.isOverflown = ()=> {
let element = $element[0].querySelector(".tbody");
return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
}
function initializeTable() {
Object.entries($scope.data.items).forEach(([key, item]) => {
setupTableItems(item, key);
processTableData(key);
});
$scope.total = $scope.tmp.data.length + 1;
}
function setupTableItems(item, key) {
let tableItem = typeof item === "string" ? { title: item, show: true } : item;
$scope.tmp.items[key] = tableItem;
}
function processTableData(key) {
$scope.data.data.forEach((row, index) => {
if (!$scope.tmp.data[index]) $scope.tmp.data[index] = {};
let val = extractValue(row, key);
val = val || '';
$scope.tmp.data[index][key] = angular.copy(val);
$scope.tmp.data[index].index = angular.copy(index);
$scope.tmp.data[index].hidden = false;
$scope.tmp.data[index].style = row.style || '';
$scope.tmp.data[index].class = row.class || '';
if($scope.data.href) $scope.tmp.data[index].href =$scope.data.href.replace(/(?<={)(.*?)(?=})/g,(e)=>{ return $scope.data.data[index][e] }).replaceAll('{','').replaceAll('}','')
//setupUniqueValues(key, val);
});
}
function extractValue(row, key) {
let val = '';
key.split('+').forEach((k) => {
let keys = k.split('.');
let tempVal = row;
for (let keyPart of keys) {
if (tempVal[keyPart] !== undefined) {
tempVal = tempVal[keyPart];
} else {
tempVal = '';
break;
}
}
val = val ? val + ' ' + tempVal : tempVal;
});
return val;
}
function get_unics(key) {
let unics = {};
$scope.tmp.filtered.forEach((e) => {
let text = $('
').html(e[key]).text();
unics[text] = unics[text] ?? { text: text, count: 0 };
unics[text].count++;
});
return Object.values(unics);
}
function setupFiltering() {
$scope.filter.changeText = (k) => {
Object.keys($scope.filter.filters[k]).forEach((key) => {
$scope.filter.filters[k][key].checked = key.toString().includes($scope.filter[k].text);
$scope.filter.filters[k][key].show = key.toString().includes($scope.filter[k].text);
});
};
$scope.filter.showOnlyVisible = function(item, i,arr,k){
return $scope.filter.filters[ $scope.filter.show][item.text].show;
}
$scope.filter.showing = (k,event)=>{
if($scope.filter.show==k){
$scope.filter.show = false;
}
else {
if(k){
$scope.filter.filters[k] = $scope.filter.filters[k] ?? {};
$scope.filter.filters[k].unics = get_unics(k);
$scope.filter.filters[k].unics.forEach((v) => {
$scope.filter.filters[k] = $scope.filter.filters[k] ?? {};
$scope.filter.filters[k][v.text] = $scope.filter.filters[k][v.text] ?? {checked:true,show:true};
});
}
$scope.filter.show = k;
setTimeout(() => {
$scope.filter.element = event.currentTarget.parentElement;
document.addEventListener("click", closeFilterOnClickOutside);
});
}
};
$scope.filter.remove = (k) => {
$scope.filter[k] = {};
$scope.filter.filters[k] = {};
$scope.filter.show = false;
};
const closeFilterOnClickOutside = (event) => {
if ($scope.filter.element && !$scope.filter.element.contains(event.target)) {
$scope.$apply(() => {
$scope.filter.show = false;
});
document.removeEventListener("click", closeFilterOnClickOutside);
}
};
}
function setupCheckFunctions() {
$scope.data.check.check = (i) => {
if (!$scope.data.checkbox) return;
$scope.tmp.data[i].checked = !$scope.tmp.data[i].checked;
reloadCheckedItems();
};
$scope.data.check.check_all = () => {
if (!$scope.data.checkbox) return;
$scope.tmp.data.forEach((e) => { e.checked = $scope.data.check.all; });
reloadCheckedItems();
};
}
function reloadCheckedItems() {
$scope.data.check.checked = [];
$scope.data.check.ids = [];
$scope.tmp.data.forEach((e) => {
if (e.checked) {
$scope.data.check.checked.push($scope.data.data[e.index]);
$scope.data.check.ids.push($scope.data.data[e.index].id);
}
});
}
function setupResizer() {
$scope.resizer = {
down(event, index) {
const element = event.target.parentElement;
const startX = event.clientX;
const startWidth = element.offsetWidth;
document.body.style.cursor = 'col-resize';
document.body.style.userSelect = 'none';
const move = (e) => {
const newWidth = startWidth + (e.clientX - startX);
element.style.width = `${newWidth}px`;
element.style.minWidth = `${newWidth}px`;
element.style.maxWidth = `${newWidth}px`;
};
const up = () => {
document.body.style.removeProperty('cursor');
document.body.style.removeProperty('userSelect');
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', up);
$scope.tmp.items[index].style = `max-width:${element.style.width}; min-width:${element.style.width}; width:${element.style.width}`;
$scope.$apply();
};
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', up);
}
};
}
function setupPagination() {
if ($scope.data.pagination) {
$scope.page = {
from: 0,
current: 1,
limit: Math.floor($element[0].offsetHeight / 36),
change_limit: () => {
$scope.page.total = Math.ceil($scope.tmp.total / $scope.page.limit);
},
go: (c) => {
$scope.page.current = Math.max(c, 1);
$scope.page.from = ($scope.page.current - 1) * $scope.page.limit;
}
};
$scope.page.change_limit();
}
}
let recalcTimer = null;
function scheduleRecalc() {
if (recalcTimer) return;
recalcTimer = setTimeout(() => {
recalcTimer = null;
$scope.$applyAsync(() => {
$scope.tmp.view = $scope.tmp.display(); // display() გადააკეთე რომ PURE იყოს
});
}, 50);
}
$scope.$watch('filter.search', scheduleRecalc);
$scope.$watch('filter.filters', scheduleRecalc, true);
$scope.$watchGroup(['sort.key', 'sort.reverse'], scheduleRecalc);
$scope.$watchGroup(['sort.key', 'sort.reverse'], scheduleRecalc);
if ($scope.data.pagination) {
$scope.$watchGroup(['page.current', 'page.limit'], scheduleRecalc);
}
scheduleRecalc()
}
};
});
RootApp.directive('chart', function () {
return {scope: { data: '=', chart:'=' },
template: '.',
controller: function ($rootScope, $scope, $element,$timeout) {
$timeout(()=>{
$scope.chart.chart = $scope.chart.chart ?? {};
$scope.chart.chart.renderTo=$element[0];
new Highcharts.Chart($scope.chart);
},300)
}
}}); RootApp.run(function (amMoment) {
amMoment.changeLocale('ka');
});
RootApp.directive('ngRightClick', function($parse) {
return function(scope, element, attrs) {
var fn = $parse(attrs.ngRightClick);
element.bind('contextmenu', function(event) {
scope.$apply(function() {
event.preventDefault();
fn(scope, {$event:event});
});
});
};
});
RootApp.directive('multiSelect', function($timeout){
return {
restrict: 'E',
scope: {
options: '=?', // ["ორშაბათი", ...]
ngModel: '=', // "ორშაბათი,პარასკევი" ან ["ორშაბათი","პარასკევი"]
ngDisabled: '=?'
},
template: `
`,
link: function(scope, el){
const $sel = el.find('select');
// Helpers: CSV <-> Array
function toArray(v){
if (Array.isArray(v)) return v;
if (v == null || v === '') return [];
return String(v).split(',').map(s => s.trim()).filter(Boolean);
}
function toCSV(arr){
if (!Array.isArray(arr)) return '';
return arr.join(',');
}
// Init
scope.options = scope.options || [];
scope.localModel = toArray(scope.ngModel);
// local -> ngModel (CSV)
scope.$watch('localModel', function(n, o){
if (n === o) return;
scope.ngModel = toCSV(n);
$timeout(() => $sel.trigger('chosen:updated'));
}, true);
// ngModel (string/array) -> local
scope.$watch('ngModel', function(n, o){
if (n === o) return;
const arr = toArray(n);
// თავიდან დავაფარებთ უსასრულო ციკლს
if (JSON.stringify(arr) !== JSON.stringify(scope.localModel)){
scope.localModel = arr;
$timeout(() => $sel.trigger('chosen:updated'));
}
});
// options ან disabled ცვლილებაზე UI განახლება
scope.$watchCollection('options', function(){
$timeout(() => $sel.trigger('chosen:updated'));
});
scope.$watch('ngDisabled', function(){
$timeout(() => $sel.trigger('chosen:updated'));
});
}
};
});
RootApp.directive('person', function() {
return {
restrict: 'E',
replace: true,
scope: {
item: '=' // ✅ @ იყენებს სტრინგის გადასაცემად
},
controller: function($rootScope, $scope, $element, $http) {
$scope.person = {
loaded: false
};
$scope.load = function() {
if ($scope.item.p_number) {
$http.get($rootScope.server + `/person/pn/${$scope.item.p_number}`)
.then(response => {
$scope.person = response.data;
$scope.item.person_id = $scope.person.id*1;
$scope.person.loaded = true;
})
.catch(error => {
$scope.person = {error:'არ მოიძებნა',loaded : true};
});
}else{
$scope.person = {error:'შეცდომა',loaded : true};
}
};
$scope.load();
},
template: `
იტვირთება
{{person.first_name}} {{person.last_name}}
{{person.error}}
`
};
});
RootApp.directive('fileChange', [function () {
return {
restrict: 'A',
scope: {
fileChange: '&'
},
link: function (scope, element) {
element.on('change', function (event) {
scope.$apply(function () {
scope.fileChange({ $files: event.target.files });
});
});
}
};
}]);
RootApp.directive('carousel', ['$interval', '$timeout', '$window', function($interval, $timeout, $window){
return {
restrict: 'E',
scope: {
items: '=',
width: '@?',
height: '@?',
autoplay: '@?'
},
template:
`
`,
link: function(scope, el){
var track = el[0].querySelector('.carousel_track');
var idx = 0, count = 0, step = 0, autoplayPromise = null;
var startX = 0, deltaX = 0, dragging = false;
function coerceNumber(v, fallback){ var n = parseInt(v,10); return isNaN(n)? fallback : n; }
scope.index = 0;
scope.count = 0;
// helpers for nav visibility
scope.hasPrev = function(){ return idx > 0; };
scope.hasNext = function(){ return idx < (count - 1); };
// ზომები
var w = coerceNumber(scope.width, 0);
var h = coerceNumber(scope.height, 170);
scope.heightPx = h + 'px';
function measure(){
step = el[0].clientWidth || (track ? track.clientWidth : w || 0);
if(step <= 0) step = w || 260;
moveTo(scope.index, false);
}
function moveTo(i, animate){
if(!track) return;
if(i < 0) i = 0;
if(i > count-1) i = count-1;
idx = i; scope.index = i;
track.style.transition = (animate === false) ? 'none' : 'transform .35s ease';
track.style.transform = 'translateX(' + (-i * step) + 'px)';
// განვაახლოთ ღილაკების ხილვადობა pointer მოვლენებიდანაც
scope.$evalAsync(); // უსაფრთხოა, დეჯესტს დაგეგმავს თუ საჭიროია
}
scope.prev = function(){ moveTo(idx-1, true); };
scope.next = function(){ moveTo(idx+1, true); };
scope.go = function(i){ moveTo(i, true); };
// ავტოპლეი
function startAutoplay(){
stopAutoplay();
var ms = coerceNumber(scope.autoplay, 0);
if(ms && ms > 0 && count > 1){
autoplayPromise = $interval(function(){
var next = (idx + 1) % count;
moveTo(next, true);
}, ms);
}
}
function stopAutoplay(){ if(autoplayPromise){ $interval.cancel(autoplayPromise); autoplayPromise=null; } }
// swipe/drag
track.addEventListener('pointerdown', function(e){
dragging = true; startX = e.clientX; deltaX = 0;
track.setPointerCapture(e.pointerId);
track.style.transition = 'none';
});
track.addEventListener('pointermove', function(e){
if(!dragging) return;
deltaX = e.clientX - startX;
track.style.transform = 'translateX(' + (-idx * step + deltaX) + 'px)';
});
track.addEventListener('pointerup', function(){
if(!dragging) return; dragging = false;
var threshold = step * 0.2;
if(deltaX > threshold) moveTo(idx-1, true);
else if(deltaX < -threshold)moveTo(idx+1, true);
else moveTo(idx, true);
});
track.addEventListener('pointercancel', function(){
if(dragging){ dragging=false; moveTo(idx,true); }
});
// items ცვლილება
scope.$watchCollection('items', function(arr){
count = (arr && arr.length) || 0;
scope.count = count;
$timeout(function(){
measure();
moveTo(0, false);
startAutoplay();
});
});
var onResize = function(){ measure(); };
angular.element($window).on('resize', onResize);
el.on('mouseenter', stopAutoplay);
el.on('mouseleave', startAutoplay);
scope.$on('$destroy', function(){
stopAutoplay();
angular.element($window).off('resize', onResize);
el.off('mouseenter'); el.off('mouseleave');
});
$timeout(measure);
}
};
}]);
RootApp.directive('fileInput', ['$http', '$timeout', function ($http, $timeout) {
return {
restrict: 'E',
template: `
`,
scope: {
ngModel: '=',
},
controller: ['$scope', '$http', '$element','$attrs', function ($scope, $http, $element) {
$scope.files = [];
$scope.isDragOver = false;
if ($scope.ngModel) {
const unics = $scope.ngModel.split(',');
unics.forEach(unic => {
const file = {
unic: unic,
preview: `/api/file/thumb/${unic}`,
uploadProgress: 100,
isUploading: false
};
$scope.files.push(file);
});
}else{
$scope.ngModel = '';
}
$scope.sortableOptions = {
stop: function () {
$scope.updateNgModel(); // განახლდეს ngModel ახალი რიგითობით
}
};
function resizeImage(file, callback) {
const MAX_WIDTH = 1024;
const MAX_HEIGHT = 1024;
const img = new Image();
const reader = new FileReader();
reader.onload = function (e) {
img.src = e.target.result;
img.onload = function () {
let width = img.width;
let height = img.height;
// Calculate the new dimensions if the image is too large
if (width > MAX_WIDTH || height > MAX_HEIGHT) {
if (width > height) {
height = Math.round((MAX_WIDTH / width) * height);
width = MAX_WIDTH;
} else {
width = Math.round((MAX_HEIGHT / height) * width);
height = MAX_HEIGHT;
}
}
// Create a canvas to resize the image
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Draw the image to the canvas
ctx.drawImage(img, 0, 0, width, height);
// Convert canvas to blob and pass it to callback
canvas.toBlob(function (blob) {
const resizedFile = new File([blob], file.name, { type: file.type });
callback(resizedFile);
}, file.type);
};
};
reader.readAsDataURL(file);
}
// Open the file dialog
$scope.openFileDialog = function () {
$element.find('input[type="file"]').click();
};
// Handle file selection
$scope.onFileSelect = function (files) {
angular.forEach(files, function (file) {
if (file.type.startsWith('image/')) {
// Check if the file needs to be resized
resizeImage(file, function (resizedFile) {
const reader = new FileReader();
reader.onload = function (e) {
$timeout(function () {
resizedFile.preview = e.target.result;
resizedFile.isUploading = false;
resizedFile.uploadProgress = 0;
resizedFile.errorMessage = '';
resizedFile.unic = false; // Placeholder for unic value from server
$scope.files.push(resizedFile);
});
};
reader.readAsDataURL(resizedFile);
});
}
});
};
// Check if all files are uploaded
$scope.allUploaded = function () {
return $scope.files.every(function(file) {
return file.unic || file.isUploading;
});
};
// Upload a single file
$scope.uploadFile = function (file) {
file.isUploading = true;
const formData = new FormData();
formData.append('file', file);
$http.post('/api/file/upload', formData, {
headers: { 'Content-Type': undefined },
transformRequest: angular.identity,
uploadEventHandlers: {
progress: function (e) {
if (e.lengthComputable) {
$timeout(function () {
file.uploadProgress = Math.round((e.loaded / e.total) * 100);
});
}
}
}
}).then(function (response) {
file.isUploading = false;
// file.isUploaded = true;
if (response.data && response.data.unic) {
file.unic = response.data.unic;
$scope.updateNgModel();
}
}).catch(function () {
file.isUploading = false;
file.uploadProgress = 0;
file.errorMessage = 'Upload failed. Please try again.';
});
};
// Upload all files
$scope.uploadAll = function () {
angular.forEach($scope.files, function (file) {
if (!file.unic && !file.isUploading) {
$scope.uploadFile(file);
}
});
};
// Remove a file
$scope.removeFile = function (file) {
if (file.isUploading) {
alert('Cannot delete a file that is currently uploading.');
return;
}
const index = $scope.files.indexOf(file);
if (index > -1) {
// If the file has been uploaded, optionally delete it from the server
if (file.unic && 0) {
$http.post('/api/file/delete', { unic: file.unic })
.then(function () {
// Successfully deleted on server
})
.catch(function () {
// Handle deletion error if necessary
});
}
$scope.files.splice(index, 1);
$scope.updateNgModel();
}
};
// Update ngModel with comma-separated unic values
$scope.updateNgModel = function () {
const unicValues = $scope.files
.filter(file => file.unic)
.map(file => file.unic);
$scope.ngModel = unicValues.join(',');
};
// Handle drag and drop
const dropzone = $element[0].querySelector('.dropzone');
dropzone.addEventListener('dragover', function (event) {
event.preventDefault();
$timeout(function () {
$scope.isDragOver = true;
});
});
dropzone.addEventListener('dragleave', function (event) {
event.preventDefault();
$timeout(function () {
$scope.isDragOver = false;
});
});
dropzone.addEventListener('drop', function (event) {
event.preventDefault();
const files = event.dataTransfer.files;
$scope.isDragOver = false;
$scope.onFileSelect(files);
});
}]
};
}]);
RootApp.config(function ($stateProvider,$locationProvider,$urlRouterProvider) {
$stateProvider
.state("/login", {
url : '/login',
templateUrl: "/app/templates/login.php",
controller: function ($scope,$rootScope,$http) {
$scope.login=(u)=>{
$http.post($rootScope.server + "/login", u).then(function ($rs, h) {
Swal.fire("","თქვენ წარმატებით გაიარეთ ავტორიზაცია","success")
setTimeout(()=>{
location.reload();
},200);
},()=>{
Swal.fire("","მომხმარებელი არ მოიძებნა","error")
});
}
}
})
.state("/", { url: '/',
templateUrl: "/app/templates/main.php",
controller: function ($state) { $state.go('/login'); }})
// $urlRouterProvider.when('/main',`/main/${moment(new Date()).format("YYYY-MM-DD")}`);
$urlRouterProvider.otherwise("/");
$locationProvider.html5Mode({ enabled: true, requireBase: false });
});