Browse Source

added create form for ant acl, exported edit route from TableAjax

Piotr Labudda 7 năm trước cách đây
mục cha
commit
9340c16a90

+ 53 - 1
SE/se-lib/AntAclBase.php

@@ -431,7 +431,7 @@ class AntAclBase extends Core_AclBase {
 		$fieldName = $field['name'];
 
 		switch ($taskPerm) {
-			case 'C': return false; // 'PERM_C'
+			case 'C': return $this->canCreateField($fieldName);
 			case 'R': return ($record) ? $this->canReadObjectField($fieldName, $record) : $this->canReadField($fieldName);
 			case 'W': return ($record) ? $this->canWriteObjectField($fieldName, $record) : $this->canWriteField($fieldName);
 			default: throw new Exception("Not Implemented isAllowed perm '{$taskPerm}'");
@@ -623,6 +623,58 @@ class AntAclBase extends Core_AclBase {
 	public function init($force = false) { }
 	public function isInitialized($force = false) { return true; }
 
+	public function addItem($itemTodo) {
+		if (is_object($itemTodo)) {
+			$itemTodo = (array)$itemTodo;
+		} else if (!is_array($itemTodo)) {
+			throw new HttpException('Item is not array', 400);
+		}
+
+		// from convertObjectFromUserInput - fixEmptyValueFromUser
+		$item = array();
+		$fields = $this->getFieldListByIdZasob();
+		foreach ($fields as $kID => $vFieldName) {
+			if (!$this->isAllowed($kID, 'C')) {
+				continue;
+			}
+			if (isset($itemTodo[$vFieldName])) {
+				$value = $itemTodo[$vFieldName];
+
+				if (empty($value) && strlen($value) == 0) {// fix bug in input type date and value="0000-00-00"
+					$value = $this->fixEmptyValueFromUser($kID);
+				}
+				$item[$vFieldName] = $value;
+			}
+		}
+
+		{// add DefaultAclGroup if no create perms ('C')
+			$defaultAclGroup = User::getDefaultAclGroup();
+			if ($defaultAclGroup) {
+				$permFields = array('A_ADM_COMPANY', 'A_CLASSIFIED');
+				foreach ($permFields as $permFldName) {
+					$permFldId = $this->getFieldIdByName($permFldName);
+					if (0 == $permFldId || !$this->isAllowed($permFldId, 'C')) {
+						$item[$permFldName] = $defaultAclGroup;
+					}
+				}
+			}
+		}
+
+		DBG::log($item, 'array', "insert \$item");
+		$idItem = DB::getPDO()->insert($this->getRootTableName(), array_merge($item, [
+			'A_RECORD_CREATE_DATE' => 'NOW()',
+			'A_RECORD_CREATE_AUTHOR' => User::getLogin(),
+		]));
+		if ($idItem) {
+			DB::getPDO()->insert($this->getRootTableName() . '_HIST', array_merge($item, [
+				'ID_USERS2' => $idItem,
+				'A_RECORD_CREATE_DATE' => 'NOW()',
+				'A_RECORD_CREATE_AUTHOR' => User::getLogin(),
+			]));
+		}
+		return $idItem;
+	}
+
 	public function updateItem($itemPatch) {
 		if (is_object($itemPatch)) {
 			$itemPatch = (array)$itemPatch;

+ 159 - 1
SE/se-lib/Route/ViewTableAjax.php

@@ -420,7 +420,123 @@ class Route_ViewTableAjax extends RouteBase {
 		Response::sendTryCatchJson(array($this, 'createFormJson'), $args = $_REQUEST);
 	}
 	public function createFormJson($args) { // namespace, _hash, _primaryKey
-		throw new Exception("TODO: ...");
+		$namespace = V::get('namespace', '', $args, 'word');
+		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
+		$acl = Core_AclHelper::getAclByNamespace($namespace);
+		$tbl = $this->getTableAjaxWidget($acl);
+
+		if (!Core_AclHelper::hasCreatePerms($acl)) {
+			return [
+				'type' => "success",
+				'msg' => "Dodaj nowy rekord",
+				'body' => [
+					'reactNode' => [ 'div', [ 'class' => "alert alert-danger" ], "Brak uprawnień do utworzenia nowego rekordu." ]
+				],
+			];
+			// throw new Exception("Brak uprawnień do utworzenia nowego rekordu.");
+		}
+		$fieldsList = array();
+		foreach ($acl->getFieldListByIdZasob() as $kID => $fieldName) {
+			if ($fieldName == 'ID') continue;
+			$field['name'] = $fieldName;
+			$field['opis'] = $acl->getFieldOpis($fieldName);
+			$field['label'] = $acl->getFieldLabel($fieldName);
+			if (empty($field['label'])) $field['label'] = str_replace('_', ' ', $fieldName);
+			$fieldsList[$kID] = $field;
+		}
+		$cols = array();
+		$forceFilterInit = array();
+		$defaultAclGroup = User::getDefaultAclGroup();
+		if ($defaultAclGroup) {
+			$forceFilterInit['A_ADM_COMPANY'] = $defaultAclGroup;
+			$forceFilterInit['A_CLASSIFIED'] = $defaultAclGroup;
+		}
+		foreach ($_GET as $k => $v) { // TODO: read from $args ?
+			if (strlen($k) > 4 && substr($k, 0, 3) == 'ff_' && !empty($v)) {// force filter prefix
+				$fldName = substr($k, 3);
+				$forceFilterInit[$fldName] = $v;
+			}
+		}
+		foreach ($fieldsList as $kID => $field) {
+			$defaultValue = '';
+			if (!empty($forceFilterInit[$field['name']])) {
+				$defaultValue = $forceFilterInit[$field['name']];
+			}
+			$cols[$kID] = V::get("f{$kID}", $cols[$kID], $_POST);
+		}
+		$tsValues = array();
+		$featureFunctions = [
+			// 'edit'  => [ 'href' => '#EDIT/{0}', 'ico' => 'glyphicon glyphicon-pencil', 'title' => "Edytuj rekord"],
+			'hist'  => [ 'href' => '#HIST/{0}', 'ico' => 'glyphicon glyphicon-book', 'title' => "Historia" ],
+			'files' => [ 'href' => '#FILES/{0}', 'ico' => 'glyphicon glyphicon-folder-open', 'title' => "Pliki" ],
+			// 'cp'    => [ 'href' => '#', 'ico' => 'glyphicon glyphicon-plus-sign', 'title' => "Kopiuj rekord", 'onclick' => 'return tableAjaxCopy({0});' ],
+			'msgs' => [ 'href' => "index.php?_route=TableMsgs&_task=tableRow&idTable=".$acl->getID()."&idRow={0}", 'ico' => 'glyphicon glyphicon-envelope', 'title' => "Wiadomości" ],
+		];
+		$jsFields = [];
+		$tabindex = 0;
+		foreach ($fieldsList as $kID => $vCol) {
+			$fieldName = $vCol['name'];
+			DBG::log(['$fieldName'=>$fieldName, 'canCreate'=>$acl->canCreateField($fieldName)], 'array', "form field");
+			if ($acl->canCreateField($fieldName)) {
+				DBG::log("editFormJson::field({$fieldName})");
+				$fieldParams = [ 'appendBack' => true, 'tabindex' => (++$tabindex), 'maxGrid' => 8 ];
+				if (!empty($tsValues[$kID])) $fieldParams['typespecialValue'] = $tsValues[$kID];
+
+				$jsFields[] = [ 'div', [ 'class' => "form-group" ], [
+					[ 'label', [ 'class' => "control-label", 'for' => "f{$kID}" ], [
+						[ 'span', [ 'style' => ['padding-right'=>'4px'] ], $vCol['label'] ],
+						[ 'i', [ 'class' => "glyphicon glyphicon-info-sign frm-help", 'data-toggle' => "popover", 'data-trigger' => "hover", 'title' => "", 'data-content' => htmlspecialchars($vCol['opis']), 'data-original-title' => "[{$kID}] {$fieldName}" ] ],
+					] ],
+					[ 'div', [ 'class' => "" ], [
+						UI::hGetFormItem($acl, $fieldName, 'C', $kID, "f{$kID}", $cols[$kID], $fieldParams),
+					] ]
+				] ];
+			// } else {
+			// 	$jsFields[] = [ 'div', [ 'class' => "form-group" ], [
+			// 		"TODO: SKIP field ({$fieldName}) - ! canWriteObjectField && ! canReadObjectField"
+			// 	]];
+			}
+		}
+		$jsFields[] = [ 'div', [ 'class' => "form-group" ], [
+			[ 'div', [ 'class' => "" ], [
+				['button', [ 'type' => "submit", 'class' => "btn btn-primary", 'tabindex' => ++$tabindex ], "Zapisz" ]
+			] ]
+		] ];
+
+		$tblLabel = $acl->getNamespace();
+		if ('default_db' == $acl->getSourceName()) {
+			$tblLabel = array();
+			$zasobObj = ProcesHelper::getZasobTableInfo($acl->getID());
+			if (!$zasobObj) throw new Exception("Zasob TABELA ID=" . $acl->getID() . " nie istnieje");
+			if (!empty($zasobObj->DESC_PL)) $tblLabel []= $zasobObj->DESC_PL;
+			if (!empty($zasobObj->OPIS))    $tblLabel []= $zasobObj->OPIS;
+			$tblLabel = implode(" - ", $tblLabel);
+		}
+		$syncUrl = Request::getPathUri() . 'index.php?_route=ViewTableAjax&namespace=' . $acl->getNamespace();
+
+		$jsGui = [
+			'reactNode' => [ 'div', [ 'class' => "container AjaxFrmHorizontalEdit", 'style' => [ "max-width" => "940px" ] ], [
+				[ 'h4', [ 'style' => [ "padding-bottom" => "3px", "border-bottom" => "1px solid #ddd" ] ], [
+					"Dodaj nowy rekord",
+				] ],
+				[ 'P5UI__FeatureCreateForm', [
+					'class' => "", 'action' => "", 'method' => "post",
+					'id' => "CREATE_FRM_{$this->_htmlID}", // TODO: rm - use React nodes // TODO: $this->_htmlID not exists!
+					'ajaxSaveUrl' => "{$syncUrl}&_task=createSaveAjax", // TODO:? &_hash={$this->_htmlID}
+					'ajaxSaveLegacyUrl' => "{$syncUrl}&_task=createSaveLegacy", // TODO: Legacy RM
+					'namespace' => $acl->getNamespace(),
+					'tableLabelHtml' => $tblLabel,
+					'_htmlID' => $acl->getName(),
+				], [
+					[ 'fieldset', [ 'style' => [ "padding-bottom" => "100px" ] ], $jsFields ] // fieldset
+				] ] // form
+			] ] // .container
+		];
+		return [
+			'type' => "success",
+			'msg' => "Dodaj nowy rekord",
+			'body' => $jsGui, // TODO: action for GUI: array to render by function h, js to trigger
+		];
 	}
 	public function createSaveAjaxAction() {
 		Response::sendTryCatchJson(array($this, 'createSaveAjax'), $args = 'JSON_FROM_REQUEST_BODY');
@@ -428,6 +544,48 @@ class Route_ViewTableAjax extends RouteBase {
 	public function createSaveAjax($args) {
 		throw new Exception("TODO: ...");
 	}
+	public function createSaveLegacyAction() { // TODO: Legacy RM
+		$args = [
+			'namespace' => V::get('namespace', '', $_GET),
+			'body' => Request::getRequestJson(),
+		];
+		DBG::log($args, 'array', 'createSaveLegacyAction');
+		Response::sendTryCatchJson(array($this, 'createSaveLegacy'), $args);
+	}
+	public function createSaveLegacy($args) { // TODO: Legacy RM
+		$namespace = V::get('namespace', '', $args, 'word');
+		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
+		$body = V::get('body', null, $args);
+		if (!$body) throw new HttpException("Bad Request - missing body", 400);
+		$acl = Core_AclHelper::getAclByNamespace($namespace);
+		$tbl = $this->getTableAjaxWidget($acl);
+		DBG::log($args, 'array', "ajaxCreateSave");
+		$createdId = null;
+		try {
+			$item = $acl->convertObjectFromUserInput($body, $type = 'array_by_id', $prefix = 'f');
+			$createdId = $acl->addItem($item);
+			if ($createdId) {
+				return [
+					'type' => 'success',
+					'msg' => "Utworzono pomyślnie rekord nr {$createdId}",
+					'id' => $createdId,
+					'record' => $acl->buildQuery([])->getItem($createdId),
+				];
+			}
+			else {
+				return [
+					'type' => 'error',
+					'msg' => "Nie udało się utworzyć nowego rekordu!",
+				];
+			}
+		}
+		catch (Exception $e) {
+			return [
+				'type' => 'error',
+				'msg' => $e->getMessage(),
+			];
+		}
+	}
 
 	public function editFormAction() { // TODO: not used - moved to editFormJsonAction
 		try {

+ 11 - 54
SE/se-lib/TableAjax.php

@@ -3493,7 +3493,13 @@ class TableAjax extends ViewAjax {
 		'FIRCE_FILER_INIT' => $forceFilterInit,
 		'FUNCTION_CREATE_ROUTE' => "TableAjax__CREATE_Route",
 		'URL_CREATE_FORM_AJAX' => "{$this->syncUrl}&_hash={$this->_htmlID}&_task=createFormJson",
-		'URL_CREATE_FORM_LEGACY_HTML' => "index.php?_route=ViewTableAjax&_task=createForm&namespace=" . $acl->getNamespace() . "&_hash={$this->_htmlID}",
+	]);
+	UI::inlineJS(__FILE__ . '.edit.js', [
+		'TABLE_AJAX_NODE_ID' => $this->_htmlID,
+		'TABLE_AJAX_LABEL' => $this->getLabelHtml(),
+		'NAMESPACE' => $acl->getNamespace(),
+		'FUNCTION_EDIT_ROUTE' => "TableAjax__EDIT_Route",
+		'URL_EDIT_FORM_AJAX' => "{$this->syncUrl}&_hash={$this->_htmlID}&_task=editFormJson&_primaryKey=",
 	]);
 
 	$fltrs = (method_exists($acl, 'getSpecialFilters')) ? $acl->getSpecialFilters() : null;
@@ -3503,6 +3509,7 @@ class TableAjax extends ViewAjax {
 var TABLE_AJAX_NODE_ID = '<?= $this->_htmlID; ?>';
 var NAMESPACE = '<?= $acl->getNamespace(); ?>';
 var FUNCTION_HIST_ROUTE = window['TableAjax__HIST_Route'];
+var FUNCTION_EDIT_ROUTE = window['TableAjax__EDIT_Route'];
 var URL_LOAD_AJAX_BASE = '<?= $this->syncUrl; ?>&_hash=<?= $this->_htmlID; ?>&_task=loadDataAjax';
 var URL_USER_TABLE_FILTER = '<?= ($this->useUserTableFilter) ? $this->useUserTableFilter : ''; ?>';
 var FILER_INIT = <?= json_encode($filterInit); ?>;
@@ -3554,58 +3561,7 @@ jQuery(document).ready(function(){
 		specialFilterFunctions: <?= $jsonSpecialFilters; ?>,
 		router: function() {
 			var routes = {
-				EDIT: function(args) {
-					var recordID = args;
-					if (typeof args == 'object') {
-						recordID = args.shift();
-						recordID = parseInt(recordID);
-					}
-					if (typeof recordID !== 'number' || recordID <= 0) {
-						// TODO: msg
-						return false;
-					}
-					var cont = jQuery('#<?php echo $this->_htmlID; ?>').parent();
-					cont.hide();
-
-					// remove previous task content
-					var taskCnt = jQuery('#<?php echo $this->_htmlID; ?>_task');
-					taskCnt.parent().remove();
-					taskCnt.remove();
-
-					var taskCont = jQuery('<div class="AjaxTableCont"></div>').insertBefore(cont);
-					jQuery('<ul class="breadcrumb">' +
-						'<li><a href="#" onclick="return tableAjaxBackToTable();"><?php echo $this->getLabelHtml(); ?></a></li>' +
-						'<li class="active">Edytuj rekord</li>' +
-					'</ul>').appendTo(taskCont);
-					taskCnt = jQuery('<div id="<?php echo $this->_htmlID . '_task'; ?>" class="AjaxTableTaskCnt AjaxTable-loading"></div>').appendTo(taskCont);
-					jQuery('<span class="loading-info"> loading ...</span>').appendTo(taskCnt);
-
-					window.fetch('<?= $this->syncUrl; ?>&_hash=<?= $this->_htmlID; ?>&_task=editFormJson&_primaryKey=' + recordID, {
-						method: 'GET',
-						credentials: 'same-origin',
-					}).then(function(response) {
-						return response.json()
-					}).then(function __route_edit_payload(payload) {
-						taskCnt.removeClass('AjaxTable-loading');
-						// console.log('editFormJson :: payload', payload)
-						if ('success' == payload.type) {
-							var node = document.createElement('div')
-							taskCnt.get(0).appendChild(node)
-							p5UI__buildDom(payload.body.reactNode, node)
-							initDateTimePicker(jQuery(node));
-							// console.log('editFormJson :: dom loaded - TODO: add action on save - P5UI__FeatureEditForm')
-						} else {
-							console.log('editFormJson :: ERROR payload', payload)
-						}
-					}).catch(function __route_edit_catch(e) {
-						taskCnt.removeClass('AjaxTable-loading');
-						console.log('editFormJson :: ERROR', e)
-						p5UI__notifyAjaxCallback({
-							type: 'error',
-							msg: 'Request error ' + e
-						});
-					})
-				},
+				EDIT: FUNCTION_EDIT_ROUTE,
 				HIST: FUNCTION_HIST_ROUTE,
 				FILES: function tableAjaxFiles(args) {
 					var recordID = args;
@@ -4523,6 +4479,7 @@ jQuery(document).ready(function(){
 	}
 
 	private function ajaxCreateSave($args) {
+		DBG::log($args, 'array', "ajaxCreateSave");
 		$acl = $this->_acl;
 		$response = new stdClass();
 		$createdId = null;
@@ -5819,7 +5776,7 @@ jQuery(document).ready(function(){
 		return $response;
 	}
 
-	private function sendAjaxResponseJson($method, $args) {
+	public function sendAjaxResponseJson($method, $args) {
 		try {
 			$response = $this->{$method}($args);
 		}

+ 23 - 42
SE/se-lib/TableAjax.php.create.js

@@ -5,7 +5,6 @@ if ('undefined' === typeof NAMESPACE) throw "Missing NAMESPACE";
 if ('undefined' === typeof FIRCE_FILER_INIT) throw "Missing FIRCE_FILER_INIT";
 if ('undefined' === typeof FUNCTION_CREATE_ROUTE) throw "Missing FUNCTION_CREATE_ROUTE";
 if ('undefined' === typeof URL_CREATE_FORM_AJAX) throw "Missing URL_CREATE_FORM_AJAX";
-if ('undefined' === typeof URL_CREATE_FORM_LEGACY_HTML) throw "Missing URL_CREATE_FORM_LEGACY_HTML";
 
 function TableAjax__CREATE_Route() {
 	var cont = jQuery('#' + TABLE_AJAX_NODE_ID).parent();
@@ -32,48 +31,30 @@ function TableAjax__CREATE_Route() {
 		});
 	}
 
-	// TODO: replace jQuery.ajax
-	// window.fetch(URL_CREATE_FORM_AJAX, {
-	// 	method: 'GET',
-	// 	credentials: 'same-origin',
-	// }).then(function(response) {
-	// 	return response.json()
-	// }).then(function __route_edit_payload(payload) {
-	// 	taskCnt.removeClass('AjaxTable-loading');
-	// 	// console.log('editFormJson :: payload', payload)
-	// 	if ('success' == payload.type) {
-	// 		var node = document.createElement('div')
-	// 		taskCnt.get(0).appendChild(node)
-	// 		p5UI__buildDom(payload.body.reactNode, node)
-	// 		initDateTimePicker(jQuery(node));
-	// 		// console.log('editFormJson :: dom loaded - TODO: add action on save - P5UI__FeatureEditForm')
-	// 	} else {
-	// 		console.log('editFormJson :: ERROR payload', payload)
-	// 	}
-	// }).catch(function __route_edit_catch(e) {
-	// 	taskCnt.removeClass('AjaxTable-loading');
-	// 	console.log('editFormJson :: ERROR', e)
-	// 	p5UI__notifyAjaxCallback({
-	// 		type: 'error',
-	// 		msg: 'Request error ' + e
-	// 	});
-	// });
-
-	jQuery.ajax({
-		url: URL_CREATE_FORM_LEGACY_HTML,
-		type: 'GET',
-		dataType: 'text',
-		data: reqData,
-		async: true,
-		success: function(data) {
-			taskCnt.removeClass('AjaxTable-loading');
-			jQuery(data).appendTo(taskCnt);
-
-			initDateTimePicker(taskCnt);
-		},
-		error: function(err) {
-			taskCnt.removeClass('AjaxTable-loading');
+	window.fetch(URL_CREATE_FORM_AJAX, {
+		method: 'GET',
+		credentials: 'same-origin',
+	}).then(function(response) {
+		return response.json()
+	}).then(function __route_create_payload(payload) {
+		taskCnt.removeClass('AjaxTable-loading');
+		// console.log('editFormJson :: payload', payload)
+		if ('success' == payload.type) {
+			var node = document.createElement('div')
+			taskCnt.get(0).appendChild(node)
+			p5UI__buildDom(payload.body.reactNode, node)
+			initDateTimePicker(jQuery(node));
+			// console.log('editFormJson :: dom loaded - TODO: add action on save - P5UI__FeatureEditForm')
+		} else {
+			console.log('createFormJson :: ERROR payload', payload)
 		}
+	}).catch(function __route_create_catch(e) {
+		taskCnt.removeClass('AjaxTable-loading');
+		console.log('createFormJson :: ERROR', e)
+		p5UI__notifyAjaxCallback({
+			type: 'error',
+			msg: 'Request error ' + e
+		});
 	});
 }
 

+ 60 - 0
SE/se-lib/TableAjax.php.edit.js

@@ -0,0 +1,60 @@
+// @require variables:
+if ('undefined' === typeof TABLE_AJAX_NODE_ID) throw "Missing TABLE_AJAX_NODE_ID"; // $this->_htmlID,
+if ('undefined' === typeof TABLE_AJAX_LABEL) throw "Missing TABLE_AJAX_LABEL"; // this->getLabelHtml()
+if ('undefined' === typeof FUNCTION_EDIT_ROUTE) throw "Missing FUNCTION_EDIT_ROUTE";
+if ('undefined' === typeof URL_EDIT_FORM_AJAX) throw "Missing URL_EDIT_FORM_AJAX";
+
+function TableAjax__EDIT_Route(args) {
+	var recordID = args;
+	if (typeof args == 'object') {
+		recordID = args.shift();
+		recordID = parseInt(recordID);
+	}
+	if (typeof recordID !== 'number' || recordID <= 0) {
+		// TODO: msg
+		return false;
+	}
+	var cont = jQuery('#' + TABLE_AJAX_NODE_ID).parent();
+	cont.hide();
+
+	// remove previous task content
+	var taskCnt = jQuery('#'+TABLE_AJAX_NODE_ID+'_task');
+	taskCnt.parent().remove();
+	taskCnt.remove();
+
+	var taskCont = jQuery('<div class="AjaxTableCont"></div>').insertBefore(cont);
+	jQuery('<ul class="breadcrumb">' +
+		'<li><a href="#" onclick="return tableAjaxBackToTable();">' + TABLE_AJAX_LABEL + '</a></li>' +
+		'<li class="active">Edytuj rekord</li>' +
+	'</ul>').appendTo(taskCont);
+	taskCnt = jQuery('<div id="' + TABLE_AJAX_NODE_ID + '_task" class="AjaxTableTaskCnt AjaxTable-loading"></div>').appendTo(taskCont);
+	jQuery('<span class="loading-info"> loading ...</span>').appendTo(taskCnt);
+
+	window.fetch(URL_EDIT_FORM_AJAX + recordID, {
+		method: 'GET',
+		credentials: 'same-origin',
+	}).then(function(response) {
+		return response.json()
+	}).then(function __route_edit_payload(payload) {
+		taskCnt.removeClass('AjaxTable-loading');
+		// console.log('editFormJson :: payload', payload)
+		if ('success' == payload.type) {
+			var node = document.createElement('div')
+			taskCnt.get(0).appendChild(node)
+			p5UI__buildDom(payload.body.reactNode, node)
+			initDateTimePicker(jQuery(node));
+			// console.log('editFormJson :: dom loaded - TODO: add action on save - P5UI__FeatureEditForm')
+		} else {
+			console.log('editFormJson :: ERROR payload', payload)
+		}
+	}).catch(function __route_edit_catch(e) {
+		taskCnt.removeClass('AjaxTable-loading');
+		console.log('editFormJson :: ERROR', e)
+		p5UI__notifyAjaxCallback({
+			type: 'error',
+			msg: 'Request error ' + e
+		});
+	})
+}
+
+global[FUNCTION_EDIT_ROUTE] = TableAjax__EDIT_Route

+ 1 - 0
SE/se-lib/UI.php

@@ -462,6 +462,7 @@ class UI {
 			switch ($taskPerm) {
 				case 'R': return "Brak uprawnień do odczytu";
 				case 'W': return "Brak uprawnień do zapisu";
+				case 'C': return "Brak uprawnień";
 				default: return "Brak uprawnień do tego pola ({$taskPerm})";
 			}
 		}

+ 152 - 0
SE/static/p5UI/buildDom.js

@@ -190,6 +190,158 @@
 	})
 	global.p5VendorJs['P5UI__FeatureEditForm'] = P5UI__FeatureEditForm
 
+	var P5UI__FeatureCreateForm = createReactClass({
+		componentDidMount: function () {
+			if(DBG)console.warn('P5UI__FeatureCreateForm::componentDidMount this.rootNode', this.rootNode)
+			jQuery(this.rootNode).find('textarea').autosize();
+			jQuery(this.rootNode).find('.frm-help').popover({trigger:'hover'});
+			jQuery(this.rootNode).find('.show-last-value input').on('input', function(e) {
+				var input, btn, btnIco;
+				input = jQuery(e.target);
+				btn = input.next('.button-appendBack');
+				btnIco = btn.find('.glyphicon');
+				if (btn.attr('title') != input.val()) {
+					btnIco.show();
+				} else {
+					btnIco.hide();
+				}
+			});
+			jQuery(this.rootNode).find('.show-last-value').find('.button-appendBack').on('click', function(e) {
+				var input, btn, btnIco;
+				btn = jQuery(this);
+				btnIco = btn.find('.glyphicon');
+				input = btn.prev();
+				if (input.is('input')) {
+					if (btn.attr('title') != input.val()) {
+						input.val(btn.attr('title'));
+						btnIco.hide();
+					}
+				}
+			});
+		},
+		submit: function (e) {
+			if(DBG)console.warn('P5UI__FeatureCreateForm::submit this.rootNode', this.rootNode)
+			e.preventDefault()
+
+			var formData = {};
+			jQuery(this.rootNode).serializeArray().map(function(i) { formData[i.name] = i.value; });// TODO: edit Widget - send only updated fields
+			if(DBG)console.log('P5UI__FeatureCreateForm::submit formData', formData);
+
+			var taskContLast = jQuery('#' + this.props._htmlID + '_task'),
+				taskCont = taskContLast.parent();
+			taskContLast.fadeOut('slow');
+			var taskCnt = jQuery('<div id="' + this.props._htmlID + '_task" class="AjaxTableTaskCnt AjaxTable-loading"></div>').appendTo(taskCont);
+			jQuery('<div class="alert alert-danger"><div style="padding:0 0 0 20px; background:url(./icon/loading.gif) no-repeat left top;"> save ... </div></div>').appendTo(taskCnt);
+
+			function notifyAjaxCallback(data) {
+				var notify = {}, outMsg = '';
+				notify.type = (data && data.type)? data.type : '';
+				notify.msg = (data && data.msg)? data.msg : '';
+				switch (notify.type) {
+					case 'success':
+						if (!notify.msg) notify.msg = 'OK';
+						break;
+					case 'info':
+						if (!notify.msg) notify.msg = '';
+						break;
+					case 'error':
+						if (!notify.msg) notify.msg = 'Wystąpiły błędy';
+						break;
+					case 'warning':
+						notify.type = 'warn';
+						if (!notify.msg) notify.msg = 'Wystąpiły błędy';
+						break;
+					default:
+						notify.msg = 'Nieznany błąd';
+						if (data && data.errorCode) notify.msg += ' ' + data.errorCode;
+						notify.type = '';
+				}
+				jQuery.notify(notify.msg, notify.type);
+				var alertType = ('error' == data.type) ? 'danger' : data.type;
+				outMsg = '<div class="alert alert-' + alertType + '">' + notify.msg + '</div>';
+				return outMsg;
+			}
+
+			var tableLabelHtml = this.props.tableLabelHtml;
+			global.fetch(this.props.ajaxSaveLegacyUrl, {
+				headers: {
+					'Content-Type': 'application/json'
+				},
+				method: 'POST',
+				credentials: 'same-origin',
+				body: JSON.stringify(formData),
+			}).then(function (response) {
+				return response.json()
+			}).then(function (data) {
+				taskCnt.removeClass('AjaxTable-loading');
+				taskCnt.empty();
+				if(DBG)console.log('P5UI__FeatureCreateForm:: data: ', data)
+				if ('success' === data.type) {
+					var msg = 'OK';
+					if (data.id && data.id > 0) msg = 'Utworzono pomyślnie rekord: ID = ' + data.id;
+					else if (data.msg) msg = data.msg;
+					var out = '<div class="container">';
+					out += '<div class="alert alert-success">' + msg + '</div>';
+					out += '<div class="breadcrumb">' +
+							' <a href="#" onclick="return tableAjaxBackToTable();" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-arrow-left"></i> Wróć do tabeli ' + tableLabelHtml + '</a>' +
+							' <a href="#EDIT/' + data.id + '" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-pencil"></i> Edytuj rekord ' + data.id + '</a>' +
+							' <a href="#CREATE/' + Math.random(1).toString().substr(2) + '" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-plus"></i> Dodaj nowy rekord</a></li>' +
+						'</div>';
+					out += '</div>';
+					jQuery(out).appendTo(taskCnt);
+				} else {
+					var msg = (data.msg) ? data.msg : "Nieznany błąd!";
+					var out = '<div class="container">' +
+							'<div class="alert alert-danger">' +
+								'<h4>Wystąpiły błędy!</h4>' + msg +
+							'</div>';
+					out += '<div class="breadcrumb">' +
+								' <a class="create-fix" href="#CREATE/' + Math.random(1).toString().substr(2) + '" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-arrow-left"></i> Wróć do formularza i popraw dane</a></li>' +
+							'</div>' +
+						'</div>';
+					jQuery(out).appendTo(taskCnt);
+					var taskContLastNode = taskContLast
+						, taskCntNode = taskCnt;
+					taskCnt.find('.create-fix').click(function(){
+						taskCntNode.remove();
+						taskContLastNode.fadeIn('slow');
+						return false;
+					});
+				}
+			}).catch(function (e) {
+				taskCnt.removeClass('AjaxTable-loading');
+				taskCnt.empty();
+				var out = '<div class="container">' +
+						'<div class="alert alert-danger">' +
+							'<h4>Wystąpiły błędy!</h4>' + e +
+						'</div>';
+				out += '<div class="breadcrumb">' +
+							' <a class="create-fix" href="#CREATE/' + Math.random(1).toString().substr(2) + '" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-arrow-left"></i> Wróć do formularza i popraw dane</a></li>' +
+						'</div>' +
+					'</div>';
+				jQuery(out).appendTo(taskCnt);
+				var taskContLastNode = taskContLast
+					, taskCntNode = taskCnt;
+				taskCnt.find('.create-fix').click(function(){
+					taskCntNode.remove();
+					taskContLastNode.fadeIn('slow');
+					return false;
+				});
+				if(DBG)console.log('P5UI__FeatureCreateForm:: e: ', e)
+			});
+		},
+		render: function () {
+			if(DBG)console.warn('P5UI__FeatureCreateForm::render this.props', this.props)
+			var formProps = Object.assign({}, this.props)
+			delete formProps.children
+			return h('form', Object.assign(formProps, {
+				ref: function (node) { this.rootNode = node; }.bind(this),
+				onSubmit: this.submit.bind(this)
+			}), this.props.children)
+		}
+	})
+	global.p5VendorJs['P5UI__FeatureCreateForm'] = P5UI__FeatureCreateForm
+
 	var P5UI__Typespecial = createReactClass({
 		componentDidMount: function () {
 			if(DBG)console.log('TS::componentDidMount (['+this.props.idField+'] '+this.props.fieldNamespace+') ...')