Przeglądaj źródła

table ajax more func popover - fetch more functions

Piotr Labudda 10 lat temu
rodzic
commit
a9a338f39f
1 zmienionych plików z 243 dodań i 133 usunięć
  1. 243 133
      SE/se-lib/TableAjax.php

+ 243 - 133
SE/se-lib/TableAjax.php

@@ -7,6 +7,7 @@ Lib::loadClass('SE_Layout');
 Lib::loadClass('FoldersConfig');
 Lib::loadClass('FileUploader');
 Lib::loadClass('UserProfile');
+Lib::loadClass('ProcesHelper');
 
 class TableAjax extends ViewAjax {
 
@@ -516,7 +517,7 @@ class TableAjax extends ViewAjax {
 }(jQuery));
 
 (function($, undefined) {
-	var TableAjax = function () {
+	var TableAjax = function() {
 		var priv = {}; //private api
 		var publ = {}; //public api
 
@@ -584,7 +585,7 @@ class TableAjax extends ViewAjax {
 		/*
 		 initialize the plugin.
 		 */
-		priv.init = function () {
+		priv.init = function() {
 			_uiNodeCont = priv.options.id;
 			_state = {};// init state
 			_state.page = 1;
@@ -622,7 +623,7 @@ class TableAjax extends ViewAjax {
 			}
 		};
 
-		priv.initEvents = function () {
+		priv.initEvents = function() {
 			jQuery(_uiNodeCont).on('TableAjax:render', priv.onRender);
 		};
 
@@ -651,7 +652,7 @@ class TableAjax extends ViewAjax {
 			}
 		};
 
-		priv.initialRender = function () {
+		priv.initialRender = function() {
 			_uiNode$Table = $('<table class="AjaxTable table table-striped table-hover table-bordered table-condensed"></table>').appendTo(_uiNodeCont);
 				_head = $('<thead></thead>').prependTo(_uiNode$Table);
 					_headSort = $('<tr class="sort tblAjax__head__sort"></tr>').prependTo(_head);
@@ -683,7 +684,7 @@ class TableAjax extends ViewAjax {
 		 note that only the parts we need is created.
 		 (yeah, the function is huge)
 		 */
-		priv.renderTable = function () {
+		priv.renderTable = function() {
 			//create table itself
 /// console.log('renderTable:: _data', _data);//TODO:DBG:RMME
 /// console.log('renderTable:: _uiNode$Table', _uiNode$Table);//TODO:DBG:RMME
@@ -727,7 +728,7 @@ class TableAjax extends ViewAjax {
 				var rowsAdded = 0;
 
 				//slice out the chunk of data we need and create rows
-				$.each(_data.rows, function (index, props) {
+				$.each(_data.rows, function(index, props) {
 					var rowNode = priv.renderRow(props);
 					if (rowNode) rowNode.appendTo(_bodyNode);
 					rowsAdded++;
@@ -877,7 +878,7 @@ class TableAjax extends ViewAjax {
 								&& (0 === columnProps._tsRetId || '0' === columnProps._tsRetId)
 								&& undefined !== columnProps._tsSimpleLink) {
 							valLink = columnProps._tsSimpleLink.format;
-							$.each(columnProps._tsSimpleLink.aliasMap, function (i, v) {
+							$.each(columnProps._tsSimpleLink.aliasMap, function(i, v) {
 								//console.log('simpleLink aliasMap columnName:', columnName, 'i:', i, 'v:', v, 'props['+v+']', props[v], 'val', val, 'typeof val', typeof val);
 								if (undefined !== props[v]) {
 									valLink = valLink.replace(new RegExp('\{' + i + '\}', 'g'), props[v]);
@@ -1004,13 +1005,8 @@ class TableAjax extends ViewAjax {
 			moreFunctions = keys.splice(3);
 			keys.forEach(function(key) {
 				var funObj = rowFunctions[key],
-						funcNode = $('<a href="#" style="margin:0 2px;"></a>')
+						funcNode = priv.generateFunctionNode(funObj, rowPK, {ico: true, label: false})
 				;
-				//funcNode = funObj.f(rowPK);
-				if ('href' in funObj) funcNode.attr('href', funObj.href.f(rowPK));
-				if ('ico' in funObj) funcNode.append('<span class="' + funObj.ico + '"></span>');
-				if ('onclick' in funObj) funcNode.attr('onclick', funObj.onclick.f(rowPK));
-				if ('title' in funObj) funcNode.attr('title', funObj.title);
 				funcNode.appendTo(cellNode);
 			});
 			moreFuncBtnNode = $('<a href="#" style="margin:0 2px;text-decoration:none" title="Więcej funkcji ['+rowPK+']" class="glyphicon glyphicon-menu-hamburger"> </a>');
@@ -1019,24 +1015,7 @@ class TableAjax extends ViewAjax {
 			return cellNode;
 		};
 
-		priv.generateMoreFunctionsNodeList = function (moreFunctions, rowFunctions, rowPK) {
-			var moreFuncNodeList = [];
-			moreFunctions.forEach(function(funcName) {
-				var funObj = rowFunctions[funcName],
-						funcNode = $('<a href="#" style="margin:0 2px;"></a>')
-				;
-				//moreFuncNodeList += link.f(rowPK);
-				if ('href' in funObj) funcNode.attr('href', funObj.href.f(rowPK));
-				if ('ico' in funObj) funcNode.append('<span class="' + funObj.ico + '"></span>');
-				if ('onclick' in funObj) funcNode.attr('onclick', funObj.onclick.f(rowPK));
-				if ('title' in funObj) funcNode.attr('title', funObj.title);
-				if ('title' in funObj) funcNode.append(' ' + funObj.title);
-				moreFuncNodeList.push(funcNode);
-			});
-			return moreFuncNodeList;
-		};
-
-		priv.popoverCellMoreFunctions = function (e) {
+		priv.popoverCellMoreFunctions = function(e) {
 			e.preventDefault();
 			e.stopPropagation();
 			if (priv.options.debug) console.log('TableAjax::popoverCellMoreFunctions: rowPK', e.data.rowPK, 'moreFunctions', e.data.more, 'rowFunctions', e.data.rowFunctions);
@@ -1044,7 +1023,9 @@ class TableAjax extends ViewAjax {
 				var lastId = _popoverCell.data('rowid'),
 						lastCol = _popoverCell.data('col'),
 						rowPK = e.data.rowPK,
-						moreFuncNodeList = null
+						moreFunctions = e.data.more,
+						rowFunctions = e.data.rowFunctions,
+						funcListNode
 				;
 
 				if (lastId == e.data.rowPK && lastCol == 'moreFunctions') {
@@ -1055,16 +1036,24 @@ class TableAjax extends ViewAjax {
 						_popoverCellCurrent.popover('destroy');
 					}
 
-					moreFuncNodeList = priv.generateMoreFunctionsNodeList(e.data.more, e.data.rowFunctions, rowPK);
-
 					_popoverCell.data('rowid', rowPK);
 					_popoverCell.data('col', 'rowFunctions');
-					_popoverCell.html(moreFuncNodeList);
+					_popoverCell.empty();
+					funcListNode = $('<ul class="list-unstyled"></ul>').appendTo(_popoverCell);
+					moreFunctions.forEach(function(funcName) {
+						var funcItemNode = $('<li></li>').appendTo(funcListNode),
+								funObj = rowFunctions[funcName],
+								funcNode = priv.generateFunctionNode(funObj, rowPK, {ico: true, label: true})
+						;
+						funcItemNode.append(funcNode);
+					});
+
 					_popoverCell.append('<div class="popoverCellContent" style="white-space:normal"></div>');
 
 					_popoverCellCurrent = jQuery(e.currentTarget);
 					// title : '<span class="text-info"><strong>title</strong></span> <button type="button" id="close" class="close">&times;</button>'
 					var opts = {
+						container: 'body',
 						placement: 'right',
 						trigger: 'click',
 						template: '',
@@ -1105,6 +1094,28 @@ class TableAjax extends ViewAjax {
 			return;
 		};
 
+		priv.generateFunctionNode = function(funObj, rowPK, props) {
+			var defaultsProps = {
+						ico: true,
+						label: false
+					},
+					props = $.extend({}, defaultsProps, props);
+					funcNode = $('<a href="#" style="margin:0 2px;"></a>')
+			;
+			if ('href' in funObj) funcNode.attr('href', funObj.href.f(rowPK));
+			if (props.ico) {
+				if ('ico' in funObj) funcNode.append('<span class="' + funObj.ico + '"></span>');
+			}
+			if ('onclick' in funObj) funcNode.attr('onclick', funObj.onclick.f(rowPK));
+			if ('title' in funObj) funcNode.attr('title', funObj.title);
+
+			if (props.label) {
+				if ('title' in funObj) funcNode.append(' ' + funObj.title);
+			}
+
+			return funcNode;
+		};
+
 		priv.ajaxLoadMoreFunctionsCell = function(rowPK) {
 			if (_popoverCellAjaxXhr) {
 				_popoverCellAjaxXhr.abort();
@@ -1115,16 +1126,35 @@ class TableAjax extends ViewAjax {
 				url: 'index-ajax.php?_zasobID=<?php echo $this->_zasobID; ?>&_cls=<?php echo __CLASS__; ?>&_hash=<?php echo $this->_htmlID; ?>&_task=MORE_FUNCTIONS_CELL&ID=' + rowPK,
 				dataType: 'json',
 				contentType: "application/json; charset=utf-8",
-				data: '',
-				success: function(data) {
-					if (data && 'success' === data.type) {
-						var addHtml = '';
-						addHtml += 'TODO: ...';
-						//_popoverCell.append(addHtml);// cache
-						if (_popoverCellCurrent) {
-							var popoverNodeId = _popoverCellCurrent.attr('aria-describedby');
-							if (popoverNodeId) {
-								jQuery('#' + popoverNodeId).find('.popoverCellContent').html(addHtml);
+				data: ''
+			})
+			.done(function(data, textStatus, jqXHR){
+				if (data && 'success' === data.type) {
+					var popoverCellContent,
+							rowFunctions = []
+					;
+					if (data.rowFunctions && data.rowFunctions.length > 0) {
+						rowFunctions = data.rowFunctions;
+					}
+					if (rowFunctions.length > 0) {
+						var popoverCellContent = $('<ul class="list-unstyled"></ul>');
+						rowFunctions.forEach(function(funObj) {
+							var funcItemNode = $('<li></li>').appendTo(popoverCellContent),
+									funcNode = priv.generateFunctionNode(funObj, rowPK, {ico: true, label: true})
+							;
+							funcItemNode.append(funcNode);
+						});
+					} else {
+						popoverCellContent = '<p class="text-muted">Brak dodatkowych funkcji</p>';
+					}
+					//_popoverCell.append(popoverCellContent);// cache
+					if (_popoverCellCurrent) {
+						var popoverNodeId = _popoverCellCurrent.attr('aria-describedby');
+						if (popoverNodeId) {
+							var pooverCntNode = jQuery('#' + popoverNodeId).find('.popoverCellContent');
+							pooverCntNode.empty().append(popoverCellContent);
+							if (rowFunctions.length <= 0) {
+								pooverCntNode.find('p.text-muted').delay(600).hide(300);
 							}
 						}
 					}
@@ -1322,7 +1352,7 @@ class TableAjax extends ViewAjax {
 				tooltip = priv.options.types.bool.filterTooltip || 'Toggle between:<br/>indeterminate,<br/>checked,<br/>unchecked';
 				headCell = $('<th></th>').appendTo(node);
 				elem = $('<input class="filter indeterminate" checked type="checkbox" />').appendTo(headCell);
-				$.map(_state.filters.filterCols, function (colProps, col) {
+				$.map(_state.filters.filterCols, function(colProps, col) {
 					if (col == "unique") {
 						if (colProps.filter) elem.prop('checked', true).removeClass('indeterminate');
 						else if (!colProps.filter) elem.prop('checked', false).removeClass('indeterminate');
@@ -1439,7 +1469,7 @@ class TableAjax extends ViewAjax {
 					}
 
 					if (elem && props.filter) {
-						$.map(_state.filters.filterCols, function (colProps, col) {
+						$.map(_state.filters.filterCols, function(colProps, col) {
 							if (col == column) {
 								var columnSettings = _data.cols[col];
 								if (columnSettings.type == 'bool') {
@@ -1561,7 +1591,7 @@ class TableAjax extends ViewAjax {
 				var span = $('<span class="caret"></span>').appendTo(btn);
 				var ul = $('<ul class="dropdown-menu">').appendTo(node);
 
-				$.each(priv.options.pageSizes, function (index, val) {
+				$.each(priv.options.pageSizes, function(index, val) {
 					var li = $('<li></li>').appendTo(ul);
 					if (val == priv.options.pageSize) {
 						$('<a style="color:#337AB7;">{0}</a>'.f(val)).appendTo(li);
@@ -1586,7 +1616,7 @@ class TableAjax extends ViewAjax {
 				var span = $('<span class="caret"></span>').appendTo(btn);
 				var ul = $('<ul class="dropdown-menu">').appendTo(node);
 
-				$.each(_data.cols, function (col, props) {
+				$.each(_data.cols, function(col, props) {
 					if (props.type != "unique" && col != 'ID') {
 						var li = $('<li></li>').appendTo(ul),
 								label = props.friendly || col;
@@ -1636,7 +1666,7 @@ class TableAjax extends ViewAjax {
 				var span = $('<span class="caret"></span>').appendTo(btn);
 				var ul = $('<ul class="dropdown-menu">').appendTo(node);
 
-				$.each(_data.cols, function (col, props) {
+				$.each(_data.cols, function(col, props) {
 					if (-1 !== priv.options.exportFields.indexOf(col)) {
 						var li = $('<li></li>').appendTo(ul);
 						$('<input {0} type="checkbox" title="{1}" value="{1}" >&nbsp;{2}</input>'.f((_exportFieldsSelect[col])? 'checked' : '', col, props.friendly || col)).appendTo(li);
@@ -1739,7 +1769,7 @@ class TableAjax extends ViewAjax {
 			currentNode.replaceWith(node);
 		};
 
-		priv.exportFieldChanged = function (e) {
+		priv.exportFieldChanged = function(e) {
 
 			e.stopPropagation();
 
@@ -1748,15 +1778,15 @@ class TableAjax extends ViewAjax {
 			_exportFieldsSelect[column] = !_exportFieldsSelect[column];
 		};
 
-		priv.exportToHTML = function (e) {
+		priv.exportToHTML = function(e) {
 			priv.exportData('html', $(this), e);
 		};
-		priv.exportToCSV = function (e) {
+		priv.exportToCSV = function(e) {
 			priv.exportData('csv', $(this), e);
 		};
-		priv.exportData = function (format, node, e) {
+		priv.exportData = function(format, node, e) {
 			var exportFields = [];
-			$.each(_exportFieldsSelect, function (col, selected) {
+			$.each(_exportFieldsSelect, function(col, selected) {
 				if (selected) {
 					exportFields.push(col);
 				}
@@ -1789,7 +1819,7 @@ class TableAjax extends ViewAjax {
 			exportUrl += '&sortDir=' + (_state.filters.currSortFlip ? "desc" : "asc");
 
 			if (Object.keys(_state.filters.filterCols).length > 0) {
-				$.each(_state.filters.filterCols, function (col, colProps) {
+				$.each(_state.filters.filterCols, function(col, colProps) {
 					if (colProps.filter && colProps.filter.length > 0) {
 						exportUrl += '&f_' + col + '=' + colProps.filter;
 					}
@@ -1804,7 +1834,7 @@ class TableAjax extends ViewAjax {
 			});
 
 			if (priv.options.forceFilterInit) {
-				$.map(priv.options.forceFilterInit, function (fltrProps, fltr) {
+				$.map(priv.options.forceFilterInit, function(fltrProps, fltr) {
 					exportUrl += '&sf_' + fltr + '=' + fltrProps;
 				});
 			}
@@ -1816,7 +1846,7 @@ class TableAjax extends ViewAjax {
 		 calls the webservice(if defined).
 		 used only inside priv.init
 		 */
-		priv.update = function (callback) {
+		priv.update = function(callback) {
 			var skipCols, resetChecked;// undefined
 			if (!priv.options.url) {
 				if (priv.options.debug) console.log('no url found L.<?php echo __LINE__; ?>');
@@ -1831,7 +1861,7 @@ class TableAjax extends ViewAjax {
 			initUrlAdd += '&currSortCol=' + _state.filters.currSortCol;
 			initUrlAdd += '&currSortFlip=' + ((_state.filters.currSortCol)? "desc" : "asc");
 			if (Object.keys(_state.filters.filterCols).length > 0) {
-				$.each(_state.filters.filterCols, function (col, colProps) {
+				$.each(_state.filters.filterCols, function(col, colProps) {
 					if (colProps.filter && colProps.filter.length > 0) {
 						initUrlAdd += '&f_' + col + '=' + colProps.filter;
 						filtersInitSet = true;
@@ -1846,7 +1876,7 @@ class TableAjax extends ViewAjax {
 			});
 
 			if (priv.options.forceFilterInit) {
-				$.map(priv.options.forceFilterInit, function (fltrProps, fltr) {
+				$.map(priv.options.forceFilterInit, function(fltrProps, fltr) {
 					reqData['f_' + fltr] = fltrProps;
 					filtersInitSet = true;
 				});
@@ -1859,7 +1889,7 @@ class TableAjax extends ViewAjax {
 				contentType: "application/json; charset=utf-8",
 				data: reqData,
 				async: true,
-				success: function (data) {
+				success: function(data) {
 					if (priv.options.debug) console.log('request finished L.<?php echo __LINE__; ?>');
 
 					// assign the new data
@@ -1901,7 +1931,7 @@ class TableAjax extends ViewAjax {
 					if (typeof callback == "function")
 						callback.call(this);
 				},
-				error: function (err) {
+				error: function(err) {
 					//console.log('request error: {0}'.f(JSON.stringify(err)));
 					if (typeof callback == "function")
 						callback.call(this);
@@ -1912,7 +1942,7 @@ class TableAjax extends ViewAjax {
 		/*
 		 assigns the new data.
 		 */
-		priv.setState = function (state) {
+		priv.setState = function(state) {
 			var oldState = _state,// TODO: use to check what really changed (use extend!)
 					renderParts = {};
 			if (state.data) {
@@ -1959,19 +1989,19 @@ class TableAjax extends ViewAjax {
 			}
 		};
 
-		priv.setStateCols = function (cols, uniqueCol) {
+		priv.setStateCols = function(cols, uniqueCol) {
 			_state.cols = cols;
 			_state.uniqueCol = uniqueCol;
 			// fix col name - props.column
-			$.each(_state.cols, function (col, props) {
+			$.each(_state.cols, function(col, props) {
 				props.column = col;
 			});
 			// fix col types - default 'string'
-			$.each(_state.cols, function (col, props) {
+			$.each(_state.cols, function(col, props) {
 				if (!props.type) cols[col].type = "string";
 			});
 			// fix props.filter - set true if not set - TODO: allow filter this col?
-			$.each(_state.cols, function (col, props) {
+			$.each(_state.cols, function(col, props) {
 				if (props.filter == undefined) props.filter = true;
 			});
 			if (_state.uniqueCol) {
@@ -1983,7 +2013,7 @@ class TableAjax extends ViewAjax {
 					hidden: true
 				};
 			}
-			_state.colsSorted = Object.keys(_state.cols).sort(function (a, b) {
+			_state.colsSorted = Object.keys(_state.cols).sort(function(a, b) {
 				return _state.cols[a].index - _state.cols[b].index;
 			});
 		};
@@ -1991,7 +2021,7 @@ class TableAjax extends ViewAjax {
 		priv.setStateFilters = function(stateFilters) {
 			var newFilterCols = {},
 					newSpecialFilters = {};
-			$.map(stateFilters, function (fltrProps, fltr) {
+			$.map(stateFilters, function(fltrProps, fltr) {
 				switch (fltr) {
 					case 'currSortCol': _state.filters.currSortCol = fltrProps; break;
 					case 'currSortFlip': _state.filters.currSortFlip = (fltrProps == 'desc')? true : false; break;
@@ -2014,7 +2044,7 @@ class TableAjax extends ViewAjax {
 			_state.specialFilters = newSpecialFilters;
 		};
 
-		priv.setStateData = function (pData, skipCols, resetChecked) {
+		priv.setStateData = function(pData, skipCols, resetChecked) {
 			var data = $.extend(true, {}, pData);
 			data.cols = _state.cols;// always use old cols - change cols mved to priv.setStateCols
 
@@ -2036,7 +2066,7 @@ class TableAjax extends ViewAjax {
 
 			if (_state.uniqueCol) {
 				//add rows that needs to be pre-checked
-				$.each(_data.rows, function (index, row) {
+				$.each(_data.rows, function(index, row) {
 					if (row["checked"] === true)
 						_uniqueCols[row[_state.uniqueCol]] = row;
 				});
@@ -2046,7 +2076,7 @@ class TableAjax extends ViewAjax {
 		/**
 		 * Filters the data.
 		 */
-		priv.filter = function () {
+		priv.filter = function() {
 			if (!priv.options.filter) return;
 			if (Object.keys(_state.filters.filterCols).length == 0) return;
 
@@ -2056,7 +2086,7 @@ class TableAjax extends ViewAjax {
 		/*
 		 sorts the data on the current sorting column
 		 */
-		priv.sort = function () {
+		priv.sort = function() {
 			if (!_data.cols[_state.filters.currSortCol]) _state.filters.currSortCol = "";
 			if (!_state.filters.currSortCol) return;
 
@@ -2066,9 +2096,9 @@ class TableAjax extends ViewAjax {
 		/*
 		 helper that returns the underlying data by the unique value
 		 */
-		priv.getRow = function (uniqueValue) {
+		priv.getRow = function(uniqueValue) {
 			var row;
-			$.each(_data.rowsOrg, function (i, r) {
+			$.each(_data.rowsOrg, function(i, r) {
 				if (r[_state.uniqueCol] == uniqueValue) {
 					row = r;
 					return false;
@@ -2081,7 +2111,7 @@ class TableAjax extends ViewAjax {
 		 when: typing a filter
 		 what: triggers filtering on the value
 		 */
-		priv.filterChanged = function (e) {
+		priv.filterChanged = function(e) {
 			//clear old timer if we're typing fast enough
 			if (priv.options.debug) console.log('filterChanged L.<?php echo __LINE__; ?>');
 			if (_filterTimeout) {
@@ -2130,20 +2160,20 @@ class TableAjax extends ViewAjax {
 			};
 
 			//wait a few deciseconds before filtering
-			_filterTimeout = setTimeout(function () {
+			_filterTimeout = setTimeout(function() {
 				_filterTimeout = undefined;
 				priv.filter();
 			}, timeout);
 		};
 
-		priv.filtersClean = function (e) {
+		priv.filtersClean = function(e) {
 			if (_filterTimeout) {
 				clearTimeout(_filterTimeout);
 				if (priv.options.debug) console.log('filtering cancelled - filtersClean');
 			}
 
 			var filtersActive = false;
-			$.map(_state.filters.filterCols, function (colProps, col) {
+			$.map(_state.filters.filterCols, function(colProps, col) {
 				if (colProps.filter.length > 0) {
 					filtersActive = true;
 					colProps.filter = '';
@@ -2166,7 +2196,7 @@ class TableAjax extends ViewAjax {
 		 * when: click on special filter
 		 * what: triggers filtering on the value
 		 */
-		priv.specialFilterChanged = function (e) {
+		priv.specialFilterChanged = function(e) {
 			if (priv.options.debug) console.log('specialFilterChanged e.data:', e.data);
 			var state = {};
 			state.specialFilters = _state.specialFilters;
@@ -2417,7 +2447,7 @@ class TableAjax extends ViewAjax {
 		 when: changing page in pager
 		 what: triggers table to be created with new page
 		 */
-		priv.pageChanged = function (e) {
+		priv.pageChanged = function(e) {
 			e.preventDefault();
 			var totalPages = Math.ceil(_data.total / _state.pageSize);
 			if (e.data.pageIndex < 1 || e.data.pageIndex > totalPages) return;
@@ -2432,7 +2462,7 @@ class TableAjax extends ViewAjax {
 		 when: changing pagesize in pagesize dropdown
 		 what: triggers table to be created with new pagesize
 		 */
-		priv.pageSizeChanged = function (e) {
+		priv.pageSizeChanged = function(e) {
 			e.preventDefault();
 			var val = $(this).text();
 			if (priv.options.debug) console.log('pagesize changed to:{0}'.f(val));
@@ -2453,7 +2483,7 @@ class TableAjax extends ViewAjax {
 		 when: clicking a column
 		 what: triggers table to be sorted by the column
 		 */
-		priv.columnClicked = function (e) {
+		priv.columnClicked = function(e) {
 			e.preventDefault();
 			if (priv.options.debug) console.log('col:{0} clicked'.f(e.data.column));
 
@@ -2493,7 +2523,7 @@ class TableAjax extends ViewAjax {
 		priv.saveHiddenCols = function() {
 			var reqData = {};
 
-			$.each(_data.cols, function (col, props) {
+			$.each(_data.cols, function(col, props) {
 				if (props.type != "unique" && col != 'unique' && col != 'ID') {
 					reqData[col] = (props.hidden)? 'HIDE' : 'SHOW';
 				}
@@ -2522,7 +2552,7 @@ class TableAjax extends ViewAjax {
 		 when: clicking a column in columnpicker
 		 what: triggers table to show/hide the column
 		 */
-		priv.columnPickerClicked = function (e) {
+		priv.columnPickerClicked = function(e) {
 			e.stopPropagation();
 
 			var column = $(this).val();
@@ -2536,7 +2566,7 @@ class TableAjax extends ViewAjax {
 			jQuery(_uiNodeCont).trigger('TableAjax:render', ['head', 'body']);
 		};
 
-		priv.columnHideClicked = function (e) {
+		priv.columnHideClicked = function(e) {
 			e.stopPropagation();
 
 			var column;
@@ -2559,7 +2589,7 @@ class TableAjax extends ViewAjax {
 		 when: clicking a row checkbox
 		 what: toggles checked state on row, and add/removes it from checked array
 		 */
-		priv.rowChecked = function (e) {
+		priv.rowChecked = function(e) {
 			var elem = $(this);
 
 			//get the row's unique value
@@ -2575,7 +2605,7 @@ class TableAjax extends ViewAjax {
 		 when: clicking anywhere on a row
 		 what: row data and other info is returned to caller
 		 */
-//		priv.rowClicked = function (e) {// TODO: not used
+//		priv.rowClicked = function(e) {// TODO: not used
 //			if (!_state.uniqueCol) {
 //				if (priv.options.debug) console.log('no unique column specified');
 //				return;
@@ -2602,7 +2632,7 @@ class TableAjax extends ViewAjax {
 		/**
 		 * Inline edit.
 		 */
-		priv.rowDblClicked = function (e) {
+		priv.rowDblClicked = function(e) {
 			var inlineEditBox$Node = $(_uiNodeCont).parent().children('.tblAjax__inlineEditBox');
 
 			// hide popover for typespecial fld on click
@@ -2643,7 +2673,7 @@ class TableAjax extends ViewAjax {
 					dataType: 'text',
 					data: '',
 					async: true,
-					success: function (data) {
+					success: function(data) {
 						inlineEditBox$Node.find('.inlineEditBox-cnt').html(data);
 						inlineEditBox$Node.find('.btn-save').show();
 
@@ -2663,7 +2693,7 @@ class TableAjax extends ViewAjax {
 							});
 						}
 					},
-					error: function (err) {
+					error: function(err) {
 						if (priv.options.debug) console.log('err');
 					}
 				});
@@ -2708,7 +2738,7 @@ class TableAjax extends ViewAjax {
 
 		};
 
-		priv.popoverCellTypeSpecial = function (e) {
+		priv.popoverCellTypeSpecial = function(e) {
 			e.preventDefault();
 			e.stopPropagation();
 			if ('id' in e.data && 'col' in e.data && e.data.id > 0) {
@@ -2769,12 +2799,12 @@ class TableAjax extends ViewAjax {
 			location.hash = hash;
 		};
 
-		priv.refresh = function (e) {
+		priv.refresh = function(e) {
 			e.preventDefault();
 			publ.loadPage(_state.page);
 		};
 
-		publ.init = function (options) {
+		publ.init = function(options) {
 			if (priv.options.debug) console.log('TableAjax initialization...');
 			//merge supplied options with defaults
 			$.extend(priv.options, defaults, options);
@@ -2782,7 +2812,7 @@ class TableAjax extends ViewAjax {
 			return publ;
 		};
 
-		publ.refresh = function () {
+		publ.refresh = function() {
 			publ.loadPage(_state.page);
 		};
 
@@ -2797,7 +2827,7 @@ class TableAjax extends ViewAjax {
 			};
 
 			if (Object.keys(_state.filters.filterCols).length > 0) {
-				$.each(_state.filters.filterCols, function (col, colProps) {
+				$.each(_state.filters.filterCols, function(col, colProps) {
 					if (colProps.filter && colProps.filter.length > 0) {
 						reqData['f_' + col] = colProps.filter;
 					}
@@ -2813,7 +2843,7 @@ class TableAjax extends ViewAjax {
 			});
 
 			if (priv.options.forceFilterInit) {
-				$.map(priv.options.forceFilterInit, function (fltrProps, fltr) {
+				$.map(priv.options.forceFilterInit, function(fltrProps, fltr) {
 					reqData['f_' + fltr] = fltrProps;
 					filtersInitSet = true;
 				});
@@ -2828,7 +2858,7 @@ class TableAjax extends ViewAjax {
 				contentType: "application/json; charset=utf-8",
 				data: reqData,
 				async: true,
-				success: function (data) {
+				success: function(data) {
 					state = {data: {}};
 					state.data.rows = data.rows || [];
 					state.data.total = data.total || 0;
@@ -2838,7 +2868,7 @@ class TableAjax extends ViewAjax {
 					priv.setState(state);
 					_uiNode$Table.parent().parent().removeClass('AjaxTable-loading');
 				},
-				error: function (err) {
+				error: function(err) {
 					if (priv.options.debug) console.log('request error: {0}'.f(JSON.stringify(err)));
 				}
 			});
@@ -2848,7 +2878,7 @@ class TableAjax extends ViewAjax {
 			return _state.page;
 		};
 
-		publ.popoverCellRemove = function () {
+		publ.popoverCellRemove = function() {
 			if (_popoverCellCurrent) {
 				_popoverCellCurrent.popover('destroy');
 			}
@@ -2860,30 +2890,30 @@ class TableAjax extends ViewAjax {
 		return publ;
 	}
 
-	$.fn.TableAjax = function (options) {
+	$.fn.TableAjax = function(options) {
 		options = options || {};
-		return this.each(function () {
+		return this.each(function() {
 			options.id = this;
 			$(this).data('TableAjax', new TableAjax().init(options));
 		});
 	};
 
-	$.fn.TableAjaxLoadPage = function (page, pageSize) {
-		return this.each(function () {
+	$.fn.TableAjaxLoadPage = function(page, pageSize) {
+		return this.each(function() {
 			var tblAjax = jQuery(this).data('TableAjax');
 			var curPage = page || tblAjax.getCurrentPage();
 			if (tblAjax) tblAjax.loadPage(curPage, pageSize);
 		});
 	};
 
-	$.fn.TableAjaxRefresh = function (page, pageSize) {
-		return this.each(function () {
+	$.fn.TableAjaxRefresh = function(page, pageSize) {
+		return this.each(function() {
 			var tblAjax = jQuery(this).data('TableAjax');
 			if (tblAjax) tblAjax.refresh();
 		});
 	};
 
-	String.prototype.format = String.prototype.f = function () {
+	String.prototype.format = String.prototype.f = function() {
 		var s = this;
 		i = arguments.length;
 		while (i--) s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
@@ -2949,9 +2979,9 @@ jQuery(document).ready(function(){
 			}
 			echo ',';
 		?>
-		router: function () {
+		router: function() {
 			var routes = {
-				EDIT: function (args) {
+				EDIT: function(args) {
 					var recordID = args;
 					if (typeof args == 'object') {
 						recordID = args.shift();
@@ -2983,13 +3013,13 @@ jQuery(document).ready(function(){
 						dataType: 'text',
 						data: '',
 						async: true,
-						success: function (data) {
+						success: function(data) {
 							taskCnt.removeClass('AjaxTable-loading');
 							jQuery(data).appendTo(taskCnt);
 
 							initDateTimePicker(taskCnt);
 						},
-						error: function (err) {
+						error: function(err) {
 							taskCnt.removeClass('AjaxTable-loading');
 							//console.log('request error: {0}'.f(err));
 						}
@@ -2997,7 +3027,7 @@ jQuery(document).ready(function(){
 
 					//return false;
 				},
-				HIST: function (args) {
+				HIST: function(args) {
 					var recordID = args;
 					if (typeof args == 'object') {
 						recordID = args.shift();
@@ -3029,12 +3059,12 @@ jQuery(document).ready(function(){
 						dataType: 'text',
 						data: '',
 						async: true,
-						success: function (data) {
+						success: function(data) {
 							taskCnt.removeClass('AjaxTable-loading');
 							//console.log('request finished L.<?php echo __LINE__; ?>');
 							jQuery(data).appendTo(taskCnt);
 						},
-						error: function (err) {
+						error: function(err) {
 							taskCnt.removeClass('AjaxTable-loading');
 							//console.log('request error: {0}'.f(err));
 						}
@@ -3073,12 +3103,12 @@ jQuery(document).ready(function(){
 						dataType: 'text',
 						data: '',
 						async: true,
-						success: function (data) {
+						success: function(data) {
 							taskCnt.removeClass('AjaxTable-loading');
 							//console.log('request finished L.<?php echo __LINE__; ?>', data);
 							jQuery(data).appendTo(taskCnt);
 						},
-						error: function (jqXHR, textStatus, errorThrown) {
+						error: function(jqXHR, textStatus, errorThrown) {
 							//console.log('request error:', jqXHR.status, 'txt:', jqXHR.responseText, 'err:', jqXHR);
 							taskCnt.removeClass('AjaxTable-loading');
 							var txt = jqXHR.responseText || 'Error';
@@ -3111,7 +3141,7 @@ jQuery(document).ready(function(){
 					var reqData = {};
 					var forceFilterInit = <?php echo json_encode($forceFilterInit);// TODO: read from TableAjax ?>;
 					if (forceFilterInit) {
-						$.map(forceFilterInit, function (fltrProps, fltr) {
+						$.map(forceFilterInit, function(fltrProps, fltr) {
 							reqData['ff_' + fltr] = fltrProps;
 						});
 					}
@@ -3122,14 +3152,14 @@ jQuery(document).ready(function(){
 						dataType: 'text',
 						data: reqData,
 						async: true,
-						success: function (data) {
+						success: function(data) {
 							taskCnt.removeClass('AjaxTable-loading');
 							//console.log('request finished L.<?php echo __LINE__; ?>');
 							jQuery(data).appendTo(taskCnt);
 
 							initDateTimePicker(taskCnt);
 						},
-						error: function (err) {
+						error: function(err) {
 							taskCnt.removeClass('AjaxTable-loading');
 							//console.log('request error: {0}'.f(err));
 						}
@@ -3530,7 +3560,6 @@ function <?php echo $jsToogleFiltrProcesuFunctionName; ?>(n) {
 				break;
 			}
 			case 'TYPESPECIALL_CELL': {
-sleep(1);// TODO: RMME
 				$id = V::get('ID', 0, $_REQUEST, 'int');
 				$col = V::get('col', '', $_REQUEST);
 				if ($id > 0 && !empty($col)) {
@@ -3541,7 +3570,6 @@ sleep(1);// TODO: RMME
 				break;
 			}
 			case 'MORE_FUNCTIONS_CELL': {
-sleep(1);// TODO: RMME
 				$this->sendAjaxResponseJson('ajaxMoreFunctionsCell', $_REQUEST);
 				break;
 			}
@@ -5034,10 +5062,10 @@ function fileListUpdateAjax<?php echo $this->_htmlID; ?>() {
 		//contentType: "application/json; charset=utf-8",
 		data: postData,
 		async: true,
-		success: function (data) {
+		success: function(data) {
 			fileListUpdate<?php echo $this->_htmlID; ?>(data);
 		},
-		error: function (jhr, textStatus, errorThrown) {
+		error: function(jhr, textStatus, errorThrown) {
 			if (priv.options.debug) console.log('request error: ', errorThrown, ' textStatus: ', textStatus);
 		}
 	});
@@ -5078,7 +5106,7 @@ function fileListUpdate<?php echo $this->_htmlID; ?>(fileListJson) {
 					//contentType: "application/json; charset=utf-8",
 					data: postData,
 					async: true,
-					success: function (data) {
+					success: function(data) {
 						if (data && data.type) {
 							if (data.type == 'SUCCESS') {
 								n.parents('tr').remove();
@@ -5091,7 +5119,7 @@ function fileListUpdate<?php echo $this->_htmlID; ?>(fileListJson) {
 							if (priv.options.debug) console.log('TODO: ??? data: ', data);
 						}
 					},
-					error: function (jhr, textStatus, errorThrown) {
+					error: function(jhr, textStatus, errorThrown) {
 						if (priv.options.debug) console.log('rm error: ', errorThrown, ' textStatus: ', textStatus);
 					}
 				});
@@ -5113,10 +5141,10 @@ function connTblListUpdateAjax<?php echo $this->_htmlID; ?>(connTblID) {
 		//contentType: "application/json; charset=utf-8",
 		data: postData,
 		async: true,
-		success: function (data) {
+		success: function(data) {
 			connTblListUpdate<?php echo $this->_htmlID; ?>(data);
 		},
-		error: function (jqXHR, textStatus, errorThrown) {
+		error: function(jqXHR, textStatus, errorThrown) {
 			var txt = jqXHR.responseText || 'Error';
 			jQuery('#FILES_CONN_TBLS_<?php echo $this->_htmlID; ?>').find('.files-list').html('<tr><td colspan="6"><div class="alert alert-danger">' + txt + '</div></td></tr>');
 			if (priv.options.debug) console.log('connTblListUpdateAjax error: ', errorThrown, ' textStatus: ', textStatus);
@@ -5204,11 +5232,11 @@ function fileListActions<?php echo $this->_htmlID; ?>() {
 }
 
 jQuery(document).ready(function(){
-	$('#FILES_TAB_<?php echo $this->_htmlID; ?> a').click(function (e) {
+	$('#FILES_TAB_<?php echo $this->_htmlID; ?> a').click(function(e) {
 		e.preventDefault();
 		$(this).tab('show');
 	})
-	.on('shown.bs.tab', function (e) {
+	.on('shown.bs.tab', function(e) {
 		var fileSource = $(e.target).data('toggle')
 			, frm = jQuery('#FILES_FRM_<?php echo $this->_htmlID; ?>').get(0);
 		if (frm['M_DIST_UPLOAD_SOURCE']) {
@@ -5831,13 +5859,95 @@ jQuery(document).ready(function(){
 
 	function ajaxMoreFunctionsCell($args) {// ajax task 'MORE_FUNCTIONS_CELL'
 		$id = V::get('ID', 0, $args, 'int');
-		if ($id <= 0) {
-			throw new HttpException("404", 404);
-		}
+		if ($id <= 0) throw new HttpException("404", 404);
 
 		$response = new stdClass();
 		$response->type = 'success';
-		$response->msg = 'TODO: L.' . __LINE__;
+		$response->msg = 'Funkcje';
+		$response->rowFunctions = [];
+
+		if(0){// TODO: fetch $totalMsgs from TableMsgs
+			$totalMsgs = 3;
+			$rowFunc = new stdClass();
+			$rowFunc->ico = 'glyphicon glyphicon-envelope';
+			$rowFunc->href = 'index.php?_route=TableMsgs&_task=tableRow&idTable=' . $this->_zasobID . '&idRow=' . $id;
+			$rowFunc->title = "Wiadomości ({$totalMsgs})";
+			$response->rowFunctions[] = $rowFunc;
+		}
+
+		if ('CRM_PROCES' == $this->_acl->getName()) {// TODO: mv to table gui xml or php class
+			$record = $this->_acl->getItem($id);
+
+			$wskazniki = ProcesHelper::get_wskazniki($id);
+			$connectedZasobyTotal = count($wskazniki);
+			$rowFunc = new stdClass();
+			$rowFunc->ico = 'glyphicon glyphicon-random';
+			$rowFunc->href = "index.php?MENU_INIT=PROCES_ADD_ZASOB&procesID={$id}";
+			$rowFunc->title = "Powiązane zasoby <span class=\"badge\">{$connectedZasobyTotal}</span>";
+			$response->rowFunctions[] = $rowFunc;
+		}
+
+		if ('CRM_LISTA_ZASOBOW' == $this->_acl->getName()) {// TODO: mv to table gui xml or php class
+			// index.php?MENU_INIT=ZASOB_OBOWIAZKI&id_zasob=22001
+			$record = $this->_acl->getItem($id);
+
+			$rowFunc = new stdClass();
+			$rowFunc->ico = 'glyphicon glyphicon-random';
+			$rowFunc->href = "index.php?MENU_INIT=ZASOB_OBOWIAZKI&id_zasob={$id}";
+			$rowFunc->title = "Powiązane procesy (OB)";
+			$response->rowFunctions[] = $rowFunc;
+
+			// index.php?MENU_INIT=ZASOB_EXTERNAL_IDS&id_zasob=22001
+			$rowFunc = new stdClass();
+			$rowFunc->ico = 'glyphicon glyphicon-random';
+			$rowFunc->href = "index.php?MENU_INIT=ZASOB_EXTERNAL_IDS&id_zasob={$id}";
+			$rowFunc->title = "Powiązane dane (IDS)";
+			$response->rowFunctions[] = $rowFunc;
+
+			$groupTypeList = array();
+			$groupTypeList[] = 'STANOWISKO';
+			$groupTypeList[] = 'PODMIOT';
+			$groupTypeList[] = 'DZIAL';
+			if (in_array($record->TYPE, $groupTypeList)) {
+				$rowFunc = new stdClass();
+				$rowFunc->ico = 'glyphicon glyphicon-retweet';
+				$rowFunc->href = "index.php?_route=Users&_task=syncGroup&idGroup={$id}";
+				$rowFunc->title = "Synchronizuj do LDAP";
+				$response->rowFunctions[] = $rowFunc;
+			}
+		}
+
+		if ('ADMIN_USERS' == $this->_acl->getName()) {// TODO: mv to table gui xml
+			$record = $this->_acl->getItem($id);
+			$isAllowedoReadUserLogin = false;
+			if ($this->_acl->canReadRecord($record)) {
+				$idFieldUserLogin = $this->_acl->getFieldIdByName('ADM_ACCOUNT');
+				if ($idFieldUserLogin) {
+					if ($this->_acl->isAllowed($idFieldUserLogin, 'R', $record)) {
+						$isAllowedoReadUserLogin = true;
+					}
+				}
+			}
+			if ($isAllowedoReadUserLogin) {
+				$rowFunc = new stdClass();
+				$rowFunc->ico = 'glyphicon glyphicon-user';
+				$rowFunc->href = 'index.php?_route=Users&_task=userGroups&usrLogin=' . $record->ADM_ACCOUNT;
+				$rowFunc->title = "Ustal stanowisko";
+				$response->rowFunctions[] = $rowFunc;
+
+				$rowFunc = new stdClass();
+				$rowFunc->ico = 'glyphicon glyphicon-retweet';
+				$rowFunc->href = 'index.php?_route=Users&_task=syncUser&usrLogin=' . $record->ADM_ACCOUNT;
+				$rowFunc->title = "Synchronizuj do LDAP";
+				$response->rowFunctions[] = $rowFunc;
+
+				$rowFunc = new stdClass();
+				$rowFunc->ico = 'glyphicon glyphicon-minus';
+				$rowFunc->href = 'index.php?MENU_INIT=USER_OCENA_PRACOWNIKA&usrLogin=' . $record->ADM_ACCOUNT;
+				$rowFunc->title = "Ocena pracownika";
+				$response->rowFunctions[] = $rowFunc;
+			}
+		}
 		return $response;
 	}