buildDom.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. (function (global, p5VendorJs) {
  2. if (!p5VendorJs.React) throw "Missing React"
  3. if (!p5VendorJs.ReactDOM) throw "Missing ReactDOM"
  4. if (!p5VendorJs.createReactClass) throw "Missing createReactClass"
  5. var React = p5VendorJs.React
  6. var ReactDOM = p5VendorJs.ReactDOM
  7. var createReactClass = p5VendorJs.createReactClass
  8. var h = React.createElement
  9. var DBG = 0
  10. // global.p5VendorJs['P5UI__MyWidget'] = createReactClass({
  11. // componentWillMount: function () { console.log('MyWidget::componentWillMount...'); },
  12. // render: function () {
  13. // console.log('MyWidget::render... state, props', this.state, this.props);
  14. // var defaultProps = {}
  15. // return h('div', Object.assign(defaultProps, {
  16. // ref: function (node) { this.rootNode = node; }.bind(this),
  17. // // onSubmit: this.submit.bind(this)
  18. // }), this.props.children)
  19. // },
  20. // componentDidMount: function () { console.log('MyWidget::componentDidMount...'); },
  21. // componentWillReceiveProps: function (nextProps) { console.log('MyWidget::componentWillReceiveProps(nextProps)...', nextProps); },
  22. // shouldComponentUpdate: function (nextProps, nextState) { console.log('MyWidget::shouldComponentUpdate(nextProps, nextState)...', nextProps, nextState); },
  23. // componentWillUpdate: function (nextProps, nextState) { console.log('MyWidget::componentWillUpdate(nextProps, nextState)...', nextProps, nextState); },
  24. // componentDidUpdate: function (prevProps, prevState) { console.log('MyWidget::componentDidUpdate(prevProps, prevState)...', prevProps, prevState); },
  25. // componentWillUnmount: function () { console.log('MyWidget::componentWillUnmount...'); },
  26. // })
  27. var P5UI__RawHtml = createReactClass({
  28. componentDidMount: function () {
  29. if (this.props.rawHtml) {
  30. this.rootNode.innerHTML = this.props.rawHtml
  31. }
  32. },
  33. render: function () {
  34. return h('div', {
  35. ref: function (node) { this.rootNode = node; }.bind(this),
  36. })
  37. }
  38. })
  39. global.p5VendorJs['P5UI__RawHtml'] = P5UI__RawHtml
  40. var P5UI__FeatureEditForm = createReactClass({
  41. componentDidMount: function () {
  42. if(DBG)console.warn('P5UI__FeatureEditForm::componentDidMount this.rootNode', this.rootNode)
  43. jQuery(this.rootNode).find('textarea').autosize();
  44. jQuery(this.rootNode).find('.frm-help').popover({trigger:'hover'});
  45. jQuery(this.rootNode).find('.show-last-value input').on('input', function(e) {
  46. var input, btn, btnIco;
  47. input = jQuery(e.target);
  48. btn = input.next('.button-appendBack');
  49. btnIco = btn.find('.glyphicon');
  50. if (btn.attr('title') != input.val()) {
  51. btnIco.show();
  52. } else {
  53. btnIco.hide();
  54. }
  55. });
  56. jQuery(this.rootNode).find('.show-last-value').find('.button-appendBack').on('click', function(e) {
  57. var input, btn, btnIco;
  58. btn = jQuery(this);
  59. btnIco = btn.find('.glyphicon');
  60. input = btn.prev();
  61. if (input.is('input')) {
  62. if (btn.attr('title') != input.val()) {
  63. input.val(btn.attr('title'));
  64. btnIco.hide();
  65. }
  66. }
  67. });
  68. },
  69. submit: function (e) {
  70. if(DBG)console.warn('P5UI__FeatureEditForm::submit this.rootNode', this.rootNode)
  71. e.preventDefault()
  72. var formData = {};
  73. jQuery(this.rootNode).serializeArray().map(function(i) { formData[i.name] = i.value; });// TODO: edit Widget - send only updated fields
  74. // TODO: change Edit btn to return to edit record with fields -> show form
  75. var taskCont = jQuery(this.rootNode).parents('.AjaxTableTaskCnt').parent(); // jQuery('#{$this->_htmlID}_task').parent();
  76. //taskCont.empty();
  77. taskCont.children().fadeOut('slow');
  78. var alertCntWrap = jQuery('<div class="AjaxTableAlert AjaxTable-loading"></div>').prependTo(taskCont)
  79. , alertCnt = jQuery('<div class="container"></div>').prependTo(alertCntWrap);
  80. 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);
  81. function notifyAjaxCallback(data) {
  82. var notify = {}, outMsg = '';
  83. notify.type = (data && data.type)? data.type : '';
  84. notify.msg = (data && data.msg)? data.msg : '';
  85. switch (notify.type) {
  86. case 'success':
  87. if (!notify.msg) notify.msg = 'Dane poprawnie zaktualizowane';
  88. break;
  89. case 'info':
  90. if (!notify.msg) notify.msg = 'Nie wprowadzono żadnych zmian';
  91. break;
  92. case 'error':
  93. if (!notify.msg) notify.msg = 'Wystąpiły błędy';
  94. break;
  95. case 'warning':
  96. notify.type = 'warn';
  97. if (!notify.msg) notify.msg = 'Wystąpiły błędy';
  98. break;
  99. default:
  100. notify.msg = 'Nieznany błąd';
  101. if (data && data.errorCode) notify.msg += ' ' + data.errorCode;
  102. notify.type = '';
  103. }
  104. jQuery.notify(notify.msg, notify.type);
  105. var alertType = ('error' == data.type) ? 'danger' : data.type;
  106. outMsg = '<div class="alert alert-' + alertType + '">' + notify.msg + '</div>';
  107. return outMsg;
  108. }
  109. var idRecord = this.props.idRecord
  110. var tableLabelHtml = this.props.tableLabelHtml
  111. superagent
  112. .post(this.props.ajaxSaveUrl)
  113. .type('json') // header ĺapplication/x-www-form-urlencoded' requires type('form');
  114. .send({
  115. namespace: this.props.namespace,
  116. primaryKey: this.props.idRecord,
  117. form: formData
  118. })
  119. .set('Accept', 'application/json')
  120. .end(function(err, res) {
  121. var payload;
  122. if (err || !res.ok || 'application/json' !== res.type) {
  123. payload = {type: 'warning', msg: res.body.msg || 'Wystąpiły błędy', body: res.body};
  124. } else {
  125. payload = {type: 'success', msg: res.body.msg || '', body: res.body};
  126. }
  127. var data = res.body;
  128. alertCntWrap.removeClass('AjaxTable-loading');
  129. alertCnt.empty();
  130. if (false === ['success', 'info'].indexOf(payload.type)) {
  131. jQuery(errorTxt).appendTo(alertCnt);
  132. var errLinks = jQuery('<div class="breadcrumb"></div>').appendTo(alertCnt);
  133. jQuery('<a href="#" onclick="return tableAjaxBackToTable();"> <i class="icon-arrow-left"></i> Wróć do tabeli '+tableLabelHtml+'</a>').appendTo(errLinks);
  134. 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);
  135. backToEditBtn.on('click', function(){
  136. alertCnt.remove();
  137. taskCont.children().fadeIn('slow');
  138. return false;
  139. });
  140. } else {
  141. var outMsg = notifyAjaxCallback(payload);
  142. var out = '';
  143. out += outMsg;
  144. out += '<div class="breadcrumb">' +
  145. ' <a href="#" onclick="return tableAjaxBackToTable();" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-arrow-left"></i> Wróć do tabeli '+tableLabelHtml+'</a>' +
  146. ' <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>' +
  147. '</div>';
  148. jQuery(out).appendTo(alertCnt);
  149. // add rowFunctions from response
  150. if (data && data.rowFunctions && data.primaryKey) {
  151. var rowFunWrapNode = $('<div class="container"></div>').insertAfter(alertCnt);
  152. var rowFunListNode = $('<ul></ul>').appendTo(rowFunWrapNode);
  153. var keys = Object.keys(data.rowFunctions),
  154. total = keys.length,
  155. moreFuncBtnNode,
  156. moreFunctions = [],
  157. idx
  158. ;
  159. moreFunctions = keys.splice(3);
  160. keys.forEach(function(key) {
  161. var cellNode = $('<li></li>');
  162. var funObj = data.rowFunctions[key],
  163. funcNode = p5UI_TableAjax_generateFunctionNode(funObj, data.primaryKey, {ico: true, label: true})
  164. ;
  165. funcNode.appendTo(cellNode);
  166. cellNode.appendTo(rowFunListNode);
  167. });
  168. }
  169. }
  170. })
  171. },
  172. render: function () {
  173. if(DBG)console.warn('P5UI__FeatureEditForm::render this.props', this.props)
  174. var formProps = Object.assign({}, this.props)
  175. delete formProps.children
  176. return h('form', Object.assign(formProps, {
  177. ref: function (node) { this.rootNode = node; }.bind(this),
  178. onSubmit: this.submit.bind(this)
  179. }), this.props.children)
  180. }
  181. })
  182. global.p5VendorJs['P5UI__FeatureEditForm'] = P5UI__FeatureEditForm
  183. var P5UI__FeatureCreateForm = createReactClass({
  184. componentDidMount: function () {
  185. if(DBG)console.warn('P5UI__FeatureCreateForm::componentDidMount this.rootNode', this.rootNode)
  186. jQuery(this.rootNode).find('textarea').autosize();
  187. jQuery(this.rootNode).find('.frm-help').popover({trigger:'hover'});
  188. jQuery(this.rootNode).find('.show-last-value input').on('input', function(e) {
  189. var input, btn, btnIco;
  190. input = jQuery(e.target);
  191. btn = input.next('.button-appendBack');
  192. btnIco = btn.find('.glyphicon');
  193. if (btn.attr('title') != input.val()) {
  194. btnIco.show();
  195. } else {
  196. btnIco.hide();
  197. }
  198. });
  199. jQuery(this.rootNode).find('.show-last-value').find('.button-appendBack').on('click', function(e) {
  200. var input, btn, btnIco;
  201. btn = jQuery(this);
  202. btnIco = btn.find('.glyphicon');
  203. input = btn.prev();
  204. if (input.is('input')) {
  205. if (btn.attr('title') != input.val()) {
  206. input.val(btn.attr('title'));
  207. btnIco.hide();
  208. }
  209. }
  210. });
  211. },
  212. submit: function (e) {
  213. if(DBG)console.warn('P5UI__FeatureCreateForm::submit this.rootNode', this.rootNode)
  214. e.preventDefault()
  215. var formData = {};
  216. jQuery(this.rootNode).serializeArray().map(function(i) { formData[i.name] = i.value; });// TODO: edit Widget - send only updated fields
  217. if(DBG)console.log('P5UI__FeatureCreateForm::submit formData', formData);
  218. var taskContLast = jQuery('#' + this.props._htmlID + '_task'),
  219. taskCont = taskContLast.parent();
  220. taskContLast.fadeOut('slow');
  221. var taskCnt = jQuery('<div id="' + this.props._htmlID + '_task" class="AjaxTableTaskCnt AjaxTable-loading"></div>').appendTo(taskCont);
  222. 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);
  223. function notifyAjaxCallback(data) {
  224. var notify = {}, outMsg = '';
  225. notify.type = (data && data.type)? data.type : '';
  226. notify.msg = (data && data.msg)? data.msg : '';
  227. switch (notify.type) {
  228. case 'success':
  229. if (!notify.msg) notify.msg = 'OK';
  230. break;
  231. case 'info':
  232. if (!notify.msg) notify.msg = '';
  233. break;
  234. case 'error':
  235. if (!notify.msg) notify.msg = 'Wystąpiły błędy';
  236. break;
  237. case 'warning':
  238. notify.type = 'warn';
  239. if (!notify.msg) notify.msg = 'Wystąpiły błędy';
  240. break;
  241. default:
  242. notify.msg = 'Nieznany błąd';
  243. if (data && data.errorCode) notify.msg += ' ' + data.errorCode;
  244. notify.type = '';
  245. }
  246. jQuery.notify(notify.msg, notify.type);
  247. var alertType = ('error' == data.type) ? 'danger' : data.type;
  248. outMsg = '<div class="alert alert-' + alertType + '">' + notify.msg + '</div>';
  249. return outMsg;
  250. }
  251. var tableLabelHtml = this.props.tableLabelHtml;
  252. global.fetch(this.props.ajaxSaveLegacyUrl, {
  253. headers: {
  254. 'Content-Type': 'application/json'
  255. },
  256. method: 'POST',
  257. credentials: 'same-origin',
  258. body: JSON.stringify(formData),
  259. }).then(function (response) {
  260. return response.json()
  261. }).then(function (data) {
  262. taskCnt.removeClass('AjaxTable-loading');
  263. taskCnt.empty();
  264. if(DBG)console.log('P5UI__FeatureCreateForm:: data: ', data)
  265. if ('success' === data.type) {
  266. var msg = 'OK';
  267. if (data.id && data.id > 0) msg = 'Utworzono pomyślnie rekord: ID = ' + data.id;
  268. else if (data.msg) msg = data.msg;
  269. var out = '<div class="container">';
  270. out += '<div class="alert alert-success">' + msg + '</div>';
  271. out += '<div class="breadcrumb">' +
  272. ' <a href="#" onclick="return tableAjaxBackToTable();" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-arrow-left"></i> Wróć do tabeli ' + tableLabelHtml + '</a>' +
  273. ' <a href="#EDIT/' + data.id + '" class="btn btn-link btn-sm"> <i class="glyphicon glyphicon-pencil"></i> Edytuj rekord ' + data.id + '</a>' +
  274. ' <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>' +
  275. '</div>';
  276. out += '</div>';
  277. jQuery(out).appendTo(taskCnt);
  278. } else {
  279. var msg = (data.msg) ? data.msg : "Nieznany błąd!";
  280. var out = '<div class="container">' +
  281. '<div class="alert alert-danger">' +
  282. '<h4>Wystąpiły błędy!</h4>' + msg +
  283. '</div>';
  284. out += '<div class="breadcrumb">' +
  285. ' <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>' +
  286. '</div>' +
  287. '</div>';
  288. jQuery(out).appendTo(taskCnt);
  289. var taskContLastNode = taskContLast
  290. , taskCntNode = taskCnt;
  291. taskCnt.find('.create-fix').click(function(){
  292. taskCntNode.remove();
  293. taskContLastNode.fadeIn('slow');
  294. return false;
  295. });
  296. }
  297. }).catch(function (e) {
  298. taskCnt.removeClass('AjaxTable-loading');
  299. taskCnt.empty();
  300. var out = '<div class="container">' +
  301. '<div class="alert alert-danger">' +
  302. '<h4>Wystąpiły błędy!</h4>' + e +
  303. '</div>';
  304. out += '<div class="breadcrumb">' +
  305. ' <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>' +
  306. '</div>' +
  307. '</div>';
  308. jQuery(out).appendTo(taskCnt);
  309. var taskContLastNode = taskContLast
  310. , taskCntNode = taskCnt;
  311. taskCnt.find('.create-fix').click(function(){
  312. taskCntNode.remove();
  313. taskContLastNode.fadeIn('slow');
  314. return false;
  315. });
  316. if(DBG)console.log('P5UI__FeatureCreateForm:: e: ', e)
  317. });
  318. },
  319. render: function () {
  320. if(DBG)console.warn('P5UI__FeatureCreateForm::render this.props', this.props)
  321. var formProps = Object.assign({}, this.props)
  322. delete formProps.children
  323. return h('form', Object.assign(formProps, {
  324. ref: function (node) { this.rootNode = node; }.bind(this),
  325. onSubmit: this.submit.bind(this)
  326. }), this.props.children)
  327. }
  328. })
  329. global.p5VendorJs['P5UI__FeatureCreateForm'] = P5UI__FeatureCreateForm
  330. var P5UI__Typespecial = createReactClass({
  331. componentDidMount: function () {
  332. if(DBG)console.log('TS::componentDidMount (['+this.props.idField+'] '+this.props.fieldNamespace+') ...')
  333. // console.log('TS::componentDidMount (['+this.props.idField+'] '+this.props.fieldNamespace+') this.rootNode', this.rootNode) // OK
  334. var fldNode = jQuery(document.getElementById(this.props.fieldName)) // jQuery('#{$fName}')
  335. var tsNode = jQuery(this.rootNode) // jQuery('#ts-{$fName}')
  336. var ajaxDataUrlBase = this.props.ajaxDataUrlBase
  337. if (!fldNode && !tsNode) {
  338. console.log("BUG Missing fldNode or tsNode in P5UI__Typespecial")
  339. return;
  340. }
  341. if (!ajaxDataUrlBase) {
  342. console.log("BUG Missing ajaxDataUrlBase in P5UI__Typespecial")
  343. return;
  344. }
  345. fldNode.attr('name', '');
  346. fldNode.hide();
  347. if (fldNode.parent().hasClass('show-last-value')) {
  348. fldNode.parent().hide();
  349. }
  350. tsNode.attr('name', this.props.frmFldName)
  351. tsNode.attr('tabindex', fldNode.attr('tabindex'))
  352. var getFetchCallback = ('TypespecialVariable' === this.props.type)
  353. ? function (query, callback) {
  354. return function(res) {
  355. for (var i in res) {
  356. if (!res[i].name || res[i].id != res[i].name) {
  357. res[i].name = res[i].id + ': ' + res[i].name;
  358. }
  359. }
  360. callback(res);
  361. }
  362. }
  363. : function (query, callback) {
  364. return function(res) {
  365. var i, prefix, prefixLen;
  366. for (i in res) {
  367. prefix = '' + res[i].id;
  368. prefixLen = prefix.length;
  369. if (prefixLen > 0 && prefix !== res[i].name.substr(0, prefixLen)) {
  370. res[i].name = res[i].id + ': ' + res[i].name;
  371. }
  372. res[i]['\$order'] = 1 + (parseInt(i) || 0); // set order from request
  373. }
  374. callback(res);
  375. }
  376. }
  377. ;
  378. var scoreCallback = ('TypespecialVariable' === this.props.type)
  379. ? function(search) {
  380. var score = this.getScoreFunction(search);
  381. return function(item) {
  382. // console.log('score:item:', item, ', score:', score(item));
  383. if (search && search == item.id) {
  384. return 1;
  385. } else {
  386. return score(item);// score(item) * (1 + Math.min(item.watchers / 100, 1));
  387. }
  388. };
  389. }
  390. : function(query) {
  391. // console.log('Typespecial({$fName})::score: q(', query, ')');
  392. var score = this.getScoreFunction(query);
  393. return function(item) {
  394. var retScore = 0, lName = ('' + item.name).toLowerCase(), lQuery = query.toLowerCase();
  395. if (query.search(' ') > -1) {
  396. retScore = score(item);
  397. }
  398. else {
  399. if (lQuery + ':' == lName.substr(0, lQuery.length + 1)) {
  400. retScore = 100;
  401. } else if (lName.search(lQuery) > -1) {
  402. retScore = 90 - lName.search(lQuery);
  403. } else {
  404. retScore = 0;
  405. }
  406. }
  407. // console.log('Typespecial({$fName})::score: q(', lQuery, ') , retScore(', retScore, '), score(', score(item), '), item.name(', item.name, ') item.id:', item.id);
  408. return retScore;
  409. };
  410. }
  411. ;
  412. tsNode.selectize({
  413. theme: 'typespecial',
  414. valueField: 'id',
  415. labelField: 'id',
  416. searchField: 'name',
  417. sortField: ('TypespecialVariable' === this.props.type) ? 'name' : '$order', // TODO: skip in Typespecial - default sort field is '$order'
  418. create: this.props.create,
  419. delimiter: ';',
  420. dataAttr: 'typespecial',
  421. preload: this.props.preload || false,
  422. options: this.props.options,
  423. render: {
  424. item: function(item, escape) {
  425. return '<div>' +
  426. '<span class=\"name\">' + escape(item.name || item.id) + '</span>' +
  427. '</div>';
  428. },
  429. option: function(item, escape) {
  430. return '<div>' +
  431. '<span class=\"title\">' +
  432. escape(item.name || item.id) +
  433. '</span>' +
  434. '</div>';
  435. }
  436. },
  437. onItemAdd: function(value, item) {// Invoked when an item is selected.
  438. var curSel = this.options[value] || null, fieldExport;
  439. if (curSel && curSel.exports) {
  440. for (var i in curSel.exports) {
  441. fieldExport = jQuery('#ts-f' + i);
  442. if (fieldExport.length) {
  443. //console.log('--- onItemAdd fieldExport.selectize(',fieldExport.selectize,')', fieldExport);
  444. if (fieldExport.get(0).selectize) {
  445. fieldExport.get(0).selectize.addOption({id:curSel.exports[i], name:curSel.exports[i]});
  446. fieldExport.get(0).selectize.setValue(curSel.exports[i]);
  447. } else {
  448. //jQuery('#f' + i).val(curSel.exports[i]);
  449. }
  450. } else {
  451. fieldExport = jQuery('#f' + i);
  452. if (fieldExport.is('input')) {
  453. jQuery('#f' + i).val(curSel.exports[i]);
  454. } else if (fieldExport.is('select')) {
  455. //TODO: add option and select //jQuery('#f' + i).val(curSel.exports[i]);
  456. }
  457. }
  458. }
  459. }
  460. },
  461. score: scoreCallback,
  462. load: function(query, callback) {
  463. // if (!query.length) return callback(); // empty query at preload action
  464. $.ajax({
  465. url: ajaxDataUrlBase,
  466. data: 'q=' + encodeURIComponent(query),
  467. type: 'POST',
  468. error: function() {
  469. callback();
  470. },
  471. success: getFetchCallback(query, callback),
  472. });
  473. }
  474. });
  475. },
  476. render: function () {
  477. if(DBG)console.log('TS::render (['+this.props.idField+'] '+this.props.fieldNamespace+') props', this.props)
  478. return h('div', {
  479. 'className': "typespecial",
  480. 'style': { 'max-width': '366px' }
  481. }, [
  482. h('select', {
  483. 'ref': function (node) { this.rootNode = node; }.bind(this),
  484. }, this.props.children)
  485. ])
  486. }
  487. })
  488. global.p5VendorJs['P5UI__Typespecial'] = P5UI__Typespecial
  489. var P5UI__FeatureRowFunctions = createReactClass({
  490. componentDidMount: function () {
  491. if(DBG)console.warn('P5UI__FeatureRowFunctions::componentDidMount this.rootNode', this.rootNode)
  492. if (this.props.rawHtml) {
  493. if(DBG)console.warn('P5UI__FeatureRowFunctions::componentDidMount this.props.rawHtml', this.props.rawHtml)
  494. this.rootNode.innerHTML = this.props.rawHtml
  495. }
  496. },
  497. render: function () {
  498. var showLabels = this.props.showLabels || false
  499. var functions = this.props.functions || {}
  500. if (!this.props.id) return h('div', { 'className': 'alert alert-danger' }, "Missing ID")
  501. if(DBG)console.warn('P5UI__FeatureRowFunctions::render this.props', this.props)
  502. return h('div', {
  503. ref: function (node) { this.rootNode = node; }.bind(this),
  504. }, [
  505. ('hist' in functions)
  506. ? 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) ])
  507. : null
  508. ,
  509. ('files' in functions)
  510. ? 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) ])
  511. : null
  512. ,
  513. ('msgs' in functions)
  514. ? 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) ])
  515. : null
  516. ,
  517. (this.props.viewMoreDropdown)
  518. ? h(P5UI__MoreFunctionsDropdownAjax, this.props.viewMoreDropdown)
  519. : null
  520. ,
  521. ])
  522. }
  523. })
  524. global.p5VendorJs['P5UI__FeatureRowFunctions'] = P5UI__FeatureRowFunctions
  525. var P5UI__MoreFunctionsDropdownAjax = createReactClass({
  526. componentDidMount: function () {
  527. jQuery(this.rootNode).popover({
  528. container: 'body',
  529. placement: 'bottom',
  530. trigger: 'click',
  531. // title: e.data.col + '<a href="#" class="glyphicon glyphicon-remove pull-right" onclick="return hidePopover();"></a>',
  532. 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>',
  533. html: true,
  534. content: 'TODO: list...', // this.renderListToString.bind(this),
  535. template: '' +
  536. '<div class="popover" role="tooltip" style="max-width:600px;width:400px;">' +
  537. '<div class="arrow"></div>' +
  538. '<div style="display:block;position:relative;">' +
  539. '<div class="popover-title">' +
  540. '</div>' +
  541. '</div>' +
  542. '<div class="popover-content"></div>' +
  543. '</div>'
  544. })
  545. this.setState({ 'isOpen': false })
  546. },
  547. componentWillUnmount: function () {
  548. if(DBG)console.warn("P5UI__MoreFunctionsDropdownAjax::componentWillUnmount")
  549. jQuery(this.rootNode).popover('destroy')
  550. },
  551. componentWillMount: function() {
  552. this._closeDropdownIfClickedOutside = function (event) {
  553. if (!this.state.isOpen) return;
  554. var idHtmlPopover = jQuery(this.rootNode).attr('aria-describedby')
  555. if(DBG)console.warn("P5UI__MoreFunctionsDropdownAjax::_closeDropdownIfClickedOutside idHtmlPopover:", idHtmlPopover)
  556. if (!idHtmlPopover) return;
  557. var popoverNode = document.getElementById(idHtmlPopover)
  558. var isClickedOutside = p5UI__clickedOutsideElement(popoverNode, event)
  559. if(DBG)console.warn("P5UI__MoreFunctionsDropdownAjax::_closeDropdownIfClickedOutside isClickedOutside:", isClickedOutside, 'this.rootNode', this.rootNode)
  560. if (isClickedOutside) {
  561. if (jQuery(this.rootNode).data("bs.popover")) {
  562. jQuery(this.rootNode).popover('hide')
  563. } else {
  564. popoverNode.parentNode.removeChild(popoverNode) // DOM removed before 'hide'
  565. }
  566. this.setState({
  567. isOpen: false
  568. }, this._unbindCloseDropdownIfClickedOutside.bind(this));
  569. }
  570. }.bind(this);
  571. this._bindCloseDropdownIfClickedOutside = function () {
  572. if(DBG)console.warn("P5UI__MoreFunctionsDropdownAjax::_bindCloseDropdownIfClickedOutside", this._closeDropdownIfClickedOutside)
  573. if (!document.addEventListener && document.attachEvent) {
  574. document.attachEvent('onclick', this._closeDropdownIfClickedOutside);
  575. } else {
  576. document.addEventListener('click', this._closeDropdownIfClickedOutside);
  577. }
  578. }.bind(this);
  579. this._unbindCloseDropdownIfClickedOutside = function () {
  580. if(DBG)console.warn("P5UI__MoreFunctionsDropdownAjax::_unbindCloseDropdownIfClickedOutside", this._closeDropdownIfClickedOutside)
  581. if (!document.removeEventListener && document.detachEvent) {
  582. document.detachEvent('onclick', this._closeDropdownIfClickedOutside);
  583. } else {
  584. document.removeEventListener('click', this._closeDropdownIfClickedOutside);
  585. }
  586. }.bind(this);
  587. },
  588. shouldComponentUpdate: function (nextProps, nextState) {
  589. if (!nextState) return false
  590. if (!this.state) return false
  591. if (this.state.rowFunctions !== nextState.rowFunctions) {
  592. var idHtmlPopover = jQuery(this.rootNode).attr('aria-describedby')
  593. if(DBG)console.warn("P5UI__MoreFunctionsDropdownAjax::shouldComponentUpdate idHtmlPopover:", idHtmlPopover, 'nextState.rowFunctions', nextState.rowFunctions)
  594. if (idHtmlPopover && nextState.rowFunctions && nextState.rowFunctions.length) {
  595. jQuery(document.getElementById(idHtmlPopover)).find('.popover-content').html(this.renderListToString(nextState.rowFunctions))
  596. } else {
  597. jQuery(document.getElementById(idHtmlPopover)).find('.popover-content').html('<p class="text-muted">Brak dodatkowych funkcji</p>')
  598. }
  599. }
  600. return false
  601. },
  602. renderListToString: function (list) {
  603. if(DBG)console.warn('P5UI__MoreFunctionsDropdownAjax::renderListToString - this.state:', this.state)
  604. var primaryKey = this.props.id
  605. var out = '<ul class="list-unstyled">' + list.map(function (fun) {
  606. return '<li><a href="'+fun.href.replace('{0}', primaryKey)+'" style="margin:0 2px;" title="'+fun.title+'">' +
  607. (fun.ico ? '<span class="'+fun.ico+'"></span> ' : '') +
  608. (fun.label || fun.title) +
  609. '</a></li>'
  610. }).join('') + '</ul>'
  611. if(DBG)console.warn('P5UI__MoreFunctionsDropdownAjax::renderListToString - out:', out)
  612. return out
  613. },
  614. onAjaxFetch: function (data) {
  615. this.setState({ rowFunctions: data.rowFunctions })
  616. },
  617. handleClick: function (e) {
  618. e.preventDefault()
  619. if (!this.props.uri) throw "Missing uri in P5UI__MoreFunctionsDropdownAjax"
  620. if (this.state.isOpen) {
  621. jQuery(this.rootNode).popover('hide')
  622. } else {
  623. jQuery(this.rootNode).popover('show')
  624. var idHtmlPopover = jQuery(this.rootNode).attr('aria-describedby')
  625. if (idHtmlPopover) {
  626. jQuery(document.getElementById(idHtmlPopover)).find('.popover-content').html('<p>Loading...</p>')
  627. }
  628. // global.fetch()
  629. // setTimeout(this.onAjaxFetch.bind(this, { msg: "Funkcje", type: "success", rowFunctions: [
  630. // { 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)" },
  631. // { 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" },
  632. // ] }), 1000)
  633. _popoverCellAjaxXhr = jQuery.ajax({
  634. type: 'GET',
  635. url: this.props.uri,
  636. dataType: 'json',
  637. contentType: "application/json; charset=utf-8",
  638. })
  639. .done(function(data, textStatus, jqXHR){
  640. if (data && 'success' === data.type) {
  641. var rowFunctions = (data.rowFunctions && data.rowFunctions.length > 0)
  642. ? data.rowFunctions
  643. : [];
  644. this.setState({ rowFunctions: data.rowFunctions })
  645. }
  646. }.bind(this))
  647. if (this.state.isOpen) this.setState({ 'isOpen': false })
  648. else this.setState({ 'isOpen': true }, this._bindCloseDropdownIfClickedOutside)
  649. }
  650. },
  651. render: function () {
  652. if(DBG)console.warn('P5UI__MoreFunctionsDropdownAjax::render this.props', this.props)
  653. return h('button', {
  654. className: 'btn btn-xs btn-link',
  655. ref: function (node) { this.rootNode = node; }.bind(this),
  656. onClick: this.handleClick.bind(this)
  657. }, [
  658. h('span', {'className':"glyphicon glyphicon-menu-hamburger"}),
  659. " Więcej "
  660. ]);
  661. }
  662. })
  663. global.p5VendorJs['P5UI__MoreFunctionsDropdownAjax'] = P5UI__MoreFunctionsDropdownAjax
  664. function buildDom(dom, target) {
  665. ReactDOM.render(buildReactNodeRec(dom), target)
  666. }
  667. function buildReactNodeRec(dom) {
  668. if (null === dom) return null
  669. if ('string' === typeof dom) return dom
  670. var nodeReactType = dom[0]
  671. if ('P5UI__' === nodeReactType.substr(0, 'P5UI__'.length)) {
  672. if (nodeReactType in global.p5VendorJs) nodeReactType = global.p5VendorJs[nodeReactType]
  673. }
  674. return h(nodeReactType,
  675. convertAttrsToReact(dom[0], dom[1]),
  676. (dom[2] && 'function' === typeof dom[2].map)
  677. ? dom[2].map(buildReactNodeRec)
  678. : dom[2]
  679. )
  680. }
  681. function convertAttrsToReact(tagName, attrs) {
  682. if (!attrs) return null
  683. if(DBG)console.log('todo convertAttrsToReact typeof attrs ('+ typeof attrs +') toString('+ attrs.toString() +')');
  684. if (!attrs.toString()) return null
  685. if ('class' in attrs) {
  686. attrs['className'] = attrs['class']
  687. delete attrs['class']
  688. }
  689. if ('input' === tagName && 'value' in attrs) { // fix input to uncontrolled
  690. attrs['defaultValue'] = attrs['value']
  691. delete attrs['value']
  692. }
  693. if ('input' === tagName && 'maxlength' in attrs) { // fix input to uncontrolled
  694. attrs['maxLength'] = attrs['maxlength']
  695. delete attrs['maxlength']
  696. }
  697. return attrs
  698. }
  699. global.p5UI__buildDom = buildDom
  700. })(window, window.p5VendorJs);