Просмотр исходного кода

add route Przypomnij with tasks and new ui

Piotr Labudda 10 лет назад
Родитель
Сommit
fa3b7c886a
2 измененных файлов с 835 добавлено и 12 удалено
  1. 11 12
      SE/se-lib/Przypomnij.php
  2. 824 0
      SE/se-lib/Route/Przypomnij.php

+ 11 - 12
SE/se-lib/Przypomnij.php

@@ -149,9 +149,7 @@ class Przypomnij {
 			$this->_data['proces'][$r->ID] = $r;
 		}
 		
-		/* @2015-09-20 todo - powiazac akcje na superedit-PRZYPOMNIJ.php - nie jest latwo - bindera
-		
-				$sqlAclFltrProblems = "
+		$sqlAclFltrProblems = "
 			and (probl.`A_ADM_COMPANY` in({$sqlUsrAclGroups})
 					or probl.`A_CLASSIFIED` in({$sqlUsrAclGroups})
 					or probl.`L_APPOITMENT_USER`='{$userLogin}'
@@ -170,24 +168,22 @@ class Przypomnij {
 
 			from `PROBLEMS` as probl
 			where probl.`A_STATUS` NOT IN ('OFF_HARD','DELETED')
+				and probl.`L_APPOITMENT_DATE`!=''
+				and probl.`L_APPOITMENT_USER`!=''
 				{$sqlAclFltrProblems}
 		";
 		$res = $db->query($sql);
 		while ($r = $db->fetch($res)) {
-			$r->M_DIST_DESC = htmlspecialchars($r->M_DIST_DESC);// TODO: fix bug in html a href inside M_DIST_DESC
-			$r->_task_type = 'problem';
+			$r->A_PROBLEM_DESC = htmlspecialchars($r->A_PROBLEM_DESC);
+			$r->_task_type = 'task';
 			$r->_show = false;
-			$r->_acl_proj_id = (int)$r->P_ID;
-			$r->_title = $r->M_DIST_DESC;
+			$r->_title = $r->A_PROBLEM_DESC;
 			$r->_type = $r->M_DIST_TYPE;
 			$r->_l_app = $r->L_APPOITMENT_USER;
 			$r->_l_app_date = $r->L_APPOITMENT_DATE;
-			$this->_data['problem'][$r->ID] = $r;
+			$this->_data['task'][$r->ID] = $r;
 		}
 
-		*/
-		
-		
 		$this->_fetchLAppUsers();
 	}
 
