querybase.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. var modal;
  2. /**
  3. * Query sql.
  4. *
  5. * @param function callback
  6. * @access public
  7. * @return void
  8. */
  9. function query(callback) {
  10. DataStorage.isInsert = false;
  11. var pivot = DataStorage.pivot;
  12. var filters = '';
  13. if(pivot)
  14. {
  15. if(!setVarFrom()) return false;
  16. filters = DataStorage.pivot.filters;
  17. filters.forEach(function(filter, index)
  18. {
  19. if(filter.from == 'query')
  20. {
  21. var find = $('#queryFilters').find('.filter-item-' + index + ' .form-' + filter.type);
  22. if(find.length != 0) filter.default = find.val();
  23. }
  24. });
  25. }
  26. DataStorage.fields = {};
  27. DataStorage.columns = {};
  28. DataStorage.rows = [];
  29. $('.query').addClass('disabled');
  30. $('#querying').removeClass('hidden');
  31. var sql = $('#sql').val();
  32. sql = latin1ToBase64(sql);
  33. $.post(createLink('dataview', 'ajaxQuery'), {sql: sql, driver: DataStorage.driver, filters: filters, recPerPage: DataStorage.recPerPage, pageID: DataStorage.pageID}, function(resp)
  34. {
  35. resp = JSON.parse(resp);
  36. $('.query').removeClass('disabled');
  37. $('#querying').addClass('hidden');
  38. if(resp.result !== 'success')
  39. {
  40. $('#exportDataview').addClass('hidden');
  41. var message = resp.message;
  42. $('.error').removeClass('hidden');
  43. $('.error td').html(message);
  44. drawTable([], []);
  45. }
  46. else
  47. {
  48. $('#exportDataview').removeClass('hidden');
  49. DataStorage.fields = resp.fields;
  50. DataStorage.columns = resp.columns;
  51. DataStorage.rows = resp.rows;
  52. vars = resp.vars;
  53. DataStorage.relatedObject = resp.relatedObject;
  54. if(resp.filters.length)
  55. {
  56. pivot.filters = resp.filters;
  57. DataStorage.pivot = pivot;
  58. resp.filters.forEach(function(filter, index)
  59. {
  60. if(filter.from != 'query') return;
  61. if(filter.type != 'date' && filter.type != 'datetime') return;
  62. var find = $('#queryFilters').find('.filter-item-' + index + ' .form-' + filter.type);
  63. find.val(filter.default);
  64. });
  65. }
  66. drawTable(resp.fields, resp.rows);
  67. getFieldSettings();
  68. addResult(resp);
  69. initPager(resp);
  70. if(typeof callback == 'function') callback();
  71. }
  72. });
  73. }
  74. /**
  75. * Add query result.
  76. *
  77. * @access public
  78. */
  79. function addResult(resp)
  80. {
  81. $('#queryResult').remove();
  82. var lineCount = resp.lineCount;
  83. var columnCount = resp.columnCount;
  84. var queryMsg = queryResult;
  85. queryMsg = queryMsg.replace('%s', lineCount);
  86. queryMsg = queryMsg.replace('%s', columnCount);
  87. $('#queryTable .table-footer').append("<span style='float:left;line-height:28px' id='queryResult'>" + queryMsg + "</span>");
  88. }
  89. function initPager(resp)
  90. {
  91. var pageID = parseInt(resp.pageID);
  92. var recPerPage = parseInt(resp.recPerPage);
  93. var recTotal = parseInt(resp.lineCount);
  94. var pageTotal = parseInt(Math.ceil(recTotal / recPerPage));
  95. $('.recTotal').html(recTotalTip.replace('%s', recTotal));
  96. $('.recPerPage').html(recPerPageTip.replace('%s', recPerPage));
  97. $('.dropup li').removeClass('active');
  98. $('.dropup li a').each(function()
  99. {
  100. if($(this).data('size') == resp.recPerPage)
  101. {
  102. $(this).parent().addClass('active');
  103. return;
  104. }
  105. });
  106. $('.page-number').html('<strong>' + pageID + '</strong>/<strong>' + pageTotal + '</strong>');
  107. $('.left-page').data('page', pageID - 1);
  108. $('.right-page').data('page', pageID + 1);
  109. $('.last-page').data('page', pageTotal);
  110. $('.first-page,.left-page,.last-page,.right-page').removeClass('disabled');
  111. if(pageID == 1) $('.first-page,.left-page').addClass('disabled');
  112. if(pageID == pageTotal) $('.last-page,.right-page').addClass('disabled');
  113. $('.table-footer').toggle(!!recTotal);
  114. }
  115. /**
  116. * Save field settings.
  117. *
  118. * @access public
  119. * @return bool
  120. */
  121. function saveSettings()
  122. {
  123. var fieldSettings = DataStorage.clone('fieldSettings');
  124. var relatedObject = DataStorage.relatedObject;
  125. var objectFields = DataStorage.objectFields;
  126. for(let index in DataStorage.fields)
  127. {
  128. var relatedTable = $('#relatedTable' + index).val();
  129. var relatedField = $('#relatedField' + index).val();
  130. fieldSettings[index].object = relatedTable;
  131. fieldSettings[index].field = relatedField;
  132. if(relatedTable != relatedObject[index])
  133. {
  134. fieldSettings[index].type = 'object';
  135. if(typeof(objectFields) != 'undefined' && typeof(objectFields[relatedTable]) != 'undefined' && typeof(objectFields[relatedTable][index]) != 'undefined') fieldSettings[index].type = objectFields[relatedTable][index].type == 'object' ? 'string' : objectFields[relatedTable][index].type;
  136. }
  137. if(relatedTable == relatedObject[index] && fieldSettings[index].type == 'object') fieldSettings[index].type = 'string';
  138. }
  139. DataStorage.fieldSettings = fieldSettings;
  140. var langs = DataStorage.clone('langs');
  141. $("input[name^='langs']").each(function()
  142. {
  143. var field = $(this).data('field');
  144. var lang = $(this).data('lang');
  145. var value = $(this).val();
  146. if(typeof(langs[field]) == 'undefined') langs[field] = {};
  147. langs[field][lang] = value;
  148. })
  149. DataStorage.langs = langs;
  150. $('#addModal').modal('hide');
  151. this.drawTable(DataStorage.fields, DataStorage.rows);
  152. return false;
  153. }
  154. /**
  155. * Draw table content for sql result.
  156. *
  157. * @param object fields
  158. * @param array rows
  159. * @access public
  160. * @return void
  161. */
  162. function drawTable(fields, rows)
  163. {
  164. $.post(createLink('dataview', 'ajaxGetFieldName'), {fields: fields, fieldSettings: DataStorage.fieldSettings}, function(resp)
  165. {
  166. resp = JSON.parse(resp);
  167. if(resp.result == 'success') fields = resp.fields ? resp.fields : fields;
  168. $('.table-empty-tip').addClass('hidden');
  169. if(rows.length == 0)
  170. {
  171. $('.table-empty-tip').removeClass('hidden');
  172. $('table.result').empty();
  173. return;
  174. }
  175. var head = '<tr>';
  176. var langs = DataStorage.langs;
  177. for(let field in fields)
  178. {
  179. var fieldName = fields[field];
  180. if(!$.isEmptyObject(langs) && typeof(langs[field]) !== 'undefined') fieldName = langs[field][clientLang] ? langs[field][clientLang] : fieldName;
  181. head += '<th>' + fieldName + '</th>';
  182. }
  183. head += '</tr>';
  184. var html = '<thead>' + head + '</thead>';
  185. var body = '';
  186. for(let row of rows)
  187. {
  188. body += '<tr>';
  189. for(let index in row) body += '<td><div class="ellipsis-multi" title="' + row[index] + '">' + row[index] + '</div></td>';
  190. body += '</tr>';
  191. }
  192. html += '<tbody>' + body + '</tbody>';
  193. $('table.result').html(html);
  194. });
  195. }
  196. /**
  197. * Get text width.
  198. *
  199. * @param string text
  200. * @access public
  201. * @return float
  202. */
  203. function getTextWidth(text)
  204. {
  205. var font = "bold 12pt arial"
  206. var canvas = document.createElement("canvas");
  207. var context = canvas.getContext("2d");
  208. context.font = font;
  209. var measure = context.measureText(text);
  210. return measure.width;
  211. }
  212. /**
  213. * Get field settings.
  214. *
  215. * @access public
  216. * @return float
  217. */
  218. function getFieldSettings()
  219. {
  220. var fieldSettings = DataStorage.clone('fieldSettings');
  221. var fields = DataStorage.fields;
  222. var columns = DataStorage.columns;
  223. var relatedObject = DataStorage.relatedObject;
  224. var objectFields = DataStorage.objectFields;
  225. var fieldSettingsNew = {};
  226. for(let index in fields)
  227. {
  228. var field = fields[index];
  229. var defaultType = columns[index];
  230. var defaultObject = relatedObject[index];
  231. if(typeof(objectFields) != 'undefined' && typeof(objectFields[defaultObject]) != 'undefined' && typeof(objectFields[defaultObject][index]) != 'undefined') defaultType = objectFields[defaultObject][index].type == 'object' ? 'string' : objectFields[defaultObject][index].type;
  232. if(!fieldSettings[index])
  233. {
  234. fieldSettingsNew[index] = {
  235. name: field,
  236. object: defaultObject,
  237. field: index,
  238. type: defaultType
  239. };
  240. }
  241. else
  242. {
  243. var object = fieldSettings[index].object;
  244. if(!object || object.length == 0) object = defaultObject;
  245. fieldSettings[index].object = object;
  246. var field = fieldSettings[index].field;
  247. if(!field || field.length == 0)
  248. {
  249. fieldSettings[index].field = index;
  250. fieldSettings[index].object = defaultObject;
  251. fieldSettings[index].type = 'string';
  252. }
  253. if(!fieldSettings[index].name) fieldSettings[index].name = fields[index];
  254. var type = fieldSettings[index].type;
  255. if(object == defaultObject && type != defaultType) fieldSettings[index].type = defaultType;
  256. fieldSettingsNew[index] = fieldSettings[index];
  257. }
  258. }
  259. DataStorage.fieldSettings = fieldSettingsNew;
  260. }
  261. function submitForm()
  262. {
  263. if($('#fields').length == 0) $('#dataform table').before($('<input>').attr({name: 'fields', id: 'fields'}).addClass('hidden'));
  264. if($('#langs').length == 0) $('#dataform table').before($('<input>').attr({name: 'langs', id: 'langs'}).addClass('hidden'));
  265. getFieldSettings();
  266. /* Fix bug #26716. */
  267. var fieldSettings = DataStorage.clone('fieldSettings');
  268. var fields = DataStorage.fields;
  269. for(let index in fieldSettings)
  270. {
  271. if(!Object.keys(fields).includes(index)) delete fieldSettings[index];
  272. }
  273. DataStorage.fieldSettings = fieldSettings;
  274. $('#fields').val(JSON.stringify(DataStorage.fieldSettings));
  275. $('#langs').val(JSON.stringify(DataStorage.langs));
  276. $('#dataform').submit();
  277. }
  278. /**
  279. * Set related field.
  280. *
  281. * @param obj $obj
  282. * @access public
  283. * @return void
  284. */
  285. function setRelatedField(obj)
  286. {
  287. var selectedTable = $(obj).val();
  288. var relatedFields = [];
  289. var objectFields = DataStorage.objectFields;
  290. for(let index in objectFields[selectedTable]) relatedFields[index] = objectFields[selectedTable][index].name;
  291. var relatedFieldOptions = Object.keys(relatedFields).map(function(key)
  292. {
  293. return {text: relatedFields[key], value: key};
  294. });
  295. var $relatedField = $(obj).closest('tr').find("select[name^='relatedField']");
  296. var picker = $relatedField.data('zui.picker');
  297. if(picker) picker.destroy();
  298. $relatedField.picker({list: relatedFieldOptions, autoselectfirst: true});
  299. }
  300. /**
  301. * handle click table item in data dictionary
  302. *
  303. * @param obj $event
  304. * @access public
  305. * @return void
  306. */
  307. function handleClickDictTable(event)
  308. {
  309. if(!$(event.target).hasClass('list-toggle') && !$(event.target).closest('li').hasClass('field-item'))
  310. {
  311. const table = $(event.target).closest('li').data('dict');
  312. appendTextToSqlForm(table);
  313. event.stopPropagation();
  314. }
  315. }
  316. /**
  317. * handle click field item in data dictionary
  318. *
  319. * @param obj $event
  320. * @access public
  321. * @return void
  322. */
  323. function handleClickDictField(event)
  324. {
  325. const field = $(event.target).closest('li').data('dict');
  326. appendTextToSqlForm(field);
  327. }
  328. /**
  329. * append text to sql form.
  330. *
  331. * @param string $text
  332. * @access public
  333. * @return void
  334. */
  335. function appendTextToSqlForm(text)
  336. {
  337. const sqlForm = $('textarea[name="sql"]');
  338. sqlForm.val(sqlForm.val() + text);
  339. }
  340. /**
  341. * Active field.
  342. *
  343. * @param obj $obj
  344. * @access public
  345. * @return void
  346. */
  347. function activeField(obj)
  348. {
  349. if(currentTheme == 'default')
  350. {
  351. $(obj).closest('tr').find('#' + $(obj).data('field')).css('color', '#2e7fff');
  352. }
  353. else
  354. {
  355. $(obj).closest('tr').find('#' + $(obj).data('field')).addClass('text-primary');
  356. }
  357. }
  358. /**
  359. * Remove field active.
  360. *
  361. * @param obj $obj
  362. * @access public
  363. * @return void
  364. */
  365. function removeActive(obj)
  366. {
  367. if(currentTheme == 'default')
  368. {
  369. $(obj).closest('tr').find('#' + $(obj).data('field')).css('color', '#0b0f18');
  370. }
  371. else
  372. {
  373. $(obj).closest('tr').find('#' + $(obj).data('field')).removeClass('text-primary');
  374. }
  375. }
  376. $(document).ready(function()
  377. {
  378. $('#sql').on('input', function()
  379. {
  380. $('.error').addClass('hidden');
  381. // fieldSettings = {};
  382. })
  383. $('#sql').on('change', function()
  384. {
  385. DataStorage.fieldSettings = {};
  386. DataStorage.langs = {};
  387. })
  388. if($('#sql').val()) setTimeout(query, 500);
  389. $('.query').click(function()
  390. {
  391. DataStorage.pageID = 1;
  392. query();
  393. });
  394. $('.fieldSettings').click(function() {
  395. query(function() {
  396. var formTpl = $('#fieldSettingTpl').html();
  397. var formHtml = $(formTpl);
  398. var tbodyTpl = $('#tbodyTpl').html();
  399. var fieldTypeOptions = Object.keys(lang.objects).map(function(key)
  400. {
  401. return {text: lang.objects[key], value: key};
  402. });
  403. var fieldSettings = DataStorage.fieldSettings;
  404. var objectFields = DataStorage.objectFields;
  405. var langs = DataStorage.langs;
  406. var tbodyHtmls = Object.keys(fieldSettings).map(function(field)
  407. {
  408. var relatedFields = [];
  409. var relatedObjectFields = objectFields[fieldSettings[field].object];
  410. for(let index in relatedObjectFields) relatedFields[index] = relatedObjectFields[index].name;
  411. var relatedFieldOptions = Object.keys(relatedFields).map(function(key)
  412. {
  413. return {text: relatedFields[key], value: key};
  414. });
  415. var html = $($.zui.formatString(tbodyTpl, {field: field, name: fieldSettings[field].name}));
  416. html.find('select#relatedTable' + field).picker({list: fieldTypeOptions, defaultValue: fieldSettings[field].object});
  417. html.find('select#relatedField' + field).picker({list: relatedFieldOptions, defaultValue: fieldSettings[field].field});
  418. html.find("input[name^='langs']").each(function()
  419. {
  420. var field = $(this).data('field');
  421. var lang = $(this).data('lang');
  422. var fieldName = '';
  423. if(lang == clientLang)
  424. {
  425. var relatedFieldName = $(this).closest('tr').find('select#relatedField' + field + '~ div.picker').find('span.picker-selection-text').text();
  426. fieldName = relatedFieldName ? relatedFieldName : DataStorage.fields[field];
  427. }
  428. fieldName = !$.isEmptyObject(langs) && typeof(langs[field]) != 'undefined' && typeof(langs[field][lang]) != 'undefined' && langs[field][lang] ? langs[field][lang] : fieldName;
  429. $(this).val(fieldName);
  430. });
  431. return html;
  432. });
  433. formHtml.find('tbody').append(tbodyHtmls);
  434. var modal = $('#addModal');
  435. modal.find('.modal-body').html(formHtml);
  436. modal.modal({width: 500});
  437. })
  438. });
  439. $('#save').click(function()
  440. {
  441. if(typeof dataview !== 'undefined' && dataview.used)
  442. {
  443. bootbox.confirm(warningDesign, function(res) { if(res) query(submitForm); });
  444. }
  445. else
  446. {
  447. query(submitForm);
  448. }
  449. });
  450. $('.first-page,.left-page,.last-page,.right-page').click(function()
  451. {
  452. DataStorage.pageID = $(this).data('page');
  453. query();
  454. });
  455. $('.dropup li a').click(function()
  456. {
  457. DataStorage.pageID = 1;
  458. DataStorage.recPerPage = $(this).data('size');
  459. query();
  460. })
  461. });