rte.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. /* vim: set expandtab sw=4 ts=4 sts=4: */
  2. /**
  3. * JavaScript functionality for Routines, Triggers and Events.
  4. *
  5. * @package PhpMyadmin
  6. */
  7. /**
  8. * @var RTE Contains all the JavaScript functionality
  9. * for Routines, Triggers and Events
  10. */
  11. var RTE = {
  12. /**
  13. * Construct for the object that provides the
  14. * functionality for Routines, Triggers and Events
  15. */
  16. object: function (type) {
  17. $.extend(this, RTE.COMMON);
  18. switch (type) {
  19. case 'routine':
  20. $.extend(this, RTE.ROUTINE);
  21. break;
  22. case 'trigger':
  23. // nothing extra yet for triggers
  24. break;
  25. case 'event':
  26. $.extend(this, RTE.EVENT);
  27. break;
  28. default:
  29. break;
  30. }
  31. },
  32. /**
  33. * @var string param_template Template for a row in the routine editor
  34. */
  35. param_template: ''
  36. };
  37. /**
  38. * @var RTE.COMMON a JavaScript namespace containing the functionality
  39. * for Routines, Triggers and Events
  40. *
  41. * This namespace is extended by the functionality required
  42. * to handle a specific item (a routine, trigger or event)
  43. * in the relevant javascript files in this folder
  44. */
  45. RTE.COMMON = {
  46. /**
  47. * @var $ajaxDialog Query object containing the reference to the
  48. * dialog that contains the editor
  49. */
  50. $ajaxDialog: null,
  51. /**
  52. * @var syntaxHiglighter Reference to the codemirror editor
  53. */
  54. syntaxHiglighter: null,
  55. /**
  56. * @var buttonOptions Object containing options for
  57. * the jQueryUI dialog buttons
  58. */
  59. buttonOptions: {},
  60. /**
  61. * Validate editor form fields.
  62. */
  63. validate: function () {
  64. /**
  65. * @var $elm a jQuery object containing the reference
  66. * to an element that is being validated
  67. */
  68. var $elm = null;
  69. // Common validation. At the very least the name
  70. // and the definition must be provided for an item
  71. $elm = $('table.rte_table').last().find('input[name=item_name]');
  72. if ($elm.val() === '') {
  73. $elm.focus();
  74. alert(PMA_messages['strFormEmpty']);
  75. return false;
  76. }
  77. $elm = $('table.rte_table').find('textarea[name=item_definition]');
  78. if ($elm.val() === '') {
  79. if (this.syntaxHiglighter !== null) {
  80. this.syntaxHiglighter.focus();
  81. }
  82. else {
  83. $('textarea[name=item_definition]').last().focus();
  84. }
  85. alert(PMA_messages['strFormEmpty']);
  86. return false;
  87. }
  88. // The validation has so far passed, so now
  89. // we can validate item-specific fields.
  90. return this.validateCustom();
  91. }, // end validate()
  92. /**
  93. * Validate custom editor form fields.
  94. * This function can be overridden by
  95. * other files in this folder
  96. */
  97. validateCustom: function () {
  98. return true;
  99. }, // end validateCustom()
  100. /**
  101. * Execute some code after the ajax
  102. * dialog for the ditor is shown.
  103. * This function can be overridden by
  104. * other files in this folder
  105. */
  106. postDialogShow: function () {
  107. // Nothing by default
  108. }, // end postDialogShow()
  109. exportDialog: function ($this) {
  110. var $msg = PMA_ajaxShowMessage();
  111. // Fire the ajax request straight away
  112. $.get($this.attr('href'), {'ajax_request': true}, function (data) {
  113. if (data.success === true) {
  114. PMA_ajaxRemoveMessage($msg);
  115. /**
  116. * @var button_options Object containing options
  117. * for jQueryUI dialog buttons
  118. */
  119. var button_options = {};
  120. button_options[PMA_messages['strClose']] = function () {
  121. $(this).dialog("close").remove();
  122. };
  123. /**
  124. * Display the dialog to the user
  125. */
  126. var $ajaxDialog = $('<div>' + data.message + '</div>').dialog({
  127. width: 500,
  128. buttons: button_options,
  129. title: data.title
  130. });
  131. // Attach syntax highlited editor to export dialog
  132. /**
  133. * @var $elm jQuery object containing the reference
  134. * to the Export textarea.
  135. */
  136. var $elm = $ajaxDialog.find('textarea');
  137. /**
  138. * @var opts Options to pass to the codemirror editor
  139. */
  140. var opts = {
  141. lineNumbers: true,
  142. matchBrackets: true,
  143. indentUnit: 4,
  144. mode: "text/x-mysql"
  145. };
  146. CodeMirror.fromTextArea($elm[0], opts);
  147. } else {
  148. PMA_ajaxShowMessage(data.error, false);
  149. }
  150. }); // end $.get()
  151. }, // end exportDialog()
  152. editorDialog: function (is_new, $this) {
  153. var that = this;
  154. /**
  155. * @var $edit_row jQuery object containing the reference to
  156. * the row of the the item being edited
  157. * from the list of items
  158. */
  159. var $edit_row = null;
  160. if ($this.hasClass('edit_anchor')) {
  161. // Remeber the row of the item being edited for later,
  162. // so that if the edit is successful, we can replace the
  163. // row with info about the modified item.
  164. $edit_row = $this.parents('tr');
  165. }
  166. /**
  167. * @var $msg jQuery object containing the reference to
  168. * the AJAX message shown to the user
  169. */
  170. var $msg = PMA_ajaxShowMessage();
  171. $.get($this.attr('href'), {'ajax_request': true}, function (data) {
  172. if (data.success === true) {
  173. // We have successfully fetched the editor form
  174. PMA_ajaxRemoveMessage($msg);
  175. // Now define the function that is called when
  176. // the user presses the "Go" button
  177. that.buttonOptions[PMA_messages['strGo']] = function () {
  178. // Move the data from the codemirror editor back to the
  179. // textarea, where it can be used in the form submission.
  180. if (typeof CodeMirror != 'undefined') {
  181. that.syntaxHiglighter.save();
  182. }
  183. // Validate editor and submit request, if passed.
  184. if (that.validate()) {
  185. /**
  186. * @var data Form data to be sent in the AJAX request
  187. */
  188. var data = $('form.rte_form').last().serialize();
  189. $msg = PMA_ajaxShowMessage(
  190. PMA_messages['strProcessingRequest']
  191. );
  192. var url = $('form.rte_form').last().attr('action');
  193. $.post(url, data, function (data) {
  194. if (data.success === true) {
  195. // Item created successfully
  196. PMA_ajaxRemoveMessage($msg);
  197. PMA_slidingMessage(data.message);
  198. that.$ajaxDialog.dialog('close');
  199. // If we are in 'edit' mode, we must
  200. // remove the reference to the old row.
  201. if (mode === 'edit') {
  202. $edit_row.remove();
  203. }
  204. // Sometimes, like when moving a trigger from
  205. // a table to another one, the new row should
  206. // not be inserted into the list. In this case
  207. // "data.insert" will be set to false.
  208. if (data.insert) {
  209. // Insert the new row at the correct
  210. // location in the list of items
  211. /**
  212. * @var text Contains the name of an item from
  213. * the list that is used in comparisons
  214. * to find the correct location where
  215. * to insert a new row.
  216. */
  217. var text = '';
  218. /**
  219. * @var inserted Whether a new item has been
  220. * inserted in the list or not
  221. */
  222. var inserted = false;
  223. $('table.data').find('tr').each(function () {
  224. text = $(this)
  225. .children('td')
  226. .eq(0)
  227. .find('strong')
  228. .text()
  229. .toUpperCase();
  230. text = $.trim(text);
  231. if (text !== '' && text > data.name) {
  232. $(this).before(data.new_row);
  233. inserted = true;
  234. return false;
  235. }
  236. });
  237. if (! inserted) {
  238. // If we didn't manage to insert the row yet,
  239. // it must belong at the end of the list,
  240. // so we insert it there.
  241. $('table.data').append(data.new_row);
  242. }
  243. // Fade-in the new row
  244. $('tr.ajaxInsert')
  245. .show('slow')
  246. .removeClass('ajaxInsert');
  247. } else if ($('table.data').find('tr').has('td').length === 0) {
  248. // If we are not supposed to insert the new row,
  249. // we will now check if the table is empty and
  250. // needs to be hidden. This will be the case if
  251. // we were editing the only item in the list,
  252. // which we removed and will not be inserting
  253. // something else in its place.
  254. $('table.data').hide("slow", function () {
  255. $('#nothing2display').show("slow");
  256. });
  257. }
  258. // Now we have inserted the row at the correct
  259. // position, but surely at least some row classes
  260. // are wrong now. So we will itirate throught
  261. // all rows and assign correct classes to them
  262. /**
  263. * @var ct Count of processed rows
  264. */
  265. var ct = 0;
  266. /**
  267. * @var rowclass Class to be attached to the row
  268. * that is being processed
  269. */
  270. var rowclass = '';
  271. $('table.data').find('tr').has('td').each(function () {
  272. rowclass = (ct % 2 === 0) ? 'odd' : 'even';
  273. $(this).removeClass().addClass(rowclass);
  274. ct++;
  275. });
  276. // If this is the first item being added, remove
  277. // the "No items" message and show the list.
  278. if ($('table.data').find('tr').has('td').length > 0
  279. && $('#nothing2display').is(':visible')) {
  280. $('#nothing2display').hide("slow", function () {
  281. $('table.data').show("slow");
  282. });
  283. }
  284. PMA_reloadNavigation();
  285. } else {
  286. PMA_ajaxShowMessage(data.error, false);
  287. }
  288. }); // end $.post()
  289. } // end "if (that.validate())"
  290. }; // end of function that handles the submission of the Editor
  291. that.buttonOptions[PMA_messages['strClose']] = function () {
  292. $(this).dialog("close");
  293. };
  294. /**
  295. * Display the dialog to the user
  296. */
  297. that.$ajaxDialog = $('<div>' + data.message + '</div>').dialog({
  298. width: 700,
  299. minWidth: 500,
  300. buttons: that.buttonOptions,
  301. title: data.title,
  302. modal: true,
  303. close: function () {
  304. $(this).remove();
  305. }
  306. });
  307. that.$ajaxDialog.find('input[name=item_name]').focus();
  308. that.$ajaxDialog.find('input.datefield, input.datetimefield').each(function () {
  309. PMA_addDatepicker($(this).css('width', '95%'));
  310. });
  311. /**
  312. * @var mode Used to remeber whether the editor is in
  313. * "Edit" or "Add" mode
  314. */
  315. var mode = 'add';
  316. if ($('input[name=editor_process_edit]').length > 0) {
  317. mode = 'edit';
  318. }
  319. // Attach syntax highlited editor to the definition
  320. /**
  321. * @var elm jQuery object containing the reference to
  322. * the Definition textarea.
  323. */
  324. var $elm = $('textarea[name=item_definition]').last();
  325. /**
  326. * @var opts Options to pass to the codemirror editor
  327. */
  328. var opts = {
  329. lineNumbers: true,
  330. matchBrackets: true,
  331. indentUnit: 4,
  332. mode: "text/x-mysql"
  333. };
  334. if (typeof CodeMirror != 'undefined') {
  335. that.syntaxHiglighter = CodeMirror.fromTextArea($elm[0], opts);
  336. }
  337. // Execute item-specific code
  338. that.postDialogShow(data);
  339. } else {
  340. PMA_ajaxShowMessage(data.error, false);
  341. }
  342. }); // end $.get()
  343. },
  344. dropDialog: function ($this) {
  345. /**
  346. * @var $curr_row Object containing reference to the current row
  347. */
  348. var $curr_row = $this.parents('tr');
  349. /**
  350. * @var question String containing the question to be asked for confirmation
  351. */
  352. var question = $('<div/>').text(
  353. $curr_row.children('td').children('.drop_sql').html()
  354. );
  355. // We ask for confirmation first here, before submitting the ajax request
  356. $this.PMA_confirm(question, $this.attr('href'), function (url) {
  357. /**
  358. * @var msg jQuery object containing the reference to
  359. * the AJAX message shown to the user
  360. */
  361. var $msg = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
  362. $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function (data) {
  363. if (data.success === true) {
  364. /**
  365. * @var $table Object containing reference
  366. * to the main list of elements
  367. */
  368. var $table = $curr_row.parent();
  369. // Check how many rows will be left after we remove
  370. // the one that the user has requested us to remove
  371. if ($table.find('tr').length === 3) {
  372. // If there are two rows left, it means that they are
  373. // the header of the table and the rows that we are
  374. // about to remove, so after the removal there will be
  375. // nothing to show in the table, so we hide it.
  376. $table.hide("slow", function () {
  377. $(this).find('tr.even, tr.odd').remove();
  378. $('#nothing2display').show("slow");
  379. });
  380. } else {
  381. $curr_row.hide("slow", function () {
  382. $(this).remove();
  383. // Now we have removed the row from the list, but maybe
  384. // some row classes are wrong now. So we will itirate
  385. // throught all rows and assign correct classes to them.
  386. /**
  387. * @var ct Count of processed rows
  388. */
  389. var ct = 0;
  390. /**
  391. * @var rowclass Class to be attached to the row
  392. * that is being processed
  393. */
  394. var rowclass = '';
  395. $table.find('tr').has('td').each(function () {
  396. rowclass = (ct % 2 === 0) ? 'odd' : 'even';
  397. $(this).removeClass().addClass(rowclass);
  398. ct++;
  399. });
  400. });
  401. }
  402. // Get rid of the "Loading" message
  403. PMA_ajaxRemoveMessage($msg);
  404. // Show the query that we just executed
  405. PMA_slidingMessage(data.sql_query);
  406. PMA_reloadNavigation();
  407. } else {
  408. PMA_ajaxShowMessage(data.error, false);
  409. }
  410. }); // end $.get()
  411. }); // end $.PMA_confirm()
  412. }
  413. }; // end RTE namespace
  414. /**
  415. * @var RTE.EVENT JavaScript functionality for events
  416. */
  417. RTE.EVENT = {
  418. validateCustom: function () {
  419. /**
  420. * @var elm a jQuery object containing the reference
  421. * to an element that is being validated
  422. */
  423. var $elm = null;
  424. if (this.$ajaxDialog.find('select[name=item_type]').find(':selected').val() === 'RECURRING') {
  425. // The interval field must not be empty for recurring events
  426. $elm = this.$ajaxDialog.find('input[name=item_interval_value]');
  427. if ($elm.val() === '') {
  428. $elm.focus();
  429. alert(PMA_messages['strFormEmpty']);
  430. return false;
  431. }
  432. } else {
  433. // The execute_at field must not be empty for "once off" events
  434. $elm = this.$ajaxDialog.find('input[name=item_execute_at]');
  435. if ($elm.val() === '') {
  436. $elm.focus();
  437. alert(PMA_messages['strFormEmpty']);
  438. return false;
  439. }
  440. }
  441. return true;
  442. }
  443. };
  444. /**
  445. * @var RTE.ROUTINE JavaScript functionality for routines
  446. */
  447. RTE.ROUTINE = {
  448. /**
  449. * Overriding the postDialogShow() function defined in common.js
  450. *
  451. * @param data JSON-encoded data from the ajax request
  452. */
  453. postDialogShow: function (data) {
  454. // Cache the template for a parameter table row
  455. RTE.param_template = data.param_template;
  456. var that = this;
  457. // Make adjustments in the dialog to make it AJAX compatible
  458. $('td.routine_param_remove').show();
  459. $('input[name=routine_removeparameter]').remove();
  460. $('input[name=routine_addparameter]').css('width', '100%');
  461. // Enable/disable the 'options' dropdowns for parameters as necessary
  462. $('table.routine_params_table').last().find('th[colspan=2]').attr('colspan', '1');
  463. $('table.routine_params_table').last().find('tr').has('td').each(function () {
  464. that.setOptionsForParameter(
  465. $(this).find('select[name^=item_param_type]'),
  466. $(this).find('input[name^=item_param_length]'),
  467. $(this).find('select[name^=item_param_opts_text]'),
  468. $(this).find('select[name^=item_param_opts_num]')
  469. );
  470. });
  471. // Enable/disable the 'options' dropdowns for
  472. // function return value as necessary
  473. this.setOptionsForParameter(
  474. $('table.rte_table').last().find('select[name=item_returntype]'),
  475. $('table.rte_table').last().find('input[name=item_returnlength]'),
  476. $('table.rte_table').last().find('select[name=item_returnopts_text]'),
  477. $('table.rte_table').last().find('select[name=item_returnopts_num]')
  478. );
  479. },
  480. /**
  481. * Overriding the validateCustom() function defined in common.js
  482. */
  483. validateCustom: function () {
  484. /**
  485. * @var isSuccess Stores the outcome of the validation
  486. */
  487. var isSuccess = true;
  488. /**
  489. * @var inputname The value of the "name" attribute for
  490. * the field that is being processed
  491. */
  492. var inputname = '';
  493. this.$ajaxDialog.find('table.routine_params_table').last().find('tr').each(function () {
  494. // Every parameter of a routine must have
  495. // a non-empty direction, name and type
  496. if (isSuccess) {
  497. $(this).find(':input').each(function () {
  498. inputname = $(this).attr('name');
  499. if (inputname.substr(0, 14) === 'item_param_dir' ||
  500. inputname.substr(0, 15) === 'item_param_name' ||
  501. inputname.substr(0, 15) === 'item_param_type') {
  502. if ($(this).val() === '') {
  503. $(this).focus();
  504. isSuccess = false;
  505. return false;
  506. }
  507. }
  508. });
  509. } else {
  510. return false;
  511. }
  512. });
  513. if (! isSuccess) {
  514. alert(PMA_messages['strFormEmpty']);
  515. return false;
  516. }
  517. this.$ajaxDialog.find('table.routine_params_table').last().find('tr').each(function () {
  518. // SET, ENUM, VARCHAR and VARBINARY fields must have length/values
  519. var $inputtyp = $(this).find('select[name^=item_param_type]');
  520. var $inputlen = $(this).find('input[name^=item_param_length]');
  521. if ($inputtyp.length && $inputlen.length) {
  522. if (($inputtyp.val() === 'ENUM' || $inputtyp.val() === 'SET' || $inputtyp.val().substr(0, 3) === 'VAR')
  523. && $inputlen.val() === '') {
  524. $inputlen.focus();
  525. isSuccess = false;
  526. return false;
  527. }
  528. }
  529. });
  530. if (! isSuccess) {
  531. alert(PMA_messages['strFormEmpty']);
  532. return false;
  533. }
  534. if (this.$ajaxDialog.find('select[name=item_type]').find(':selected').val() === 'FUNCTION') {
  535. // The length/values of return variable for functions must
  536. // be set, if the type is SET, ENUM, VARCHAR or VARBINARY.
  537. var $returntyp = this.$ajaxDialog.find('select[name=item_returntype]');
  538. var $returnlen = this.$ajaxDialog.find('input[name=item_returnlength]');
  539. if (($returntyp.val() === 'ENUM' || $returntyp.val() === 'SET' || $returntyp.val().substr(0, 3) === 'VAR')
  540. && $returnlen.val() === '') {
  541. $returnlen.focus();
  542. alert(PMA_messages['strFormEmpty']);
  543. return false;
  544. }
  545. }
  546. if ($('select[name=item_type]').find(':selected').val() === 'FUNCTION') {
  547. // A function must contain a RETURN statement in its definition
  548. if (this.$ajaxDialog.find('table.rte_table').find('textarea[name=item_definition]').val().toUpperCase().indexOf('RETURN') < 0) {
  549. this.syntaxHiglighter.focus();
  550. alert(PMA_messages['MissingReturn']);
  551. return false;
  552. }
  553. }
  554. return true;
  555. },
  556. /**
  557. * Enable/disable the "options" dropdown and "length" input for
  558. * parameters and the return variable in the routine editor
  559. * as necessary.
  560. *
  561. * @param type a jQuery object containing the reference
  562. * to the "Type" dropdown box
  563. * @param len a jQuery object containing the reference
  564. * to the "Length" input box
  565. * @param text a jQuery object containing the reference
  566. * to the dropdown box with options for
  567. * parameters of text type
  568. * @param num a jQuery object containing the reference
  569. * to the dropdown box with options for
  570. * parameters of numeric type
  571. */
  572. setOptionsForParameter: function ($type, $len, $text, $num) {
  573. /**
  574. * @var no_opts a jQuery object containing the reference
  575. * to an element to be displayed when no
  576. * options are available
  577. */
  578. var $no_opts = $text.parent().parent().find('.no_opts');
  579. /**
  580. * @var no_len a jQuery object containing the reference
  581. * to an element to be displayed when no
  582. * "length/values" field is available
  583. */
  584. var $no_len = $len.parent().parent().find('.no_len');
  585. // Process for parameter options
  586. switch ($type.val()) {
  587. case 'TINYINT':
  588. case 'SMALLINT':
  589. case 'MEDIUMINT':
  590. case 'INT':
  591. case 'BIGINT':
  592. case 'DECIMAL':
  593. case 'FLOAT':
  594. case 'DOUBLE':
  595. case 'REAL':
  596. $text.parent().hide();
  597. $num.parent().show();
  598. $no_opts.hide();
  599. break;
  600. case 'TINYTEXT':
  601. case 'TEXT':
  602. case 'MEDIUMTEXT':
  603. case 'LONGTEXT':
  604. case 'CHAR':
  605. case 'VARCHAR':
  606. case 'SET':
  607. case 'ENUM':
  608. $text.parent().show();
  609. $num.parent().hide();
  610. $no_opts.hide();
  611. break;
  612. default:
  613. $text.parent().hide();
  614. $num.parent().hide();
  615. $no_opts.show();
  616. break;
  617. }
  618. // Process for parameter length
  619. switch ($type.val()) {
  620. case 'DATE':
  621. case 'DATETIME':
  622. case 'TIME':
  623. case 'TINYBLOB':
  624. case 'TINYTEXT':
  625. case 'BLOB':
  626. case 'TEXT':
  627. case 'MEDIUMBLOB':
  628. case 'MEDIUMTEXT':
  629. case 'LONGBLOB':
  630. case 'LONGTEXT':
  631. $text.closest('tr').find('a:first').hide();
  632. $len.parent().hide();
  633. $no_len.show();
  634. break;
  635. default:
  636. if ($type.val() == 'ENUM' || $type.val() == 'SET') {
  637. $text.closest('tr').find('a:first').show();
  638. } else {
  639. $text.closest('tr').find('a:first').hide();
  640. }
  641. $len.parent().show();
  642. $no_len.hide();
  643. break;
  644. }
  645. },
  646. executeDialog: function ($this) {
  647. var that = this;
  648. /**
  649. * @var msg jQuery object containing the reference to
  650. * the AJAX message shown to the user
  651. */
  652. var $msg = PMA_ajaxShowMessage();
  653. $.get($this.attr('href'), {'ajax_request': true}, function (data) {
  654. if (data.success === true) {
  655. PMA_ajaxRemoveMessage($msg);
  656. // If 'data.dialog' is true we show a dialog with a form
  657. // to get the input parameters for routine, otherwise
  658. // we just show the results of the query
  659. if (data.dialog) {
  660. // Define the function that is called when
  661. // the user presses the "Go" button
  662. that.buttonOptions[PMA_messages['strGo']] = function () {
  663. /**
  664. * @var data Form data to be sent in the AJAX request
  665. */
  666. var data = $('form.rte_form').last().serialize();
  667. $msg = PMA_ajaxShowMessage(
  668. PMA_messages['strProcessingRequest']
  669. );
  670. $.post('db_routines.php', data, function (data) {
  671. if (data.success === true) {
  672. // Routine executed successfully
  673. PMA_ajaxRemoveMessage($msg);
  674. PMA_slidingMessage(data.message);
  675. $ajaxDialog.dialog('close');
  676. } else {
  677. PMA_ajaxShowMessage(data.error, false);
  678. }
  679. });
  680. };
  681. that.buttonOptions[PMA_messages['strClose']] = function () {
  682. $(this).dialog("close");
  683. };
  684. /**
  685. * Display the dialog to the user
  686. */
  687. $ajaxDialog = $('<div>' + data.message + '</div>').dialog({
  688. width: 650,
  689. buttons: that.buttonOptions,
  690. title: data.title,
  691. modal: true,
  692. close: function () {
  693. $(this).remove();
  694. }
  695. });
  696. $ajaxDialog.find('input[name^=params]').first().focus();
  697. /**
  698. * Attach the datepickers to the relevant form fields
  699. */
  700. $ajaxDialog.find('input.datefield, input.datetimefield').each(function () {
  701. PMA_addDatepicker($(this).css('width', '95%'));
  702. });
  703. } else {
  704. // Routine executed successfully
  705. PMA_slidingMessage(data.message);
  706. }
  707. } else {
  708. PMA_ajaxShowMessage(data.error, false);
  709. }
  710. }); // end $.get()
  711. }
  712. };
  713. /**
  714. * Attach Ajax event handlers for the Routines, Triggers and Events editor
  715. *
  716. * FIXME: submit on ENTER keypress in dialog
  717. */
  718. $(function () {
  719. /**
  720. * Attach Ajax event handlers for the Add/Edit functionality.
  721. */
  722. $('a.ajax.add_anchor, a.ajax.edit_anchor').live('click', function (event) {
  723. event.preventDefault();
  724. var type = $(this).attr('href').substr(0, $(this).attr('href').indexOf('?'));
  725. if (type.indexOf('routine') != -1) {
  726. type = 'routine';
  727. } else if (type.indexOf('trigger') != -1) {
  728. type = 'trigger';
  729. } else if (type.indexOf('event') != -1) {
  730. type = 'event';
  731. } else {
  732. type = '';
  733. }
  734. var dialog = new RTE.object(type);
  735. dialog.editorDialog($(this).hasClass('add_anchor'), $(this));
  736. }); // end $.live()
  737. /**
  738. * Attach Ajax event handlers for the Execute routine functionality
  739. */
  740. $('a.ajax.exec_anchor').live('click', function (event) {
  741. event.preventDefault();
  742. var dialog = new RTE.object('routine');
  743. dialog.executeDialog($(this));
  744. }); // end $.live()
  745. /**
  746. * Attach Ajax event handlers for Export of Routines, Triggers and Events
  747. */
  748. $('a.ajax.export_anchor').live('click', function (event) {
  749. event.preventDefault();
  750. var dialog = new RTE.object();
  751. dialog.exportDialog($(this));
  752. }); // end $.live()
  753. /**
  754. * Attach Ajax event handlers for Drop functionality
  755. * of Routines, Triggers and Events.
  756. */
  757. $('a.ajax.drop_anchor').live('click', function (event) {
  758. event.preventDefault();
  759. var dialog = new RTE.object();
  760. dialog.dropDialog($(this));
  761. }); // end $.live()
  762. /**
  763. * Attach Ajax event handlers for the "Change event/routine type"
  764. * functionality in the events editor, so that the correct
  765. * rows are shown in the editor when changing the event type
  766. */
  767. $('select[name=item_type]').live('change', function () {
  768. $(this)
  769. .closest('table')
  770. .find('tr.recurring_event_row, tr.onetime_event_row, tr.routine_return_row, td.routine_direction_cell')
  771. .toggle();
  772. }); // end $.live()
  773. /**
  774. * Attach Ajax event handlers for the "Change parameter type"
  775. * functionality in the routines editor, so that the correct
  776. * option/length fields, if any, are shown when changing
  777. * a parameter type
  778. */
  779. $('select[name^=item_param_type]').live('change', function () {
  780. /**
  781. * @var row jQuery object containing the reference to
  782. * a row in the routine parameters table
  783. */
  784. var $row = $(this).parents('tr').first();
  785. var rte = new RTE.object('routine');
  786. rte.setOptionsForParameter(
  787. $row.find('select[name^=item_param_type]'),
  788. $row.find('input[name^=item_param_length]'),
  789. $row.find('select[name^=item_param_opts_text]'),
  790. $row.find('select[name^=item_param_opts_num]')
  791. );
  792. }); // end $.live()
  793. /**
  794. * Attach Ajax event handlers for the "Change the type of return
  795. * variable of function" functionality, so that the correct fields,
  796. * if any, are shown when changing the function return type type
  797. */
  798. $('select[name=item_returntype]').live('change', function () {
  799. var rte = new RTE.object('routine');
  800. var $table = $(this).closest('table.rte_table');
  801. rte.setOptionsForParameter(
  802. $table.find('select[name=item_returntype]'),
  803. $table.find('input[name=item_returnlength]'),
  804. $table.find('select[name=item_returnopts_text]'),
  805. $table.find('select[name=item_returnopts_num]')
  806. );
  807. }); // end $.live()
  808. /**
  809. * Attach Ajax event handlers for the "Add parameter to routine" functionality
  810. */
  811. $('input[name=routine_addparameter]').live('click', function (event) {
  812. event.preventDefault();
  813. /**
  814. * @var routine_params_table jQuery object containing the reference
  815. * to the routine parameters table
  816. */
  817. var $routine_params_table = $(this).closest('div.ui-dialog').find('.routine_params_table');
  818. /**
  819. * @var new_param_row A string containing the HTML code for the
  820. * new row for the routine paramaters table
  821. */
  822. var new_param_row = RTE.param_template.replace(/%s/g, $routine_params_table.find('tr').length - 1);
  823. // Append the new row to the parameters table
  824. $routine_params_table.append(new_param_row);
  825. // Make sure that the row is correctly shown according to the type of routine
  826. if ($(this).closest('div.ui-dialog').find('table.rte_table select[name=item_type]').val() === 'FUNCTION') {
  827. $('tr.routine_return_row').show();
  828. $('td.routine_direction_cell').hide();
  829. }
  830. /**
  831. * @var newrow jQuery object containing the reference to the newly
  832. * inserted row in the routine parameters table
  833. */
  834. var $newrow = $(this).closest('div.ui-dialog').find('table.routine_params_table').find('tr').has('td').last();
  835. // Enable/disable the 'options' dropdowns for parameters as necessary
  836. var rte = new RTE.object('routine');
  837. rte.setOptionsForParameter(
  838. $newrow.find('select[name^=item_param_type]'),
  839. $newrow.find('input[name^=item_param_length]'),
  840. $newrow.find('select[name^=item_param_opts_text]'),
  841. $newrow.find('select[name^=item_param_opts_num]')
  842. );
  843. }); // end $.live()
  844. /**
  845. * Attach Ajax event handlers for the
  846. * "Remove parameter from routine" functionality
  847. */
  848. $('a.routine_param_remove_anchor').live('click', function (event) {
  849. event.preventDefault();
  850. $(this).parent().parent().remove();
  851. // After removing a parameter, the indices of the name attributes in
  852. // the input fields lose the correct order and need to be reordered.
  853. /**
  854. * @var index Counter used for reindexing the input
  855. * fields in the routine parameters table
  856. */
  857. var index = 0;
  858. $(this).closest('div.ui-dialog').find('table.routine_params_table').find('tr').has('td').each(function () {
  859. $(this).find(':input').each(function () {
  860. /**
  861. * @var inputname The value of the name attribute of
  862. * the input field being reindexed
  863. */
  864. var inputname = $(this).attr('name');
  865. if (inputname.substr(0, 14) === 'item_param_dir') {
  866. $(this).attr('name', inputname.substr(0, 14) + '[' + index + ']');
  867. } else if (inputname.substr(0, 15) === 'item_param_name') {
  868. $(this).attr('name', inputname.substr(0, 15) + '[' + index + ']');
  869. } else if (inputname.substr(0, 15) === 'item_param_type') {
  870. $(this).attr('name', inputname.substr(0, 15) + '[' + index + ']');
  871. } else if (inputname.substr(0, 17) === 'item_param_length') {
  872. $(this).attr('name', inputname.substr(0, 17) + '[' + index + ']');
  873. $(this).attr('id', 'item_param_length_' + index);
  874. } else if (inputname.substr(0, 20) === 'item_param_opts_text') {
  875. $(this).attr('name', inputname.substr(0, 20) + '[' + index + ']');
  876. } else if (inputname.substr(0, 19) === 'item_param_opts_num') {
  877. $(this).attr('name', inputname.substr(0, 19) + '[' + index + ']');
  878. }
  879. });
  880. index++;
  881. });
  882. }); // end $.live()
  883. }); // end of $()