@@ -604,7 +600,7 @@ if(V::get('DBG_P', '', $_GET) > 2){echo'<pre style="max-height:200px;overflow:au
 		if (!isset($this->_tblIdCache[$type])) {
 			$this->_tblIdCache[$type] = null;
 
-			$allowedTypes = array('projekt', 'proces', 'koresp');
+			$allowedTypes = array('projekt', 'proces', 'koresp', 'task');
 			if (empty($type) || !in_array($type, $allowedTypes)) {
 				echo '<div class="alert alert-danger cls-line-' . __LINE__ . '">' . "Brak dostępu" . '</div>';
 				return null;
@@ -621,6 +617,9 @@ if(V::get('DBG_P', '', $_GET) > 2){echo'<pre style="max-height:200px;overflow:au
 				case 'proces':
 					$this->_tblIdCache[$type] = ProcesHelper::getZasobTableID('CRM_PROCES');
 					break;
+				case 'task':
+					$this->_tblIdCache[$type] = ProcesHelper::getZasobTableID('PROBLEMS');
+					break;
 				default:
 					echo '<div class="alert alert-danger cls-line-' . __LINE__ . '">' . "Brak dostępu" . '</div>';
 					return null;

+ 824 - 0
SE/se-lib/Route/Przypomnij.php

@@ -0,0 +1,824 @@
+<?php
+
+Lib::loadClass('RouteBase');
+Lib::loadClass('Przypomnij');
+Lib::loadClass('TypespecialVariable');
+
+class Route_Przypomnij extends RouteBase {
+
+	public $_model = null;
+	public $_selectedLogin = null;
+	public $_allowedUsers = null;
+
+	public function handleAuth() {
+		if (User::get('ADM_ADMIN_LEVEL') > 5) {
+			SE_Layout::gora();
+			SE_Layout::menu();
+			?>
+			<div class="container">
+				<div class="alert alert-danger">
+					Brak dostępu!
+				</div>
+			</div>
+			<?php
+			SE_Layout::dol();
+			exit;
+		}
+		if (!User::logged()) {
+			//throw new HttpException('Unauthorized', 401);
+			User::authByRequest();
+		}
+	}
+
+	public function defaultAction() {
+		SE_Layout::gora();
+		SE_Layout::menu();
+
+		try {
+			$this->_initArgs();
+		} catch (Exception $e) {
+			echo '<div class="container">';
+			SE_Layout::alert('danger', $e->getMessage());
+			echo '</div>';
+		}
+		$this->menu();
+		$this->printEvents();
+
+		SE_Layout::dol();
+	}
+
+	public function _initArgs() {
+		$this->getModel();
+		$this->getAllowedLoginList();
+		$this->getSelectedLogin();
+	}
+
+	public function getModel() {
+		if (null === $this->_model) {
+			$this->_model = new Przypomnij();
+			$this->_model->setRecurseLimit(3);// TODO: 10
+		}
+		return $this->_model;
+	}
+
+	public function getAllowedLoginList() {
+		if (null === $this->_allowedUsers) {
+			$przypomnij = $this->getModel();
+			$this->_allowedUsers = $przypomnij->getAllowedUsersList();
+		}
+		return $this->_allowedUsers;
+	}
+
+	public function getSelectedLogin() {
+		if (null === $this->_selectedLogin) {
+			$allowedLoginList = $this->getAllowedLoginList();
+			$this->_selectedLogin = isset($_GET['KTO'])? $_GET['KTO'] : '';
+			if (!empty($this->_selectedLogin)) {
+				if (!array_key_exists($this->_selectedLogin, $allowedLoginList)) {
+					$this->_selectedLogin = '';
+					throw new Exception("Brak danych - wybierz innego użytkownika");
+				}
+			}
+		}
+		return $this->_selectedLogin;
+	}
+
+	public function menu() {
+		$usrLogin = User::getLogin();
+		$selectedLogin = $this->getSelectedLogin();
+		$typeSpecialUserLogin = TypespecialVariable::getInstance(-1, '__USER_LOGIN');
+		?>
+<style type="text/css">
+	#przypomnij-menu .typepsecial .selectize-input { width:260px; padding:6px 12px; vertical-align:middle; }
+</style>
+<div id="przypomnij-menu" class="container" style="margin-top:8px;">
+	<form class="form-inline" role="search">
+		<?php if(V::get('DBG_P', '', $_GET)){echo'<input type="hidden" name="DBG_P" value="1">';} ?>
+		<input type="hidden" name="_route" value="Przypomnij">
+		<div class="form-group">
+			<?php
+				if ($typeSpecialUserLogin) {
+					$fldName = 'KTO';
+					$fldParams = array();
+					$fldParams['allowCreate'] = false;
+					$fldParams['ajaxDataUrlBase'] = "index.php?_route=Przypomnij&_task=typeSpecialUserLogin";
+					$fldParams['placeholder'] = 'Szukaj...';
+					//$fldParams['ajaxDataUrlBase'] .= "&DBG_TS=3";
+					echo $typeSpecialUserLogin->showFormItem($tblID = -1, $fldName, $selectedLogin, $fldParams);
+				} else {
+					// TODO: simple select by allowedUsers
+				}
+			?>
+		</div>
+		<button type="submit" class="btn btn-default">Pokaż</button>
+
+		<div class="btn-group" style="margin-left:20px;">
+			<a class="btn btn-link" href="index.php?_route=Przypomnij&KTO=<?php echo $usrLogin; ?>">Twoje (<?php echo $usrLogin; ?>)</a>
+		</div>
+
+		<div class="btn-group" style="margin-left:20px;">
+			<a class="btn btn-link" href="index.php?_route=Przypomnij">Wszyscy</a>
+		</div>
+	</form>
+</div>
+<?php
+	}
+
+	public function typeSpecialUserLoginAction() {
+		header("Content-type: application/json");
+		$typeSpecialUserId = TypespecialVariable::getInstance(-1, '__USER_LOGIN');
+		if (!$typeSpecialUserId) {
+			$jsonData = new stdClass();
+			$jsonData->message = "TypeSpecial '__USER_LOGIN' not exists";
+			echo json_encode($jsonData);
+			exit;
+		}
+
+		$query = V::get('q', '', $_REQUEST);
+		$rawRows = null;
+		$jsonData = array();
+		$queryParams = array();
+		$rows = $typeSpecialUserId->getValuesWithExports($query, $queryParams);
+		foreach ($rows as $kID => $vItem) {
+			$itemJson = new stdClass();
+			$itemJson->id = $vItem->id;
+			$itemJson->name = $vItem->param_out;
+			if (!empty($vItem->exports)) {
+				$itemJson->exports = $vItem->exports;
+			}
+			$jsonData[] = $itemJson;
+		}
+		echo json_encode($jsonData);
+	}
+
+	public function printEvents() {
+		$selectedLogin = $this->getSelectedLogin();
+		$przypomnij = $this->getModel();
+		$przypomnij->fetchData();
+		$przypomnij->setFltrUser($selectedLogin);
+
+		$tasks = $przypomnij->getTasksByDate();
+		DBG::_('DBG_P', true, "tasks", $tasks, __CLASS__, __FUNCTION__, __LINE__);
+		$usrGroupNames = User::getLdapGroupsNames();
+		foreach ($tasks as $id => $task) {
+			$tasks[$id]->_visible = true;
+			//@2015-05-17 - ograniczenie widzenia listy przypomnij dla obcych uzystkownikow,
+			if (
+				$task->A_CLASSIFIED != ''
+				and !(in_array($task->A_CLASSIFIED, $usrGroupNames))
+				and $task->A_ADM_COMPANY != ''
+				and !(in_array($task->A_ADM_COMPANY, $usrGroupNames))
+				// !($allowedUsers[$task->_l_app]) - to jest bez sensu - wystarczy widocznosc sprawy?
+			) {
+				$tasks[$id]->_visible = false;
+			}
+			$tasks[$id]->_l_app_class = $przypomnij->getTaskDateFltrType($task->_l_app_date);
+			$tasks[$id]->_idZasobTable = $przypomnij->getZasobIdByType($task->_task_type);
+		}
+
+		$filtersByType = new stdClass();
+		$filtersByType->title = "Filtr";
+		$filtersByType->icon = "filter";
+		$filtersByType->prefix = "type-";
+		$filtersByType->items = array();
+		$filtersByType->items[] = 'PROJEKT';
+		$filtersByType->items[] = 'KORESP';
+		$filtersByType->items[] = 'PROCES';
+		$filtersByType->items[] = 'TASK';
+		$filtersByType->isActive = array();
+		$filtersByType->isActive['PROJEKT'] = true;
+		$filtersByType->isActive['KORESP'] = true;
+		$filtersByType->isActive['PROCES'] = true;
+		$filtersByType->isActive['TASK'] = true;
+		$filtersByType->labels = array();
+		$filtersByType->labels['PROJEKT'] = 'projekty';
+		$filtersByType->labels['KORESP'] = 'koresp.';
+		$filtersByType->labels['PROCES'] = 'procesy';
+		$filtersByType->labels['TASK'] = 'zadania';
+		$filtersByType->itemTitles = array();
+		$filtersByType->itemTitles['KORESP'] = 'Korespondencja';
+
+		$dateFltrTypes = $przypomnij->getDateFltrTypes();
+		$filtersByDate = new stdClass();
+		$filtersByDate->title = "Data";
+		$filtersByDate->icon = "calendar";
+		$filtersByDate->prefix = "date-";
+		$filtersByDate->items = array();
+		$filtersByDate->items[] = 'PO_TERMINIE';
+		$filtersByDate->items[] = 'DZISIAJ';
+		$filtersByDate->items[] = 'W_CIAGU_7_DNI';
+		$filtersByDate->items[] = 'PO_7_DNIACH';
+		$filtersByDate->items[] = 'BRAK';
+		$filtersByDate->isActive = array();
+		$filtersByDate->isActive['PO_TERMINIE'] = true;
+		$filtersByDate->isActive['DZISIAJ'] = true;
+		$filtersByDate->isActive['W_CIAGU_7_DNI'] = true;
+		$filtersByDate->isActive['PO_7_DNIACH'] = false;
+		$filtersByDate->isActive['BRAK'] = false;
+		$filtersByDate->labels = array();
+		$filtersByDate->labels['PO_TERMINIE'] = 'po terminie';
+		$filtersByDate->labels['DZISIAJ'] = 'dzisiaj';
+		$filtersByDate->labels['W_CIAGU_7_DNI'] = 'w ciagu 7 dni';
+		$filtersByDate->labels['PO_7_DNIACH'] = 'po 7 dniach';
+		$filtersByDate->labels['BRAK'] = 'brak';
+		$filtersByDate->itemTitles = array();
+		$filtersByDate->itemTitles['KORESP'] = 'Korespondencja';
+		$filters = array();
+		$filters['type'] = $filtersByType;
+		$filters['date'] = $filtersByDate;
+?>
+<style type="text/css">
+.frm-przypomnij { width:96%; margin:0 auto 10px auto; table-layout:fixed; }
+
+.tbl-przypomnij { width:96%; margin:0 auto 10px auto; table-layout:fixed; }
+ .tbl-przypomnij td,
+ .tbl-przypomnij th { overflow:hidden; }
+ .tbl-przypomnij .l_app_date { white-space:nowrap; }
+ .tbl-przypomnij .date-PO_TERMINIE   .l_app_date { color:#FD4242; }
+ .tbl-przypomnij .date-DZISIAJ       .l_app_date { color:#34B934; }
+ .tbl-przypomnij .date-W_CIAGU_7_DNI .l_app_date { color:#C58B1F; }
+ .tbl-przypomnij .date-PO_7_DNIACH   .l_app_date { color:#87847D; }
+
+.use-filtr_only_stare tr.l-app-stare{display:none;}
+.fltr-hide_PROJEKT tr.type-PROJEKT {display:none;}
+.fltr-hide_KORESP  tr.type-KORESP  {display:none;}
+.fltr-hide_PROCES  tr.type-PROCES  {display:none;}
+.fltr-hide_TASK    tr.type-TASK    {display:none;}
+.fltr-hide_PO_TERMINIE   tr.date-PO_TERMINIE   {display:none;}
+.fltr-hide_DZISIAJ       tr.date-DZISIAJ       {display:none;}
+.fltr-hide_W_CIAGU_7_DNI tr.date-W_CIAGU_7_DNI {display:none;}
+.fltr-hide_PO_7_DNIACH   tr.date-PO_7_DNIACH   {display:none;}
+.fltr-hide_BRAK          tr.date-BRAK          {display:none;}
+
+.nobr {white-space:nowrap;}
+</style>
+<div id="przypomnij-widget"></div>
+<script>
+;(function($, window, document, undefined) {
+	var pluginName = 'Przypomnij',
+			defaults = {
+				filters: {},
+				tasks: [],
+				debug: false
+			};
+
+	function Plugin(element, options) {
+		this.element = element;
+
+		// jQuery has an extend method that merges the
+		// contents of two or more objects, storing the
+		// result in the first object. The first object
+		// is generally empty because we don't want to alter
+		// the default options for future instances of the plugin
+		this.options = $.extend({}, defaults, options);
+
+		this._defaults = defaults;
+		this._name = pluginName;
+
+		this._tasks = this.options.tasks || [];
+		this._filters = {};
+		this._filterNodes = {};
+		this._sortedTasks = {};
+		this._tableNode = undefined;
+		this._tbodyNode = undefined;
+		this._inlineEditNode = undefined;
+		this._filtersPanelNode = undefined;
+		this._statsPanelNode = undefined;
+		this._needRender = {
+			TableBody: true,
+		//	FiltersPanel: false,
+			StatsPanel: false
+		};
+
+		this.init();
+	}
+
+	Plugin.prototype.init = function() {
+		this.log('init', '<?php echo __LINE__; ?>', [this]);
+		this.initTasks();
+		this.initFilters();
+		this.initialRender();
+		this.initEvents();
+
+		this._tableNode.addClass('fltr-hide_PO_7_DNIACH fltr-hide_BRAK');// TODO: by setState / setFilters
+
+		this.render();// render from State
+	};
+
+	Plugin.prototype.initTasks = function() {
+		var self = this;
+		this._sortedTasks = {// by task._task_type
+			projekt: {},
+			koresp: {},
+			proces: {},
+			task: {},
+		};
+
+		$.each(this._tasks, function(index, value) {
+			var task = value;
+			if (!self._sortedTasks.hasOwnProperty(task._task_type)) {
+				self.log('unsupproted task type "'+task._task_type+'"', '<?php echo __LINE__; ?>', task);
+			} else {
+				self._sortedTasks[task._task_type][task.ID] = index;
+			}
+		});
+		this.log('initTasks end', '<?php echo __LINE__; ?>', [this._sortedTasks]);
+	};
+
+	Plugin.prototype.initFilters = function() {
+		var self = this;
+		this._filters = {
+			type: {},
+			date: {}
+		};
+		$.each(this.options.filters, function(fltrType, fltr) {
+			$.each(fltr.items, function(idx, itemName) {
+				self._filters[fltrType][itemName] = false;
+			});
+			$.each(fltr.isActive, function(itemName, isActive) {
+				self._filters[fltrType][itemName] = isActive;
+			});
+		});
+		this.log('initFilters end', '<?php echo __LINE__; ?>', [this._filters, this.options.filters]);
+	};
+
+	Plugin.prototype.render = function() {
+		var self = this;
+		this.log('render', '<?php echo __LINE__; ?>', {_needRender: this._needRender});
+		$.each(this._needRender, function(index, value) {
+			if (value) {
+				var renderMethodName = 'render' + index;
+				if ('function' == typeof self[renderMethodName]) {
+					self[renderMethodName](value);
+				} else {
+					self.log('render method "' + renderMethodName + '" not defined!', '<?php echo __LINE__; ?>');
+				}
+				self._needRender[index] = false;
+			}
+		});
+	};
+
+	Plugin.prototype.createTableHead = function() {
+		var theadNode = $('<thead></thead>'),
+				theadTrNode = $('<tr></tr>').appendTo(theadNode);
+		$('<th style="width:120px">Termin wykonania</th>').appendTo(theadTrNode);
+		$('<th style="width:20%">Opis działań do wykonania</th>').appendTo(theadTrNode);
+		$('<th style="width:190px">Typ rekordu / ID</th>').appendTo(theadTrNode);
+		$('<th>Firma powiąz. / adres / opis-temat</th>').appendTo(theadTrNode);
+		$('<th style="width:100px">Lokalizacja</th>').appendTo(theadTrNode);
+		return theadNode;
+	};
+
+	Plugin.prototype.renderTableBody = function(value) {
+		var self = this,
+				tbodyNodes = [];
+		$.each(this._tasks, function(index, task) {
+			var rowNode = $('<tr></tr>');
+			rowNode.attr('id', 'row-' + task._task_type + '-' + task.ID);
+			rowNode.addClass('type-' + task._task_type.toUpperCase());
+			rowNode.addClass(task._l_app_class);
+			if (!self.isTaskVisible(task)) {
+				$('<td colspan="5" style="display:none">pomin task '+task.ID+'/'+task._task_type+'/'+task._title+'</td>').appendTo(rowNode);
+			} else {
+				var colLappNode = $('<td></td>'),
+						colTaskNode = $('<td></td>'),
+						colTypeNode = $('<td></td>'),
+						colDescNode = $('<td></td>'),
+						colLocationNode = $('<td></td>')
+				;
+
+				{// colLappNode
+					colLappNode.addClass('l_app_date-edit_inline');
+					colLappNode.data('type', task._task_type);
+					colLappNode.data('rowid', task.ID);
+					$('<strong class="l_app_date">' + task._l_app_date + '</strong>').appendTo(colLappNode);
+					var lappUser = '<em class="label label-important">Nieprzypisany!</em>';
+					if (task._l_app) lappUser = '<em>' + task._l_app + '</em>';
+					$('<div class="l_app_user">' + lappUser + '</div>').appendTo(colLappNode);
+				}
+				{// colTaskNode
+					colTaskNode.addClass('l_app_info l_app_date-edit_inline');
+					colTaskNode.data('type', task._task_type);
+					colTaskNode.data('rowid', task.ID);
+					colTaskNode.text(task.L_APPOITMENT_INFO);
+				}
+				{// colTypeNode
+					var typeLinksNode = $('<h5></h5>').appendTo(colTypeNode);
+					$('<span class="label label-A_STATUS-' + task.A_STATUS + '">' + task.A_STATUS + '</span>').appendTo(colTypeNode);
+					if (task._type) $('<em>' + task._type + '</em>').appendTo(colTypeNode);
+					var editLink = $('<a target="_blank" title="Edytuj rekord"></a>').appendTo(typeLinksNode);
+					editLink.attr('href', 'index.php?MENU_INIT=VIEWTABLE_AJAX&ZASOB_ID=' + task._idZasobTable + '#EDIT/' + task.ID);
+					editLink.html('<i class="glyphicon glyphicon-pencil"></i>' + ' ' + task._task_type.toUpperCase() + ' ' + task.ID);
+					typeLinksNode.append(document.createTextNode(' '));
+					var filesLink = $('<a target="_blank" title="Pliki"></a>').appendTo(typeLinksNode);
+					filesLink.attr('href', 'index.php?MENU_INIT=VIEWTABLE_AJAX&ZASOB_ID=' + task._idZasobTable + '#FILES/' + task.ID);
+					filesLink.html('<i class="glyphicon glyphicon-folder-open"></i> pliki');
+				}
+				{// colDescNode
+					if ('projekt' == task._task_type && task.M_DISTRIBUTOR.length > 0) {
+						colDescNode.html('<strong>' + task.M_DISTRIBUTOR + '</strong><br>' + task._title);
+					} else {
+						colDescNode.html(task._title);
+					}
+				}
+				{// colLocationNode
+					if ('koresp' == task._task_type) {
+						colLocationNode.html('<em>' + task.K_LOKALIZACJA_OPIS + '</em>');
+					}
+				}
+
+				colLappNode.appendTo(rowNode);
+				colTaskNode.appendTo(rowNode);
+				colTypeNode.appendTo(rowNode);
+				colDescNode.appendTo(rowNode);
+				colLocationNode.appendTo(rowNode);
+			}
+			tbodyNodes.push(rowNode);
+		});
+		this._tbodyNode.html(tbodyNodes);
+	};
+
+	Plugin.prototype.initEvents = function() {
+		var self = this,
+				_inlineEditBox = this._inlineEditNode,
+				frmInlineEdit = _inlineEditBox.find('form');
+
+		frmInlineEdit.on('submit', function() {
+			var frmData = _inlineEditBox.find('form').serialize();
+			var task_rowid = frmInlineEdit.find('input[name=rowid]').val();
+			var task_type = frmInlineEdit.find('input[name=type]').val();
+			_inlineEditBox.find('.btn-save').hide();
+			_inlineEditBox.find('.inlineEditBox-cnt').html('<span class="loading-info"> loading ...</span>');
+			jQuery.ajax({
+				url: 'index.php?_route=Przypomnij&_task=ajaxSaveInlineEdit',
+				type: 'POST',
+				dataType: 'text',
+				data: frmData,
+				async: true,
+				success: function(data) {
+					self.log('_inlineEditBox submit ajax data', '<?php echo __LINE__; ?>', data);
+					_inlineEditBox.find('.inlineEditBox-cnt').html(data);
+					_inlineEditBox.find('.btn-save').hide();
+					var upNode = _inlineEditBox.find('.inlineEditBox-cnt').find('.EditAppDateInlineSave');
+					if (upNode) {
+						var newTask = {};
+						if (upNode.find('.l_app_user')) {
+							newTask.L_APPOITMENT_USER = upNode.find('.l_app_user').text();
+							newTask._l_app = newTask.L_APPOITMENT_USER;
+						}
+						if (upNode.find('.l_app_date')) {
+							newTask.L_APPOITMENT_DATE = upNode.find('.l_app_date').text();
+							newTask._l_app_date = newTask.L_APPOITMENT_DATE;
+						}
+						if (upNode.find('.l_app_info')) {
+							newTask.L_APPOITMENT_INFO = upNode.find('.l_app_info').text();
+						}
+						if (upNode.find('.date_fltr_type')) {
+							newTask._l_app_class = upNode.find('.date_fltr_type').text();
+						}
+						self.updateTask(task_type, task_rowid, newTask);
+					}
+				},
+				error: function(jhr, textStatus, errorThrown) {
+					//console.log('_inlineEditBox submit ajax error');
+				}
+			});
+
+			return false;
+		});
+
+		this._tbodyNode.on('dblclick', '.l_app_date-edit_inline', function(e){
+			var data = $(this).data();
+			// rowid: 2266, type: "projekt"
+
+			if (!data.type || !data.rowid) {
+				return false;
+			}
+
+			_inlineEditBox.modal();
+			_inlineEditBox.show();
+			_inlineEditBox.find('input[name=rowid]').val(data.rowid);
+			_inlineEditBox.find('input[name=type]').val(data.type);
+			_inlineEditBox.find('.inlineEditBox-cnt').html('<span class="loading-info"> loading ...</span>');
+
+			$.ajax({
+				url: 'index.php?_route=Przypomnij&_task=ajaxInlineEdit',
+				type: 'GET',
+				dataType: 'text',
+				data: data,
+				async: true,
+				success: function(data) {
+					_inlineEditBox.find('.inlineEditBox-cnt').html(data);
+					_inlineEditBox.find('.btn-save').show();
+
+					initDateTimePicker(_inlineEditBox);
+					_inlineEditBox.find('textarea').autosize();
+
+					var fld = _inlineEditBox.find('input[id^="f"]');
+					if (fld && !fld.hasClass('se_type-date')) {
+						fld.focus();
+
+						fld.keydown(function(event) {
+							if (event.which == 13) {
+								event.preventDefault();
+								_inlineEditBox.find('form').submit();
+							}
+						});
+					}
+				},
+				error: function(err) {
+					console.log('err', err);
+				}
+			});
+		});
+	};
+
+	Plugin.prototype.initialRender = function() {
+		this.log('initialRender', '<?php echo __LINE__; ?>');
+
+		this._filtersPanelNode = this.createFiltersPanelNode();
+		$(this.element).append(this._filtersPanelNode);
+
+		this._statsPanelNode = this.createStatsPanelNode();
+		$(this.element).append(this._statsPanelNode);
+
+		this._tableNode = $('<table></table>');
+		this._tableNode.addClass('tbl-przypomnij');
+		this._tableNode.addClass('table table-bordered table-hover');
+		this.createTableHead().appendTo(this._tableNode);
+		this._tbodyNode = $('<tbody></tbody>');
+		this._tbodyNode.appendTo(this._tableNode);
+		$(this.element).append(this._tableNode);
+
+		this._inlineEditNode = this.createInlineEditBox();
+		$(this.element).append(this._inlineEditNode);
+	};
+
+	Plugin.prototype.createFiltersPanelNode = function() {
+		var self = this,
+				filtersPanelNode = $('<div class="container" style="margin-top:8px;"></div>'),
+				groupNode,
+				btnNode,
+				typeFiltersNode = $('<div class="btn-group"></div>').appendTo(filtersPanelNode),// TODO: RMME
+				dateFiltersNode = $('<div class="btn-group"></div>').appendTo(filtersPanelNode)// TODO: RMME
+		;
+		$.each(this._filters, function(fltrType, fltrItems) {
+			self._filterNodes[fltrType] = {};
+			groupNode = $('<div class="btn-group"></div>').appendTo(filtersPanelNode);
+			var icon = self.options.filters[fltrType].icon;
+			btnNode = $('<button class="btn btn-default" title="Filtr"><i class="glyphicon glyphicon-' + icon + '"></i></button>');
+			btnNode.appendTo(groupNode);
+			$.each(fltrItems, function(itemName, isActive) {
+				btnNode = $('<button class="btn btn-default"></button>');
+				btnNode.data('type', fltrType);
+				btnNode.data('name', itemName);
+				if (self.options.filters[fltrType]['itemTitles'][itemName]) {
+					btnNode.attr('title', self.options.filters[fltrType]['itemTitles'][itemName]);
+				}
+				if (true === self._filters[fltrType][itemName]) {
+					btnNode.addClass('active');
+				}
+				btnNode.text(self.options.filters[fltrType]['labels'][itemName]);
+				//btnNode.html(self.options.filters[fltrType]['labels'][itemName] + ' <span class="badge" style="background-color: #aaa;">3</span>');// TODO: TEST badge
+				btnNode.appendTo(groupNode);
+				btnNode.on('click', function(e) {
+					self.onClickFilter(e);
+				});
+				self._filterNodes[fltrType][itemName] = btnNode;
+			});
+			btnNode = $('<button class="btn btn-default disabled" title="Kasuj filtr do ustawień domyślnych"><i class="glyphicon glyphicon-remove"></i></button>').appendTo(groupNode);
+			btnNode.on('click', function(e) {
+				self.onClickRestoreFilters(e, fltrType);
+			});
+			self._filterNodes[fltrType]['RESTORE_DEFAULT'] = btnNode;
+			filtersPanelNode.append(document.createTextNode(' '));
+		});
+		return filtersPanelNode;
+	};
+
+	Plugin.prototype.createStatsPanelNode = function() {
+		var statsPanelNode = $('<div class="container" style="margin-top:8px;margin-bottom:8px"></div>'),
+				self = this,
+				stats = {}
+		;
+		stats['projekt'] = 0;
+		stats['koresp'] = 0;
+		stats['proces'] = 0;
+		stats['task'] = 0;
+		this.log('createStatsPanelNode', '<?php echo __LINE__; ?>', [this._filters]);
+		$.each(this._tasks, function(idx, task) {
+			if (!stats.hasOwnProperty(task._task_type)) {
+				self.log('BUG stats has no property "'+task._task_type+'"', '<?php echo __LINE__; ?>', task);
+				return;
+			}
+			if (!self.isTaskVisible(task)) {
+				return;
+			}
+			var typeName = task._task_type.toUpperCase();
+			if (self._filters['type'].hasOwnProperty(typeName)
+					&& true === self._filters['type'][typeName]) {
+			} else {
+				return;
+			}
+			var hasActiveFilter = false;
+			$.each(self._filters['date'], function(itemName, isActive) {
+				if (isActive) {
+					if (task._l_app_class == 'date-' + itemName) {
+						hasActiveFilter = true;
+					}
+				}
+			});
+			if (hasActiveFilter) {
+				stats[task._task_type] += 1;
+			}
+		});
+		$('<span>Ilość pism: ' + stats['projekt'] + ', </span>').appendTo(statsPanelNode);
+		$('<span>ilość spraw: ' + stats['koresp'] + ', </span>').appendTo(statsPanelNode);
+		$('<span>ilość procesów: ' + stats['proces'] + ', </span>').appendTo(statsPanelNode);
+		$('<span>ilość zadań: ' + stats['task'] + '.</span>').appendTo(statsPanelNode);
+		if (!stats['projekt'] && !stats['koresp'] && !stats['proces'] && !stats['task']) {
+			$('<div class="alert alert-warning">Brak danych pasujących do wybranego filtra</div>').appendTo(statsPanelNode);
+		}
+		return statsPanelNode;
+	};
+
+	Plugin.prototype.onClickRestoreFilters = function(e, fltrType) {
+		var self = this,
+				n = $(e.target)
+		;
+		this.log('onClickRestoreFilters', '<?php echo __LINE__; ?>', {fltrType: fltrType});
+		$.each(this._filters[fltrType], function(itemName, isActive) {
+			self._filters[fltrType][itemName] = self.options.filters[fltrType]['isActive'][itemName];
+		});
+		n.blur();
+		this._afterUpdateFilters();
+	};
+
+	Plugin.prototype.onClickFilter = function(e) {
+		var n = $(e.target),
+				type = n.data('type'),
+				name = n.data('name')
+		;
+		this.log('onClickFilter', '<?php echo __LINE__; ?>', [n.data('type'), n.data('name'), n, e]);
+		if (!type || !name || undefined === this._filters[type][name]) return;
+		this._filters[type][name] = !this._filters[type][name];
+		n.blur();
+		this._afterUpdateFilters();
+	};
+
+	Plugin.prototype._afterUpdateFilters = function() {
+		var self = this;
+		this.log('_afterUpdateFilters', '<?php echo __LINE__; ?>');
+		$.each(this._filters, function(fltrType, fltrItems) {
+			var isDiffToDefault = false;
+			$.each(fltrItems, function(itemName, isActive) {
+				if (self.options.filters[fltrType]['isActive'][itemName] !== isActive) {
+					isDiffToDefault = true;
+				}
+				var n = self._filterNodes[fltrType][itemName];
+				if (isActive) {
+					n.addClass('active');
+					self._tableNode.removeClass('fltr-hide_' + itemName);
+				} else {
+					n.removeClass('active');
+					self._tableNode.addClass('fltr-hide_' + itemName);
+				}
+			});
+
+			var btnRestoreDefault = self._filterNodes[fltrType]['RESTORE_DEFAULT'];
+			if (isDiffToDefault) {
+				btnRestoreDefault.removeClass('disabled');
+			} else {
+				btnRestoreDefault.addClass('disabled');
+			}
+		});
+
+		this.renderStatsPanel();
+	};
+
+	Plugin.prototype.updateTask = function(task_type, task_rowid, newTask) {
+		this.log('updateTask', '<?php echo __LINE__; ?>', {task_type: task_type, ID: task_rowid, newTask: newTask});
+		var taskIdx,
+				task,
+				taskChanged = false
+		;
+		try {
+			taskIdx = this._sortedTasks[task_type][task_rowid];
+			task = this._tasks[taskIdx];
+			this.log('updateTask task', '<?php echo __LINE__; ?>', {task: task});
+			if (task) {
+				if (newTask.hasOwnProperty('L_APPOITMENT_INFO') && newTask.L_APPOITMENT_INFO != task.L_APPOITMENT_INFO) {
+					task.L_APPOITMENT_INFO = newTask.L_APPOITMENT_INFO;
+					taskChanged = true;
+				}
+				if (newTask.hasOwnProperty('L_APPOITMENT_DATE') && newTask.L_APPOITMENT_DATE != task.L_APPOITMENT_DATE) {
+					task.L_APPOITMENT_DATE = newTask.L_APPOITMENT_DATE;
+					taskChanged = true;
+				}
+				if (newTask.hasOwnProperty('_l_app_date') && newTask._l_app_date != task._l_app_date) {
+					task._l_app_date = newTask._l_app_date;
+					taskChanged = true;
+				}
+				if (newTask.hasOwnProperty('L_APPOITMENT_USER') && newTask.L_APPOITMENT_USER != task.L_APPOITMENT_USER) {
+					task.L_APPOITMENT_USER = newTask.L_APPOITMENT_USER;
+					taskChanged = true;
+				}
+				if (newTask.hasOwnProperty('_l_app') && newTask._l_app != task._l_app) {
+					task._l_app = newTask._l_app;
+					taskChanged = true;
+				}
+				if (newTask.hasOwnProperty('_l_app_class') && newTask._l_app_class != task._l_app_class) {
+					task._l_app_class = newTask._l_app_class;
+					taskChanged = true;
+				}
+				this.log('updateTask task taskChanged', '<?php echo __LINE__; ?>', {task: task, taskChanged: taskChanged, taskStored: this._tasks[taskIdx]});
+			}
+		} catch(e) {
+			this.log('error', '<?php echo __LINE__; ?>', e);
+		}
+
+		if (taskChanged) {
+			this._needRender['TableBody'] = taskIdx;
+			this._needRender['StatsPanel'] = true;
+			this.render();
+		}
+	};
+
+	Plugin.prototype.renderStatsPanel = function(value) {
+		var statsPanelNode = this.createStatsPanelNode();
+		this._statsPanelNode.replaceWith(statsPanelNode);
+		this._statsPanelNode = statsPanelNode;
+	};
+
+	Plugin.prototype.createInlineEditBox = function() {
+		var inlineEditBoxNode = $('<div class="inlineEditBox modal fade" role="dialog" aria-labelledby="przypomnijModalLabel" aria-hidden="true"></div>'),
+				modalDialog = $('<div class="modal-dialog"></div>').appendTo(inlineEditBoxNode),
+				modalContent = $('<div class="modal-content"></div>').appendTo(modalDialog),
+				form = $('<form style="margin:0;padding:0;"></form>').appendTo(modalContent),
+				modalHeader = $('<div class="modal-header"></div>').appendTo(form),
+				headCloseBtn = $('<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="glyphicon glyphicon-remove"></i></button>').appendTo(modalHeader),
+				headLabel = $('<h3 id="przypomnijModalLabel">Edytuj</h3>').appendTo(modalHeader),
+				modalBody = $('<div class="modal-body"></div>').appendTo(form),
+				fldRowId = $('<input type="hidden" name="rowid" value="">').appendTo(modalBody),
+				fldType = $('<input type="hidden" name="type" value="">').appendTo(modalBody),
+				inlineContent = $('<div class="inlineEditBox-cnt"></div>').appendTo(modalBody),
+				modalFooter = $('<div class="modal-footer"></div>').appendTo(form),
+				footerCloseBtn = $('<button class="btn" data-dismiss="modal" aria-hidden="true">Zamknij</button>').appendTo(modalFooter),
+				footerSubmitBtn = $('<input type="submit" value="Zapisz" class="btn btn-primary btn-save">').appendTo(modalFooter)
+		;
+		return inlineEditBoxNode;
+	};
+
+	Plugin.prototype.isTaskVisible = function(task) {
+		if (task._show !== true) {
+			return false;
+		}
+		if (task._visible !== true) {
+			return false;
+		}
+		return true;
+	};
+
+	Plugin.prototype.log = function(msg, code, variables) {
+		var code = code || 0,
+				variables = variables || undefined;
+		if (this.options.debug && console && 'function' == typeof console.log) {
+			console.log(this._name + '#' + code + ':' + msg, variables);
+		}
+	};
+
+	$.fn[pluginName] = function(options) {
+		return this.each(function() {
+			if (!$.data(this, 'plugin_' + pluginName)) {
+				$.data(this, 'plugin_' + pluginName,
+				new Plugin(this, options));
+			}
+		});
+	}
+})(jQuery, window, document);
+</script>
+<script>
+jQuery(document).ready(function() {
+	jQuery('#przypomnij-widget').Przypomnij({
+		debug: false,
+		filters: <?php echo json_encode($filters); ?>,
+		tasks: <?php echo json_encode($tasks); ?>
+	});
+});
+</script>
+<?php
+	}
+
+	public function ajaxInlineEditAction() {
+		// $_GET [rowid] => 2286, [type] => proces
+		$przypomnij = $this->getModel();
+		$przypomnij->sendAjaxEditAppDateInline();
+	}
+
+	public function ajaxSaveInlineEditAction() {
+		// $_GET [rowid] => 2286, [type] => proces, [fldId] => date
+		$przypomnij = $this->getModel();
+		$przypomnij->sendAjaxEditAppDateInlineSave();
+	}
+
+}