db_structure.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /* vim: set expandtab sw=4 ts=4 sts=4: */
  2. /**
  3. * @fileoverview functions used on the database structure page
  4. * @name Database Structure
  5. *
  6. * @requires jQuery
  7. * @requires jQueryUI
  8. * @required js/functions.js
  9. */
  10. /**
  11. * AJAX scripts for db_structure.php
  12. *
  13. * Actions ajaxified here:
  14. * Drop Database
  15. * Truncate Table
  16. * Drop Table
  17. *
  18. */
  19. /**
  20. * Unbind all event handlers before tearing down a page
  21. */
  22. AJAX.registerTeardown('db_structure.js', function () {
  23. $(document).off('click', 'a.truncate_table_anchor.ajax');
  24. $(document).off('click', 'a.drop_table_anchor.ajax');
  25. $(document).off('click', '#real_end_input');
  26. $(document).off('click', 'a.favorite_table_anchor.ajax');
  27. $(document).off('click', '#printView');
  28. $('a.real_row_count').off('click');
  29. $('a.row_count_sum').off('click');
  30. $('select[name=submit_mult]').off('change');
  31. });
  32. /**
  33. * Adjust number of rows and total size in the summary
  34. * when truncating, creating, dropping or inserting into a table
  35. */
  36. function PMA_adjustTotals () {
  37. var byteUnits = [
  38. PMA_messages.strB,
  39. PMA_messages.strKiB,
  40. PMA_messages.strMiB,
  41. PMA_messages.strGiB,
  42. PMA_messages.strTiB,
  43. PMA_messages.strPiB,
  44. PMA_messages.strEiB
  45. ];
  46. /**
  47. * @var $allTr jQuery object that references all the rows in the list of tables
  48. */
  49. var $allTr = $('#tablesForm').find('table.data tbody:first tr');
  50. // New summary values for the table
  51. var tableSum = $allTr.size();
  52. var rowsSum = 0;
  53. var sizeSum = 0;
  54. var overheadSum = 0;
  55. var rowSumApproximated = false;
  56. $allTr.each(function () {
  57. var $this = $(this);
  58. var i;
  59. var tmpVal;
  60. // Get the number of rows for this SQL table
  61. var strRows = $this.find('.tbl_rows').text();
  62. // If the value is approximated
  63. if (strRows.indexOf('~') === 0) {
  64. rowSumApproximated = true;
  65. // The approximated value contains a preceding ~ (Eg 100 --> ~100)
  66. strRows = strRows.substring(1, strRows.length);
  67. }
  68. strRows = strRows.replace(/[,.]/g, '');
  69. var intRow = parseInt(strRows, 10);
  70. if (! isNaN(intRow)) {
  71. rowsSum += intRow;
  72. }
  73. // Extract the size and overhead
  74. var valSize = 0;
  75. var valOverhead = 0;
  76. var strSize = $.trim($this.find('.tbl_size span:not(.unit)').text());
  77. var strSizeUnit = $.trim($this.find('.tbl_size span.unit').text());
  78. var strOverhead = $.trim($this.find('.tbl_overhead span:not(.unit)').text());
  79. var strOverheadUnit = $.trim($this.find('.tbl_overhead span.unit').text());
  80. // Given a value and a unit, such as 100 and KiB, for the table size
  81. // and overhead calculate their numeric values in bytes, such as 102400
  82. for (i = 0; i < byteUnits.length; i++) {
  83. if (strSizeUnit === byteUnits[i]) {
  84. tmpVal = parseFloat(strSize);
  85. valSize = tmpVal * Math.pow(1024, i);
  86. break;
  87. }
  88. }
  89. for (i = 0; i < byteUnits.length; i++) {
  90. if (strOverheadUnit === byteUnits[i]) {
  91. tmpVal = parseFloat(strOverhead);
  92. valOverhead = tmpVal * Math.pow(1024, i);
  93. break;
  94. }
  95. }
  96. sizeSum += valSize;
  97. overheadSum += valOverhead;
  98. });
  99. // Add some commas for readability:
  100. // 1000000 becomes 1,000,000
  101. var strRowSum = rowsSum + '';
  102. var regex = /(\d+)(\d{3})/;
  103. while (regex.test(strRowSum)) {
  104. strRowSum = strRowSum.replace(regex, '$1' + ',' + '$2');
  105. }
  106. // If approximated total value add ~ in front
  107. if (rowSumApproximated) {
  108. strRowSum = '~' + strRowSum;
  109. }
  110. // Calculate the magnitude for the size and overhead values
  111. var size_magnitude = 0;
  112. var overhead_magnitude = 0;
  113. while (sizeSum >= 1024) {
  114. sizeSum /= 1024;
  115. size_magnitude++;
  116. }
  117. while (overheadSum >= 1024) {
  118. overheadSum /= 1024;
  119. overhead_magnitude++;
  120. }
  121. sizeSum = Math.round(sizeSum * 10) / 10;
  122. overheadSum = Math.round(overheadSum * 10) / 10;
  123. // Update summary with new data
  124. var $summary = $('#tbl_summary_row');
  125. $summary.find('.tbl_num').text(PMA_sprintf(PMA_messages.strNTables, tableSum));
  126. if (rowSumApproximated) {
  127. $summary.find('.row_count_sum').text(strRowSum);
  128. } else {
  129. $summary.find('.tbl_rows').text(strRowSum);
  130. }
  131. $summary.find('.tbl_size').text(sizeSum + ' ' + byteUnits[size_magnitude]);
  132. $summary.find('.tbl_overhead').text(overheadSum + ' ' + byteUnits[overhead_magnitude]);
  133. }
  134. /**
  135. * Gets the real row count for a table or DB.
  136. * @param object $target Target for appending the real count value.
  137. */
  138. function PMA_fetchRealRowCount ($target) {
  139. var $throbber = $('#pma_navigation').find('.throbber')
  140. .first()
  141. .clone()
  142. .css({ visibility: 'visible', display: 'inline-block' })
  143. .click(false);
  144. $target.html($throbber);
  145. $.ajax({
  146. type: 'GET',
  147. url: $target.attr('href'),
  148. cache: false,
  149. dataType: 'json',
  150. success: function (response) {
  151. if (response.success) {
  152. // If to update all row counts for a DB.
  153. if (response.real_row_count_all) {
  154. $.each(JSON.parse(response.real_row_count_all),
  155. function (index, table) {
  156. // Update each table row count.
  157. $('table.data td[data-table*="' + table.table + '"]')
  158. .text(table.row_count);
  159. }
  160. );
  161. }
  162. // If to update a particular table's row count.
  163. if (response.real_row_count) {
  164. // Append the parent cell with real row count.
  165. $target.parent().text(response.real_row_count);
  166. }
  167. // Adjust the 'Sum' displayed at the bottom.
  168. PMA_adjustTotals();
  169. } else {
  170. PMA_ajaxShowMessage(PMA_messages.strErrorRealRowCount);
  171. }
  172. },
  173. error: function () {
  174. PMA_ajaxShowMessage(PMA_messages.strErrorRealRowCount);
  175. }
  176. });
  177. }
  178. AJAX.registerOnload('db_structure.js', function () {
  179. /**
  180. * function to open the confirmation dialog for making table consistent with central list
  181. *
  182. * @param string msg message text to be displayed to user
  183. * @param function success function to be called on success
  184. *
  185. */
  186. var jqConfirm = function (msg, success) {
  187. var dialogObj = $('<div class=\'hide\'>' + msg + '</div>');
  188. $('body').append(dialogObj);
  189. var buttonOptions = {};
  190. buttonOptions[PMA_messages.strContinue] = function () {
  191. success();
  192. $(this).dialog('close');
  193. };
  194. buttonOptions[PMA_messages.strCancel] = function () {
  195. $(this).dialog('close');
  196. $('#tablesForm')[0].reset();
  197. };
  198. $(dialogObj).dialog({
  199. resizable: false,
  200. modal: true,
  201. title: PMA_messages.confirmTitle,
  202. buttons: buttonOptions
  203. });
  204. };
  205. /**
  206. * Event handler on select of "Make consistent with central list"
  207. */
  208. $('select[name=submit_mult]').change(function (event) {
  209. if ($(this).val() === 'make_consistent_with_central_list') {
  210. event.preventDefault();
  211. event.stopPropagation();
  212. jqConfirm(
  213. PMA_messages.makeConsistentMessage, function () {
  214. $('#tablesForm').submit();
  215. }
  216. );
  217. return false;
  218. } else if ($(this).val() === 'copy_tbl' || $(this).val() === 'add_prefix_tbl' || $(this).val() === 'replace_prefix_tbl' || $(this).val() === 'copy_tbl_change_prefix') {
  219. event.preventDefault();
  220. event.stopPropagation();
  221. if ($('input[name="selected_tbl[]"]:checked').length === 0) {
  222. return false;
  223. }
  224. var formData = $('#tablesForm').serialize();
  225. var modalTitle = '';
  226. if ($(this).val() === 'copy_tbl') {
  227. modalTitle = PMA_messages.strCopyTablesTo;
  228. } else if ($(this).val() === 'add_prefix_tbl') {
  229. modalTitle = PMA_messages.strAddPrefix;
  230. } else if ($(this).val() === 'replace_prefix_tbl') {
  231. modalTitle = PMA_messages.strReplacePrefix;
  232. } else if ($(this).val() === 'copy_tbl_change_prefix') {
  233. modalTitle = PMA_messages.strCopyPrefix;
  234. }
  235. $.ajax({
  236. type: 'POST',
  237. url: 'db_structure.php',
  238. dataType: 'html',
  239. data: formData
  240. }).done(function (data) {
  241. var dialogObj = $('<div class=\'hide\'>' + data + '</div>');
  242. $('body').append(dialogObj);
  243. var buttonOptions = {};
  244. buttonOptions[PMA_messages.strContinue] = function () {
  245. $('#ajax_form').submit();
  246. $(this).dialog('close');
  247. };
  248. buttonOptions[PMA_messages.strCancel] = function () {
  249. $(this).dialog('close');
  250. $('#tablesForm')[0].reset();
  251. };
  252. $(dialogObj).dialog({
  253. minWidth: 500,
  254. resizable: false,
  255. modal: true,
  256. title: modalTitle,
  257. buttons: buttonOptions
  258. });
  259. });
  260. } else {
  261. $('#tablesForm').submit();
  262. }
  263. });
  264. /**
  265. * Ajax Event handler for 'Truncate Table'
  266. */
  267. $(document).on('click', 'a.truncate_table_anchor.ajax', function (event) {
  268. event.preventDefault();
  269. /**
  270. * @var $this_anchor Object referring to the anchor clicked
  271. */
  272. var $this_anchor = $(this);
  273. // extract current table name and build the question string
  274. /**
  275. * @var curr_table_name String containing the name of the table to be truncated
  276. */
  277. var curr_table_name = $this_anchor.parents('tr').children('th').children('a').text();
  278. /**
  279. * @var question String containing the question to be asked for confirmation
  280. */
  281. var question = PMA_messages.strTruncateTableStrongWarning + ' ' +
  282. PMA_sprintf(PMA_messages.strDoYouReally, 'TRUNCATE `' + escapeHtml(curr_table_name) + '`') +
  283. getForeignKeyCheckboxLoader();
  284. $this_anchor.PMA_confirm(question, $this_anchor.attr('href'), function (url) {
  285. PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
  286. var params = getJSConfirmCommonParam(this, $this_anchor.getPostData());
  287. $.post(url, params, function (data) {
  288. if (typeof data !== 'undefined' && data.success === true) {
  289. PMA_ajaxShowMessage(data.message);
  290. // Adjust table statistics
  291. var $tr = $this_anchor.closest('tr');
  292. $tr.find('.tbl_rows').text('0');
  293. $tr.find('.tbl_size, .tbl_overhead').text('-');
  294. // Fetch inner span of this anchor
  295. // and replace the icon with its disabled version
  296. var span = $this_anchor.html().replace(/b_empty/, 'bd_empty');
  297. // To disable further attempts to truncate the table,
  298. // replace the a element with its inner span (modified)
  299. $this_anchor
  300. .replaceWith(span)
  301. .removeClass('truncate_table_anchor');
  302. PMA_adjustTotals();
  303. } else {
  304. PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + ' : ' + data.error, false);
  305. }
  306. }); // end $.post()
  307. }, loadForeignKeyCheckbox); // end $.PMA_confirm()
  308. }); // end of Truncate Table Ajax action
  309. /**
  310. * Ajax Event handler for 'Drop Table' or 'Drop View'
  311. */
  312. $(document).on('click', 'a.drop_table_anchor.ajax', function (event) {
  313. event.preventDefault();
  314. var $this_anchor = $(this);
  315. // extract current table name and build the question string
  316. /**
  317. * @var $curr_row Object containing reference to the current row
  318. */
  319. var $curr_row = $this_anchor.parents('tr');
  320. /**
  321. * @var curr_table_name String containing the name of the table to be truncated
  322. */
  323. var curr_table_name = $curr_row.children('th').children('a').text();
  324. /**
  325. * @var is_view Boolean telling if we have a view
  326. */
  327. var is_view = $curr_row.hasClass('is_view') || $this_anchor.hasClass('view');
  328. /**
  329. * @var question String containing the question to be asked for confirmation
  330. */
  331. var question;
  332. if (! is_view) {
  333. question = PMA_messages.strDropTableStrongWarning + ' ' +
  334. PMA_sprintf(PMA_messages.strDoYouReally, 'DROP TABLE `' + escapeHtml(curr_table_name) + '`');
  335. } else {
  336. question =
  337. PMA_sprintf(PMA_messages.strDoYouReally, 'DROP VIEW `' + escapeHtml(curr_table_name) + '`');
  338. }
  339. question += getForeignKeyCheckboxLoader();
  340. $this_anchor.PMA_confirm(question, $this_anchor.attr('href'), function (url) {
  341. var $msg = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
  342. var params = getJSConfirmCommonParam(this, $this_anchor.getPostData());
  343. $.post(url, params, function (data) {
  344. if (typeof data !== 'undefined' && data.success === true) {
  345. PMA_ajaxShowMessage(data.message);
  346. $curr_row.hide('medium').remove();
  347. PMA_adjustTotals();
  348. PMA_reloadNavigation();
  349. PMA_ajaxRemoveMessage($msg);
  350. } else {
  351. PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + ' : ' + data.error, false);
  352. }
  353. }); // end $.post()
  354. }, loadForeignKeyCheckbox); // end $.PMA_confirm()
  355. }); // end of Drop Table Ajax action
  356. /**
  357. * Attach Event Handler for 'Print' link
  358. */
  359. $(document).on('click', '#printView', function (event) {
  360. event.preventDefault();
  361. // Take to preview mode
  362. printPreview();
  363. }); // end of Print View action
  364. // Calculate Real End for InnoDB
  365. /**
  366. * Ajax Event handler for calculating the real end for a InnoDB table
  367. *
  368. */
  369. $(document).on('click', '#real_end_input', function (event) {
  370. event.preventDefault();
  371. /**
  372. * @var question String containing the question to be asked for confirmation
  373. */
  374. var question = PMA_messages.strOperationTakesLongTime;
  375. $(this).PMA_confirm(question, '', function () {
  376. return true;
  377. });
  378. return false;
  379. }); // end Calculate Real End for InnoDB
  380. // Add tooltip to favorite icons.
  381. $('.favorite_table_anchor').each(function () {
  382. PMA_tooltip(
  383. $(this),
  384. 'a',
  385. $(this).attr('title')
  386. );
  387. });
  388. // Get real row count via Ajax.
  389. $('a.real_row_count').on('click', function (event) {
  390. event.preventDefault();
  391. PMA_fetchRealRowCount($(this));
  392. });
  393. // Get all real row count.
  394. $('a.row_count_sum').on('click', function (event) {
  395. event.preventDefault();
  396. PMA_fetchRealRowCount($(this));
  397. });
  398. }); // end $()