Piotr Labudda 8 rokov pred
rodič
commit
bed3ce66e1

+ 150 - 0
SE/se-lib/Route/ViewTableAjax.php

@@ -389,6 +389,156 @@ class Route_ViewTableAjax extends RouteBase {
 			throw $e;
 		}
 	}
+	public function editFormJsonAction() {
+		Response::sendTryCatchJson(array($this, 'editFormJson'), $args = $_REQUEST);
+	}
+	public function editFormJson($args) {// namespace, _hash, _primaryKey
+		$id = V::get('_primaryKey', 0, $args, 'int');
+		if ($id <= 0) throw new HttpException("Bad Request - missing primaryKey", 400);
+		$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);
+
+		$record = $acl->buildQuery([])->getItem($id);
+		if (!$acl->canWriteRecord($record) && !$acl->hasPermSuperWrite()) throw new Exception("Brak dostępu do 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();
+		foreach ($fieldsList as $kID => $field) {
+			$cols[$kID] = '';
+			if ($acl->canReadObjectField($field['name'], $record)) {
+				$cols[$kID] = V::get($field['name'], '', $record);
+			} else {
+				$cols[$kID] = '*****';
+			}
+			$cols[$kID] = V::get("f{$kID}", $cols[$kID], $_POST);
+		}
+		$tsValues = array();
+		if (!empty($fieldsList)) {
+			foreach ($fieldsList as $vColID => $vCol) {
+				$typeSpecial = Typespecial::getInstance($vColID, $vCol['name']);
+				if ($typeSpecial) {
+					$colValue = V::get($vCol['name'], '', $record);
+					$specialValues = $typeSpecial->getEditSelectedValuesByIds($acl->getID(), $record['ID'], $vCol['name'], $colValue);
+					if (!empty($specialValues)) {
+						$tsValues[$vColID] = implode('<br>', $specialValues);
+					}
+				}
+			}
+		}
+		DBG::log($tsValues, 'array', "editFormJson::tsValues");
+		foreach ($tsValues as $idx => $value) {
+			if ('<' === substr($value, 0, 1)) {
+				// $tsValues[$idx] = UI::convertHtmlToArray($value); // TODO: ...
+				$tsValues[$idx] = [ 'P5UI__RawHtml', [ 'rawHtml' => $tsValues[$idx] ] ];
+			}
+		}
+		DBG::log($tsValues, 'array', "editFormJson::tsValues parsed");
+		$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" ],
+		];
+		$rowFunctionsOut = [ 'P5UI__FeatureRowFunctions', [
+			'id' => $record['ID'],
+			'functions' => $featureFunctions,
+			'showLabels' => true,
+			'viewMoreDropdown' => [
+				'primaryKey' => $record['ID'],
+				'uri' => $this->getLink('moreFunctionsCellAjax', [ 'namespace' => $acl->getNamespace(), 'ID' => $record['ID'] ]),
+			],
+		] ]; // TODO: $this->_showRowFunctions($record['ID'], array('edit', 'cp'), true);
+		$jsFields = [];
+		$tabindex = 0;
+		foreach ($fieldsList as $kID => $vCol) {
+			$fieldName = $vCol['name'];
+			if ($acl->canWriteObjectField($fieldName, $record)) {
+				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' => "col-xs-12 col-sm-3 col-md-2 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' => "col-xs-12 col-sm-9 col-md-10" ], [
+						UI::hGetFormItem($acl, $fieldName, 'W', $kID, "f{$kID}", $cols[$kID], $fieldParams, $record),
+					] ]
+				] ];
+			} else if ($acl->canReadObjectField($fieldName, $record)) {
+				$jsFields[] = [ 'div', [ 'class' => "form-group" ], [
+					[ 'label', [ 'class' => "col-xs-12 col-sm-3 col-md-2 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' => "col-xs-12 col-sm-9 col-md-10" ], [
+						['p', [ 'style' => [ 'margin-top' => '5px' ] ], [
+							(!empty($tsValues[$kID]))
+								? $tsValues[$kID]
+								: V::get($fieldName, '', $record)
+						] ],
+					] ]
+				] ];
+			} else {
+				$jsFields[] = [ 'div', [ 'class' => "form-group" ], [
+					"TODO: SKIP field ({$fieldName}) - ! canWriteObjectField && ! canReadObjectField"
+				]];
+			}
+		}
+		$jsFields[] = [ 'div', [ 'class' => "form-group" ], [
+			[ 'div', [ 'class' => "col-xs-offset-0 col-xs-12 col-sm-offset-3 col-sm-9 col-md-offset-2 col-md-10" ], [
+				['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" ] ], [
+				[ 'P5UI__FeatureEditForm', [
+					'class' => "form-horizontal", 'action' => "", 'method' => "post",
+					'id' => "EDIT_FRM_{$this->_htmlID}", // TODO: rm - use React nodes // TODO: $this->_htmlID not exists!
+					'ajaxSaveUrl' => "{$syncUrl}&_task=editSaveAjax", // TODO:? &_hash={$this->_htmlID}
+					'namespace' => $acl->getNamespace(),
+					'idRecord' => $record['ID'],
+					'tableLabelHtml' => $tblLabel,
+				], [
+					[ 'fieldset', [ 'style' => [ "padding-bottom" => "100px" ] ], array_merge([
+						[ 'legend', [], [
+							"Edycja rekordu Nr {$record['ID']}",
+							[ 'span', [ 'class' => "pull-right valign-btns-bottom" ], [ $rowFunctionsOut ] ],
+						] ] ],
+						$jsFields
+					)] // fieldset
+				] ] // form
+			] ] // .container
+		];
+		return [
+			'type' => "success",
+			'msg' => "Edycja rekordu nr {$id}",
+			'body' => $jsGui, // TODO: action for GUI: array to render by function h, js to trigger
+		];
+	}
 	public function editSaveAjaxAction() {
 		Response::sendTryCatchJson(array($this, 'editSaveAjax'), $args = 'JSON_FROM_REQUEST_BODY');
 	}

+ 30 - 19
SE/se-lib/TableAjax.php

@@ -392,6 +392,8 @@ class TableAjax extends ViewAjax {
 			.AjaxTableCont-mapEditorContainer .ui-resizable-s { background-color:#ddd; }
 			.AjaxTableCont-mapEditorContainer .ui-resizable-s:hover { background-color:#888; }
 		");
+		echo UI::h('script', ['src'=>"static/vendor.js"]);
+		echo UI::h('script', ['src'=>"static/p5UI/buildDom.js?_ts=".time()]); // TODO: DBG load js
 		$_rendered = true;
 	}
 
@@ -933,6 +935,7 @@ var p5UI_TableAjax_generateFunctionNode = function(funObj, rowPK, props) {
 						// console.log('FieldWidget: generate function to render field('+_fieldName+') _fractionDigits('+_fractionDigits+')', fieldProps);
 						return function(val, fieldPK, row) {
 							// console.log('FieldWidget: pk('+fieldPK+') run function to render field('+_fieldName+') with value('+val+') ', fieldProps);
+							if ('*****' === val) return val
 							// enumeration
 							// fractionDigits
 							// maxExclusive
@@ -1213,8 +1216,10 @@ var p5UI_TableAjax_generateFunctionNode = function(funObj, rowPK, props) {
 					cellCnt.append(fldWidgetNode);
 				} else if (fldWidgetNode === '') {
 					cellCnt.empty();
+				} else if (fldWidgetNode === 0) {
+					cellCnt.empty();
 				} else {
-					console.log('TODO: !FieldWidget for row.pk('+rowPK+') col('+columnName+') typeof fldWidgetNode(' + (typeof fldWidgetNode) + ')');
+					console.log('TODO: !FieldWidget for row.pk('+rowPK+') col('+columnName+') typeof fldWidgetNode(' + (typeof fldWidgetNode) + ') columnProps', columnProps, 'fldWidgetNode', fldWidgetNode, 'value', props[columnName]);
 				}// test fld widgets
 
 				if (columnProps._tsRetId) {
@@ -3751,25 +3756,31 @@ jQuery(document).ready(function(){
 					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);
 
-					jQuery.ajax({
-						url: '<?= $this->syncUrl; ?>&_hash=<?= $this->_htmlID; ?>&_task=editForm&_primaryKey=' + recordID,
-						type: 'GET',
-						dataType: 'text',
-						data: '',
-						async: true,
-						success: function(data) {
-							taskCnt.removeClass('AjaxTable-loading');
-							jQuery(data).appendTo(taskCnt);
-
-							initDateTimePicker(taskCnt);
-						},
-						error: function(err) {
-							taskCnt.removeClass('AjaxTable-loading');
-							//console.log(p5Utils__format('request error: {0}', [err]));
+					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)
 						}
-					});
-
-					//return false;
+				  }).catch(function __route_edit_catch(e) {
+						taskCnt.removeClass('AjaxTable-loading');
+						console.log('editFormJson :: ERROR', e)
+						p5UI__notifyAjaxCallback({
+							type: 'error',
+							msg: 'Request error ' + e
+						});
+				  })
 				},
 				HIST: TableAjax__HIST_Route,
 				FILES: function tableAjaxFiles(args) {

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

@@ -0,0 +1,547 @@
+(function (global, p5VendorJs) {
+  if (!p5VendorJs.React) throw "Missing React"
+  if (!p5VendorJs.ReactDOM) throw "Missing ReactDOM"
+  if (!p5VendorJs.createReactClass) throw "Missing createReactClass"
+  var React = p5VendorJs.React
+  var ReactDOM = p5VendorJs.ReactDOM
+  var createReactClass = p5VendorJs.createReactClass
+  var h = React.createElement
+  var DBG = 0
+
+  var P5UI__RawHtml = createReactClass({
+    componentDidMount: function () {
+      if (this.props.rawHtml) {
+        this.rootNode.innerHTML = this.props.rawHtml
+      }
+    },
+    render: function () {
+      return h('div', {
+        ref: function (node) { this.rootNode = node; }.bind(this),
+      })
+    }
+  })
+  global.p5VendorJs['P5UI__RawHtml'] = P5UI__RawHtml
+
+  var P5UI__FeatureEditForm = createReactClass({
+    componentDidMount: function () {
+      if(DBG)console.warn('P5UI__FeatureEditForm::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__FeatureEditForm::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
+      // TODO: change Edit btn to return to edit record with fields -> show form
+
+      var taskCont = jQuery(this.rootNode).parents('.AjaxTableTaskCnt').parent(); // jQuery('#{$this->_htmlID}_task').parent();
+      //taskCont.empty();
+      taskCont.children().fadeOut('slow');
+      var alertCntWrap = jQuery('<div class="AjaxTableAlert AjaxTable-loading"></div>').prependTo(taskCont)
+        , alertCnt = jQuery('<div class="container"></div>').prependTo(alertCntWrap);
+      jQuery('<div class="alert alert-info"><div style="padding:0 0 0 20px; background:url(./icon/loading.gif) no-repeat left top;"> zapisywanie ... </div></div>').appendTo(alertCnt);
+
+      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 = 'Dane poprawnie zaktualizowane';
+            break;
+          case 'info':
+            if (!notify.msg) notify.msg = 'Nie wprowadzono żadnych zmian';
+            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 idRecord = this.props.idRecord
+      var tableLabelHtml = this.props.tableLabelHtml
+      superagent
+        .post(this.props.ajaxSaveUrl)
+        .type('json') // header ĺapplication/x-www-form-urlencoded' requires type('form');
+        .send({
+          namespace: this.props.namespace,
+          primaryKey: this.props.idRecord,
+          form: formData
+        })
+        .set('Accept', 'application/json')
+        .end(function(err, res) {
+          var payload;
+          if (err || !res.ok || 'application/json' !== res.type) {
+            payload = {type: 'warning', msg: res.body.msg || 'Wystąpiły błędy', body: res.body};
+          } else {
+            payload = {type: 'success', msg: res.body.msg || '', body: res.body};
+          }
+          var data = res.body;
+
+          alertCntWrap.removeClass('AjaxTable-loading');
+          alertCnt.empty();
+          if (false === ['success', 'info'].indexOf(payload.type)) {
+            jQuery(errorTxt).appendTo(alertCnt);
+            var errLinks = jQuery('<div class="breadcrumb"></div>').appendTo(alertCnt);
+            jQuery('<a href="#" onclick="return tableAjaxBackToTable();"> <i class="icon-arrow-left"></i> Wróć do tabeli '+tableLabelHtml+'</a>').appendTo(errLinks);
+            var backToEditBtn = jQuery('<a href="#EDIT/'+idRecord+'/' + Math.random(1).toString().substr(2) + '" class="btn btn-link btn-small"> <i class="icon-pencil"></i> Popraw dane '+idRecord+'</a>').appendTo(errLinks);
+            backToEditBtn.on('click', function(){
+              alertCnt.remove();
+              taskCont.children().fadeIn('slow');
+              return false;
+            });
+          } else {
+            var outMsg = notifyAjaxCallback(payload);
+            var out = '';
+            out += outMsg;
+            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/'+idRecord+'/' + Math.random(1).toString().substr(2) + '" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-pencil"></i> Edytuj rekord '+idRecord+'</a>' +
+              '</div>';
+            jQuery(out).appendTo(alertCnt);
+
+            // add rowFunctions from response
+            if (data && data.rowFunctions && data.primaryKey) {
+              var rowFunWrapNode = $('<div class="container"></div>').insertAfter(alertCnt);
+              var rowFunListNode = $('<ul></ul>').appendTo(rowFunWrapNode);
+              var keys = Object.keys(data.rowFunctions),
+                  total = keys.length,
+                  moreFuncBtnNode,
+                  moreFunctions = [],
+                  idx
+              ;
+              moreFunctions = keys.splice(3);
+              keys.forEach(function(key) {
+                var cellNode = $('<li></li>');
+                var funObj = data.rowFunctions[key],
+                    funcNode = p5UI_TableAjax_generateFunctionNode(funObj, data.primaryKey, {ico: true, label: true})
+                ;
+                funcNode.appendTo(cellNode);
+                cellNode.appendTo(rowFunListNode);
+              });
+            }
+          }
+        })
+    },
+    render: function () {
+      if(DBG)console.warn('P5UI__FeatureEditForm::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__FeatureEditForm'] = P5UI__FeatureEditForm
+
+  var P5UI__Typespecial = createReactClass({
+    componentDidMount: function () {
+      if(DBG)console.log('TS::componentDidMount (['+this.props.idField+'] '+this.props.fieldNamespace+') ...')
+      // console.log('TS::componentDidMount (['+this.props.idField+'] '+this.props.fieldNamespace+') this.rootNode', this.rootNode) // OK
+    	var fldNode = jQuery(document.getElementById(this.props.fieldName)) // jQuery('#{$fName}')
+      var tsNode = jQuery(this.rootNode) // jQuery('#ts-{$fName}')
+      var ajaxDataUrlBase = this.props.ajaxDataUrlBase
+    	if (!fldNode && !tsNode) {
+        console.log("BUG Missing fldNode or tsNode in P5UI__Typespecial")
+    		return;
+    	}
+    	if (!ajaxDataUrlBase) {
+        console.log("BUG Missing ajaxDataUrlBase in P5UI__Typespecial")
+    		return;
+    	}
+
+    	fldNode.attr('name', '');
+    	fldNode.hide();
+    	if (fldNode.parent().hasClass('show-last-value')) {
+    		fldNode.parent().hide();
+    	}
+    	tsNode.attr('name', this.props.frmFldName)
+    	tsNode.attr('tabindex', fldNode.attr('tabindex'))
+
+      var getFetchCallback = ('TypespecialVariable' === this.props.type)
+        ? function (query, callback) {
+            return function(res) {
+    					for (var i in res) {
+    						if (!res[i].name || res[i].id != res[i].name) {
+    							res[i].name = res[i].id + ': ' + res[i].name;
+    						}
+    					}
+    					callback(res);
+    				}
+          }
+        : function (query, callback) {
+            return function(res) {
+              var i, prefix, prefixLen;
+              for (i in res) {
+                prefix = '' + res[i].id;
+                prefixLen = prefix.length;
+                if (prefixLen > 0 && prefix !== res[i].name.substr(0, prefixLen)) {
+                  res[i].name = res[i].id + ': ' + res[i].name;
+                }
+                res[i]['\$order'] = 1 + (parseInt(i) || 0); // set order from request
+              }
+              callback(res);
+            }
+          }
+      ;
+      var scoreCallback = ('TypespecialVariable' === this.props.type)
+        ? function(search) {
+      			var score = this.getScoreFunction(search);
+      			return function(item) {
+      				// console.log('score:item:', item, ', score:', score(item));
+      				if (search && search == item.id) {
+      					return 1;
+      				} else {
+      					return score(item);// score(item) * (1 + Math.min(item.watchers / 100, 1));
+      				}
+      			};
+      		}
+        : function(query) {
+      			// console.log('Typespecial({$fName})::score: q(', query, ')');
+      			var score = this.getScoreFunction(query);
+      			return function(item) {
+      				var retScore = 0, lName = ('' + item.name).toLowerCase(), lQuery = query.toLowerCase();
+      				if (query.search(' ') > -1) {
+      					retScore = score(item);
+      				}
+      				else {
+      					if (lQuery + ':' == lName.substr(0, lQuery.length + 1)) {
+      						retScore = 100;
+      					} else if (lName.search(lQuery) > -1) {
+      						retScore = 90 - lName.search(lQuery);
+      					} else {
+      						retScore = 0;
+      					}
+      				}
+      				// console.log('Typespecial({$fName})::score: q(', lQuery, ') , retScore(', retScore, '), score(', score(item), '), item.name(', item.name, ') item.id:', item.id);
+      				return retScore;
+      			};
+      		}
+      ;
+
+    	tsNode.selectize({
+    		theme: 'typespecial',
+    		valueField: 'id',
+    		labelField: 'id',
+    		searchField: 'name',
+    		sortField: ('TypespecialVariable' === this.props.type) ? 'name' : '$order', // TODO: skip in Typespecial - default sort field is '$order'
+    		create: this.props.create,
+    		delimiter: ';',
+    		dataAttr: 'typespecial',
+    		preload: this.props.preload || false,
+    		options: this.props.options,
+    		render: {
+    			item: function(item, escape) {
+    				return '<div>' +
+    					'<span class=\"name\">' + escape(item.name || item.id) + '</span>' +
+    				'</div>';
+    			},
+    			option: function(item, escape) {
+    				return '<div>' +
+    					'<span class=\"title\">' +
+    						escape(item.name || item.id) +
+    					'</span>' +
+    				'</div>';
+    			}
+    		},
+    		onItemAdd: function(value, item) {// Invoked when an item is selected.
+    			var curSel = this.options[value] || null, fieldExport;
+    			if (curSel && curSel.exports) {
+    				for (var i in curSel.exports) {
+    					fieldExport = jQuery('#ts-f' + i);
+    					if (fieldExport.length) {
+                //console.log('--- onItemAdd fieldExport.selectize(',fieldExport.selectize,')', fieldExport);
+    						if (fieldExport.get(0).selectize) {
+    							fieldExport.get(0).selectize.addOption({id:curSel.exports[i], name:curSel.exports[i]});
+    							fieldExport.get(0).selectize.setValue(curSel.exports[i]);
+    						} else {
+    							//jQuery('#f' + i).val(curSel.exports[i]);
+    						}
+    					} else {
+    						fieldExport = jQuery('#f' + i);
+    						if (fieldExport.is('input')) {
+    							jQuery('#f' + i).val(curSel.exports[i]);
+    						} else if (fieldExport.is('select')) {
+    							//TODO: add option and select //jQuery('#f' + i).val(curSel.exports[i]);
+    						}
+    					}
+    				}
+    			}
+    		},
+    		score: scoreCallback,
+    		load: function(query, callback) {
+    			// if (!query.length) return callback(); // empty query at preload action
+    			$.ajax({
+    				url: ajaxDataUrlBase,
+    				data: 'q=' + encodeURIComponent(query),
+    				type: 'POST',
+    				error: function() {
+    					callback();
+    				},
+    				success: getFetchCallback(query, callback),
+    			});
+    		}
+    	});
+    },
+    render: function () {
+      if(DBG)console.log('TS::render (['+this.props.idField+'] '+this.props.fieldNamespace+') props', this.props)
+      return h('div', {
+        'className': "typespecial",
+        'style': { 'max-width': '366px' }
+      }, [
+        h('select', {
+          'ref': function (node) { this.rootNode = node; }.bind(this),
+        }, this.props.children)
+      ])
+    }
+  })
+  global.p5VendorJs['P5UI__Typespecial'] = P5UI__Typespecial
+
+  var P5UI__FeatureRowFunctions = createReactClass({
+    componentDidMount: function () {
+      if(DBG)console.warn('P5UI__FeatureRowFunctions::componentDidMount this.rootNode', this.rootNode)
+      if (this.props.rawHtml) {
+        if(DBG)console.warn('P5UI__FeatureRowFunctions::componentDidMount this.props.rawHtml', this.props.rawHtml)
+        this.rootNode.innerHTML = this.props.rawHtml
+      }
+    },
+    render: function () {
+      var showLabels = this.props.showLabels || false
+      var functions = this.props.functions || {}
+      if (!this.props.id) return h('div', { 'className': 'alert alert-danger' }, "Missing ID")
+      if(DBG)console.warn('P5UI__FeatureRowFunctions::render this.props', this.props)
+      return h('div', {
+        ref: function (node) { this.rootNode = node; }.bind(this),
+      }, [
+        ('hist' in functions)
+          ? h('a', { className: "btn btn-xs btn-link", href: functions.hist.href.replace("{0}", this.props.id), title: functions.hist.title }, [ h('span', { className: functions.hist.ico }), h('span', { style: {'padding': '0 6px'} }, functions.hist.title) ])
+          : null
+        ,
+        ('files' in functions)
+          ? h('a', { className: "btn btn-xs btn-link", href: functions.files.href.replace("{0}", this.props.id), title: functions.files.title }, [ h('span', { className: functions.files.ico }), h('span', { style: {'padding': '0 6px'} }, functions.files.title) ])
+          : null
+        ,
+        ('msgs' in functions)
+          ? h('a', { className: "btn btn-xs btn-link", href: functions.msgs.href.replace("{0}", this.props.id), title: functions.msgs.title }, [ h('span', { className: functions.msgs.ico }), h('span', { style: {'padding': '0 6px'} }, functions.msgs.title) ])
+          : null
+        ,
+        (this.props.viewMoreDropdown)
+          ? h(P5UI__DropdownAjax, this.props.viewMoreDropdown)
+          : null
+        ,
+      ])
+    }
+  })
+  global.p5VendorJs['P5UI__FeatureRowFunctions'] = P5UI__FeatureRowFunctions
+
+  var P5UI__DropdownAjax = createReactClass({
+    componentDidMount: function () {
+      jQuery(this.rootNode).popover({
+        container: 'body',
+        placement: 'bottom',
+        trigger: 'click',
+        // title: e.data.col + '<a href="#" class="glyphicon glyphicon-remove pull-right" onclick="return hidePopover();"></a>',
+        title: 'Więcej funkcji dla rekordu nr ' + this.props.primaryKey, // '<div style="display:block;position:relative;padding:0 20px 0 0;">' + (this.props.friendly || colName) + ' <button type="button" class="close" onclick="return hidePopover();" style="position:absolute;right:0;top:0;">&times;</button>' + '</div>',
+        html: true,
+        content: 'TODO: list...', // this.renderListToString.bind(this),
+        template: '' +
+          '<div class="popover" role="tooltip" style="max-width:600px;width:400px;">' +
+            '<div class="arrow"></div>' +
+            '<div style="display:block;position:relative;">' +
+              '<div class="popover-title">' +
+              '</div>' +
+            '</div>' +
+            '<div class="popover-content"></div>' +
+          '</div>'
+      })
+      this.setState({ 'isOpen': false })
+    },
+    componentWillUnmount: function () {
+      jQuery(this.rootNode).popover('desctroy')
+    },
+    componentWillMount: function() {
+      this._closeDropdownIfClickedOutside = function (event) {
+    		if (!this.state.isOpen) return;
+
+        var idHtmlPopover = jQuery(this.rootNode).attr('aria-describedby')
+        if(DBG)console.warn("P5UI__DropdownAjax::_closeDropdownIfClickedOutside idHtmlPopover:", idHtmlPopover)
+        if (!idHtmlPopover) return;
+
+    		var popoverNode = document.getElementById(idHtmlPopover)
+    		if (p5UI__clickedOutsideElement(popoverNode, event)) {
+    			this.setState({
+    				isOpen: false
+    			}, this._unbindCloseDropdownIfClickedOutside);
+          jQuery(this.rootNode).popover('hide')
+    		}
+    	}.bind(this);
+      this._bindCloseDropdownIfClickedOutside = function () {
+    		if (!document.addEventListener && document.attachEvent) {
+    			document.attachEvent('onclick', this._closeDropdownIfClickedOutside);
+    		} else {
+    			document.addEventListener('click', this._closeDropdownIfClickedOutside);
+    		}
+    	}.bind(this);
+      this._unbindCloseDropdownIfClickedOutside = function () {
+    		if (!document.removeEventListener && document.detachEvent) {
+    			document.detachEvent('onclick', this._closeDropdownIfClickedOutside);
+    		} else {
+    			document.removeEventListener('click', this._closeDropdownIfClickedOutside);
+    		}
+    	}.bind(this);
+    },
+    shouldComponentUpdate: function (nextProps, nextState) {
+      if (!nextState) return false
+      if (!this.state) return false
+      if (this.state.rowFunctions !== nextState.rowFunctions) {
+        var idHtmlPopover = jQuery(this.rootNode).attr('aria-describedby')
+        if(DBG)console.warn("P5UI__DropdownAjax::shouldComponentUpdate idHtmlPopover:", idHtmlPopover, 'nextState.rowFunctions', nextState.rowFunctions)
+        if (idHtmlPopover && nextState.rowFunctions && nextState.rowFunctions.length) {
+          jQuery(document.getElementById(idHtmlPopover)).find('.popover-content').html(this.renderListToString(nextState.rowFunctions))
+        } else {
+          jQuery(document.getElementById(idHtmlPopover)).find('.popover-content').html('<p class="text-muted">Brak dodatkowych funkcji</p>')
+        }
+      }
+      return false
+    },
+    renderListToString: function (list) {
+      if(DBG)console.warn('P5UI__DropdownAjax::renderListToString - this.state:', this.state)
+      var primaryKey = this.props.id
+      var out = '<ul class="list-unstyled">' + list.map(function (fun) {
+        return '<li><a href="'+fun.href.replace('{0}', primaryKey)+'" style="margin:0 2px;" title="'+fun.title+'">' +
+          (fun.ico ? '<span class="'+fun.ico+'"></span> ' : '') +
+          fun.label +
+        '</a></li>'
+      }).join('') + '</ul>'
+      if(DBG)console.warn('P5UI__DropdownAjax::renderListToString - out:', out)
+      return out
+    },
+    onAjaxFetch: function (data) {
+      this.setState({ rowFunctions: data.rowFunctions })
+    },
+    handleClick: function (e) {
+      e.preventDefault()
+      if(DBG)console.warn("P5UI__DropdownAjax::handleClick TODO: dropdown clicked - state:", this.state)
+      if (!this.props.uri) throw "Missing uri in P5UI__DropdownAjax"
+      if (this.state.isOpen) {
+        jQuery(this.rootNode).popover('hide')
+      } else {
+        jQuery(this.rootNode).popover('show')
+        var idHtmlPopover = jQuery(this.rootNode).attr('aria-describedby')
+        if (idHtmlPopover) {
+          jQuery(document.getElementById(idHtmlPopover)).find('.popover-content').html('<p>Loading...</p>')
+        }
+        // global.fetch()
+        // setTimeout(this.onAjaxFetch.bind(this, { msg: "Funkcje", type: "success", rowFunctions: [
+        //   { id: "msgs", ico: "glyphicon glyphicon-envelope", href: "index.php?_route=TableMsgs&_task=tableRow&idTable=13051&idRow=83", label: 'Wiadomości <span class="badge">0</badge>', title: "Wiadomości (0)" },
+        //   { ico: "glyphicon glyphicon-file", href: "https://biuro.biall-net.pl/dev-pl/se-master/index.php?_route=UrlAction_Ant&typeName=default_db:TEST_PERMS&primaryKey=83", label: 'Druki', title: "Druki" },
+        // ] }), 1000)
+        _popoverCellAjaxXhr = jQuery.ajax({
+  				type: 'GET',
+  				url: this.props.uri,
+  				dataType: 'json',
+  				contentType: "application/json; charset=utf-8",
+  			})
+  			.done(function(data, textStatus, jqXHR){
+  				if (data && 'success' === data.type) {
+            var rowFunctions = (data.rowFunctions && data.rowFunctions.length > 0)
+              ? data.rowFunctions
+              : [];
+            this.setState({ rowFunctions: data.rowFunctions })
+    			}
+        }.bind(this))
+        if (this.state.isOpen) this.setState({ 'isOpen': false })
+        else this.setState({ 'isOpen': true }, this._bindCloseDropdownIfClickedOutside)
+      }
+    },
+    render: function () {
+      if(DBG)console.warn('P5UI__DropdownAjax::render this.props', this.props)
+      return h('button', {
+        className: 'btn btn-xs btn-link',
+        ref: function (node) { this.rootNode = node; }.bind(this),
+        onClick: this.handleClick.bind(this)
+      }, [
+        h('span', {'className':"glyphicon glyphicon-menu-hamburger"}),
+        " Więcej "
+      ]);
+    }
+  })
+  global.p5VendorJs['P5UI__DropdownAjax'] = P5UI__DropdownAjax
+
+
+  function buildDom(dom, target) {
+    ReactDOM.render(buildReactNodeRec(dom), target)
+  }
+  function buildReactNodeRec(dom) {
+    if (null === dom) return null
+    if ('string' === typeof dom) return dom
+    var nodeReactType = dom[0]
+    if ('P5UI__' === nodeReactType.substr(0, 'P5UI__'.length)) {
+      if (nodeReactType in global.p5VendorJs) nodeReactType = global.p5VendorJs[nodeReactType]
+    }
+    return h(nodeReactType,
+      convertAttrsToReact(dom[0], dom[1]),
+      (dom[2] && 'function' === typeof dom[2].map)
+        ? dom[2].map(buildReactNodeRec)
+        : dom[2]
+    )
+  }
+  function convertAttrsToReact(tagName, attrs) {
+    if (!attrs) return null
+    if(DBG)console.log('todo convertAttrsToReact typeof attrs ('+ typeof attrs +') toString('+ attrs.toString() +')');
+    if (!attrs.toString()) return null
+    if ('class' in attrs) {
+      attrs['className'] = attrs['class']
+      delete attrs['class']
+    }
+    if ('input' === tagName && 'value' in attrs) { // fix input to uncontrolled
+      attrs['defaultValue'] = attrs['value']
+      delete attrs['value']
+    }
+    if ('input' === tagName && 'maxlength' in attrs) { // fix input to uncontrolled
+      attrs['maxLength'] = attrs['maxlength']
+      delete attrs['maxlength']
+    }
+    return attrs
+  }
+
+  global.p5UI__buildDom = buildDom
+})(window, window.p5VendorJs);

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
SE/static/vendor.js


Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov