JAVASCRIPT 22
Makegrid.js Guest on 4th May 2021 10:52:44 AM
  1. /* vim: set expandtab sw=4 ts=4 sts=4: */
  2. /**
  3.  * Create advanced table (resize, reorder, and show/hide columns; and also grid editing).
  4.  * This function is designed mainly for table DOM generated from browsing a table in the database.
  5.  * For using this function in other table DOM, you may need to:
  6.  * - add "draggable" class in the table header <th>, in order to make it resizable, sortable or hidable
  7.  * - have at least one non-"draggable" header in the table DOM for placing column visibility drop-down arrow
  8.  * - pass the value "false" for the parameter "enableGridEdit"
  9.  * - adjust other parameter value, to select which features that will be enabled
  10.  *
  11.  * @param t the table DOM element
  12.  * @param enableResize Optional, if false, column resizing feature will be disabled
  13.  * @param enableReorder Optional, if false, column reordering feature will be disabled
  14.  * @param enableVisib Optional, if false, show/hide column feature will be disabled
  15.  * @param enableGridEdit Optional, if false, grid editing feature will be disabled
  16.  */
  17. function PMA_makegrid(t, enableResize, enableReorder, enableVisib, enableGridEdit) {
  18.     var g = {
  19.         /***********
  20.          * Constant
  21.          ***********/
  22.         minColWidth: 15,
  23.  
  24.  
  25.         /***********
  26.          * Variables, assigned with default value, changed later
  27.          ***********/
  28.         actionSpan: 5,              // number of colspan in Actions header in a table
  29.         tableCreateTime: null,      // table creation time, used for saving column order and visibility to server, only available in "Browse tab"
  30.  
  31.         // Column reordering variables
  32.         colOrder: [],      // array of column order
  33.  
  34.         // Column visibility variables
  35.         colVisib: [],      // array of column visibility
  36.         showAllColText: '',         // string, text for "show all" button under column visibility list
  37.         visibleHeadersCount: 0,     // number of visible data headers
  38.  
  39.         // Table hint variables
  40.         reorderHint: '',            // string, hint for column reordering
  41.         sortHint: '',               // string, hint for column sorting
  42.         markHint: '',               // string, hint for column marking
  43.         copyHint: '',               // string, hint for copy column name
  44.         showReorderHint: false,
  45.         showSortHint: false,
  46.         showMarkHint: false,
  47.  
  48.         // Grid editing
  49.         isCellEditActive: false,    // true if current focus is in edit cell
  50.         isEditCellTextEditable: false,  // true if current edit cell is editable in the text input box (not textarea)
  51.         currentEditCell: null,      // reference to <td> that currently being edited
  52.         cellEditHint: '',           // hint shown when doing grid edit
  53.         gotoLinkText: '',           // "Go to link" text
  54.         wasEditedCellNull: false,   // true if last value of the edited cell was NULL
  55.         maxTruncatedLen: 0,         // number of characters that can be displayed in a cell
  56.         saveCellsAtOnce: false,     // $cfg[saveCellsAtOnce]
  57.         isCellEdited: false,        // true if at least one cell has been edited
  58.         saveCellWarning: '',        // string, warning text when user want to leave a page with unsaved edited data
  59.         lastXHR : null,             // last XHR object used in AJAX request
  60.         isSaving: false,            // true when currently saving edited data, used to handle double posting caused by pressing ENTER in grid edit text box in Chrome browser
  61.         alertNonUnique: '',         // string, alert shown when saving edited nonunique table
  62.  
  63.         // Common hidden inputs
  64.         token: null,
  65.         server: null,
  66.         db: null,
  67.         table: null,
  68.  
  69.  
  70.         /************
  71.          * Functions
  72.          ************/
  73.  
  74.         /**
  75.          * Start to resize column. Called when clicking on column separator.
  76.          *
  77.          * @param e event
  78.          * @param obj dragged div object
  79.          */
  80.         dragStartRsz: function (e, obj) {
  81.             var n = $(g.cRsz).find('div').index(obj);    // get the index of separator (i.e., column index)
  82.             $(obj).addClass('colborder_active');
  83.             g.colRsz = {
  84.                 x0: e.pageX,
  85.                 n: n,
  86.                 obj: obj,
  87.                 objLeft: $(obj).position().left,
  88.                 objWidth: $(g.t).find('th.draggable:visible:eq(' + n + ') span').outerWidth()
  89.             };
  90.             $(document.body).css('cursor', 'col-resize').noSelect();
  91.             if (g.isCellEditActive) {
  92.                 g.hideEditCell();
  93.             }
  94.         },
  95.  
  96.         /**
  97.          * Start to reorder column. Called when clicking on table header.
  98.          *
  99.          * @param e event
  100.          * @param obj table header object
  101.          */
  102.         dragStartReorder: function (e, obj) {
  103.             // prepare the cCpy (column copy) and cPointer (column pointer) from the dragged column
  104.             $(g.cCpy).text($(obj).text());
  105.             var objPos = $(obj).position();
  106.             $(g.cCpy).css({
  107.                 top: objPos.top + 20,
  108.                 left: objPos.left,
  109.                 height: $(obj).height(),
  110.                 width: $(obj).width()
  111.             });
  112.             $(g.cPointer).css({
  113.                 top: objPos.top
  114.             });
  115.  
  116.             // get the column index, zero-based
  117.             var n = g.getHeaderIdx(obj);
  118.  
  119.             g.colReorder = {
  120.                 x0: e.pageX,
  121.                 y0: e.pageY,
  122.                 n: n,
  123.                 newn: n,
  124.                 obj: obj,
  125.                 objTop: objPos.top,
  126.                 objLeft: objPos.left
  127.             };
  128.  
  129.             $(document.body).css('cursor', 'move').noSelect();
  130.             if (g.isCellEditActive) {
  131.                 g.hideEditCell();
  132.             }
  133.         },
  134.  
  135.         /**
  136.          * Handle mousemove event when dragging.
  137.          *
  138.          * @param e event
  139.          */
  140.         dragMove: function (e) {
  141.             if (g.colRsz) {
  142.                 var dx = e.pageX - g.colRsz.x0;
  143.                 if (g.colRsz.objWidth + dx > g.minColWidth) {
  144.                     $(g.colRsz.obj).css('left', g.colRsz.objLeft + dx + 'px');
  145.                 }
  146.             } else if (g.colReorder) {
  147.                 // dragged column animation
  148.                 var dx = e.pageX - g.colReorder.x0;
  149.                 $(g.cCpy)
  150.                     .css('left', g.colReorder.objLeft + dx)
  151.                     .show();
  152.  
  153.                 // pointer animation
  154.                 var hoveredCol = g.getHoveredCol(e);
  155.                 if (hoveredCol) {
  156.                     var newn = g.getHeaderIdx(hoveredCol);
  157.                     g.colReorder.newn = newn;
  158.                     if (newn != g.colReorder.n) {
  159.                         // show the column pointer in the right place
  160.                         var colPos = $(hoveredCol).position();
  161.                         var newleft = newn < g.colReorder.n ?
  162.                                       colPos.left :
  163.                                       colPos.left + $(hoveredCol).outerWidth();
  164.                         $(g.cPointer)
  165.                             .css({
  166.                                 left: newleft,
  167.                                 visibility: 'visible'
  168.                             });
  169.                     } else {
  170.                         // no movement to other column, hide the column pointer
  171.                         $(g.cPointer).css('visibility', 'hidden');
  172.                     }
  173.                 }
  174.             }
  175.         },
  176.  
  177.         /**
  178.          * Stop the dragging action.
  179.          *
  180.          * @param e event
  181.          */
  182.         dragEnd: function (e) {
  183.             if (g.colRsz) {
  184.                 var dx = e.pageX - g.colRsz.x0;
  185.                 var nw = g.colRsz.objWidth + dx;
  186.                 if (nw < g.minColWidth) {
  187.                     nw = g.minColWidth;
  188.                 }
  189.                 var n = g.colRsz.n;
  190.                 // do the resizing
  191.                 g.resize(n, nw);
  192.  
  193.                 g.reposRsz();
  194.                 g.reposDrop();
  195.                 g.colRsz = false;
  196.                 $(g.cRsz).find('div').removeClass('colborder_active');
  197.                 rearrangeStickyColumns($(t).prev('.sticky_columns'), $(t));
  198.             } else if (g.colReorder) {
  199.                 // shift columns
  200.                 if (g.colReorder.newn != g.colReorder.n) {
  201.                     g.shiftCol(g.colReorder.n, g.colReorder.newn);
  202.                     // assign new position
  203.                     var objPos = $(g.colReorder.obj).position();
  204.                     g.colReorder.objTop = objPos.top;
  205.                     g.colReorder.objLeft = objPos.left;
  206.                     g.colReorder.n = g.colReorder.newn;
  207.                     // send request to server to remember the column order
  208.                     if (g.tableCreateTime) {
  209.                         g.sendColPrefs();
  210.                     }
  211.                     g.refreshRestoreButton();
  212.                 }
  213.  
  214.                 // animate new column position
  215.                 $(g.cCpy).stop(true, true)
  216.                     .animate({
  217.                         top: g.colReorder.objTop,
  218.                         left: g.colReorder.objLeft
  219.                     }, 'fast')
  220.                     .fadeOut();
  221.                 $(g.cPointer).css('visibility', 'hidden');
  222.  
  223.                 g.colReorder = false;
  224.                 rearrangeStickyColumns($(t).prev('.sticky_columns'), $(t));
  225.             }
  226.             $(document.body).css('cursor', 'inherit').noSelect(false);
  227.         },
  228.  
  229.         /**
  230.          * Resize column n to new width "nw"
  231.          *
  232.          * @param n zero-based column index
  233.          * @param nw new width of the column in pixel
  234.          */
  235.         resize: function (n, nw) {
  236.             $(g.t).find('tr').each(function () {
  237.                 $(this).find('th.draggable:visible:eq(' + n + ') span,' +
  238.                              'td:visible:eq(' + (g.actionSpan + n) + ') span')
  239.                        .css('width', nw);
  240.             });
  241.         },
  242.  
  243.         /**
  244.          * Reposition column resize bars.
  245.          */
  246.         reposRsz: function () {
  247.             $(g.cRsz).find('div').hide();
  248.             var $firstRowCols = $(g.t).find('tr:first th.draggable:visible');
  249.             var $resizeHandles = $(g.cRsz).find('div').removeClass('condition');
  250.             $(g.t).find('table.pma_table').find('thead th:first').removeClass('before-condition');
  251.             for (var n = 0, l = $firstRowCols.length; n < l; n++) {
  252.                 var $col = $($firstRowCols[n]);
  253.                 var colWidth;
  254.                 if (navigator.userAgent.toLowerCase().indexOf("safari") != -1) {
  255.                     colWidth = $col.outerWidth();
  256.                 } else {
  257.                     colWidth = $col.outerWidth(true);
  258.                 }
  259.                 $($resizeHandles[n]).css('left', $col.position().left + colWidth)
  260.                    .show();
  261.                 if ($col.hasClass('condition')) {
  262.                     $($resizeHandles[n]).addClass('condition');
  263.                     if (n > 0) {
  264.                         $($resizeHandles[n - 1]).addClass('condition');
  265.                     }
  266.                 }
  267.             }
  268.             if ($($resizeHandles[0]).hasClass('condition')) {
  269.                 $(g.t).find('thead th:first').addClass('before-condition');
  270.             }
  271.             $(g.cRsz).css('height', $(g.t).height());
  272.         },
  273.  
  274.         /**
  275.          * Shift column from index oldn to newn.
  276.          *
  277.          * @param oldn old zero-based column index
  278.          * @param newn new zero-based column index
  279.          */
  280.         shiftCol: function (oldn, newn) {
  281.             $(g.t).find('tr').each(function () {
  282.                 if (newn < oldn) {
  283.                     $(this).find('th.draggable:eq(' + newn + '),' +
  284.                                  'td:eq(' + (g.actionSpan + newn) + ')')
  285.                            .before($(this).find('th.draggable:eq(' + oldn + '),' +
  286.                                                 'td:eq(' + (g.actionSpan + oldn) + ')'));
  287.                 } else {
  288.                     $(this).find('th.draggable:eq(' + newn + '),' +
  289.                                  'td:eq(' + (g.actionSpan + newn) + ')')
  290.                            .after($(this).find('th.draggable:eq(' + oldn + '),' +
  291.                                                'td:eq(' + (g.actionSpan + oldn) + ')'));
  292.                 }
  293.             });
  294.             // reposition the column resize bars
  295.             g.reposRsz();
  296.  
  297.             // adjust the column visibility list
  298.             if (newn < oldn) {
  299.                 $(g.cList).find('.lDiv div:eq(' + newn + ')')
  300.                           .before($(g.cList).find('.lDiv div:eq(' + oldn + ')'));
  301.             } else {
  302.                 $(g.cList).find('.lDiv div:eq(' + newn + ')')
  303.                           .after($(g.cList).find('.lDiv div:eq(' + oldn + ')'));
  304.             }
  305.             // adjust the colOrder
  306.             var tmp = g.colOrder[oldn];
  307.             g.colOrder.splice(oldn, 1);
  308.             g.colOrder.splice(newn, 0, tmp);
  309.             // adjust the colVisib
  310.             if (g.colVisib.length > 0) {
  311.                 tmp = g.colVisib[oldn];
  312.                 g.colVisib.splice(oldn, 1);
  313.                 g.colVisib.splice(newn, 0, tmp);
  314.             }
  315.         },
  316.  
  317.         /**
  318.          * Find currently hovered table column's header (excluding actions column).
  319.          *
  320.          * @param e event
  321.          * @return the hovered column's th object or undefined if no hovered column found.
  322.          */
  323.         getHoveredCol: function (e) {
  324.             var hoveredCol;
  325.             $headers = $(g.t).find('th.draggable:visible');
  326.             $headers.each(function () {
  327.                 var left = $(this).offset().left;
  328.                 var right = left + $(this).outerWidth();
  329.                 if (left <= e.pageX && e.pageX <= right) {
  330.                     hoveredCol = this;
  331.                 }
  332.             });
  333.             return hoveredCol;
  334.         },
  335.  
  336.         /**
  337.          * Get a zero-based index from a <th class="draggable"> tag in a table.
  338.          *
  339.          * @param obj table header <th> object
  340.          * @return zero-based index of the specified table header in the set of table headers (visible or not)
  341.          */
  342.         getHeaderIdx: function (obj) {
  343.             return $(obj).parents('tr').find('th.draggable').index(obj);
  344.         },
  345.  
  346.         /**
  347.          * Reposition the columns back to normal order.
  348.          */
  349.         restoreColOrder: function () {
  350.             // use insertion sort, since we already have shiftCol function
  351.             for (var i = 1; i < g.colOrder.length; i++) {
  352.                 var x = g.colOrder[i];
  353.                 var j = i - 1;
  354.                 while (j >= 0 && x < g.colOrder[j]) {
  355.                     j--;
  356.                 }
  357.                 if (j != i - 1) {
  358.                     g.shiftCol(i, j + 1);
  359.                 }
  360.             }
  361.             if (g.tableCreateTime) {
  362.                 // send request to server to remember the column order
  363.                 g.sendColPrefs();
  364.             }
  365.             g.refreshRestoreButton();
  366.         },
  367.  
  368.         /**
  369.          * Send column preferences (column order and visibility) to the server.
  370.          */
  371.         sendColPrefs: function () {
  372.             if ($(g.t).is('.ajax')) {   // only send preferences if ajax class
  373.                 var post_params = {
  374.                     ajax_request: true,
  375.                     db: g.db,
  376.                     table: g.table,
  377.                     token: g.token,
  378.                     server: g.server,
  379.                     set_col_prefs: true,
  380.                     table_create_time: g.tableCreateTime
  381.                 };
  382.                 if (g.colOrder.length > 0) {
  383.                     $.extend(post_params, {col_order: g.colOrder.toString()});
  384.                 }
  385.                 if (g.colVisib.length > 0) {
  386.                     $.extend(post_params, {col_visib: g.colVisib.toString()});
  387.                 }
  388.                 $.post('sql.php', post_params, function (data) {
  389.                     if (data.success !== true) {
  390.                         var $temp_div = $(document.createElement('div'));
  391.                         $temp_div.html(data.error);
  392.                         $temp_div.addClass("error");
  393.                         PMA_ajaxShowMessage($temp_div, false);
  394.                     }
  395.                 });
  396.             }
  397.         },
  398.  
  399.         /**
  400.          * Refresh restore button state.
  401.          * Make restore button disabled if the table is similar with initial state.
  402.          */
  403.         refreshRestoreButton: function () {
  404.             // check if table state is as initial state
  405.             var isInitial = true;
  406.             for (var i = 0; i < g.colOrder.length; i++) {
  407.                 if (g.colOrder[i] != i) {
  408.                     isInitial = false;
  409.                     break;
  410.                 }
  411.             }
  412.             // check if only one visible column left
  413.             var isOneColumn = g.visibleHeadersCount == 1;
  414.             // enable or disable restore button
  415.             if (isInitial || isOneColumn) {
  416.                 $(g.o).find('div.restore_column').hide();
  417.             } else {
  418.                 $(g.o).find('div.restore_column').show();
  419.             }
  420.         },
  421.  
  422.         /**
  423.          * Update current hint using the boolean values (showReorderHint, showSortHint, etc.).
  424.          *
  425.          */
  426.         updateHint: function () {
  427.             var text = '';
  428.             if (!g.colRsz && !g.colReorder) {     // if not resizing or dragging
  429.                 if (g.visibleHeadersCount > 1) {
  430.                     g.showReorderHint = true;
  431.                 }
  432.                 if ($(t).find('th.marker').length > 0) {
  433.                     g.showMarkHint = true;
  434.                 }
  435.                 if (g.showSortHint && g.sortHint) {
  436.                     text += text.length > 0 ? '<br />' : '';
  437.                     text += '- ' + g.sortHint;
  438.                 }
  439.                 if (g.showMultiSortHint && g.strMultiSortHint) {
  440.                     text += text.length > 0 ? '<br />' : '';
  441.                     text += '- ' + g.strMultiSortHint;
  442.                 }
  443.                 if (g.showMarkHint &&
  444.                     g.markHint &&
  445.                     ! g.showSortHint && // we do not show mark hint, when sort hint is shown
  446.                     g.showReorderHint &&
  447.                     g.reorderHint
  448.                 ) {
  449.                     text += text.length > 0 ? '<br />' : '';
  450.                     text += '- ' + g.reorderHint;
  451.                     text += text.length > 0 ? '<br />' : '';
  452.                     text += '- ' + g.markHint;
  453.                     text += text.length > 0 ? '<br />' : '';
  454.                     text += '- ' + g.copyHint;
  455.                 }
  456.             }
  457.             return text;
  458.         },
  459.  
  460.         /**
  461.          * Toggle column's visibility.
  462.          * After calling this function and it returns true, afterToggleCol() must be called.
  463.          *
  464.          * @return boolean True if the column is toggled successfully.
  465.          */
  466.         toggleCol: function (n) {
  467.             if (g.colVisib[n]) {
  468.                 // can hide if more than one column is visible
  469.                 if (g.visibleHeadersCount > 1) {
  470.                     $(g.t).find('tr').each(function () {
  471.                         $(this).find('th.draggable:eq(' + n + '),' +
  472.                                      'td:eq(' + (g.actionSpan + n) + ')')
  473.                                .hide();
  474.                     });
  475.                     g.colVisib[n] = 0;
  476.                     $(g.cList).find('.lDiv div:eq(' + n + ') input').prop('checked', false);
  477.                 } else {
  478.                     // cannot hide, force the checkbox to stay checked
  479.                     $(g.cList).find('.lDiv div:eq(' + n + ') input').prop('checked', true);
  480.                     return false;
  481.                 }
  482.             } else {    // column n is not visible
  483.                 $(g.t).find('tr').each(function () {
  484.                     $(this).find('th.draggable:eq(' + n + '),' +
  485.                                  'td:eq(' + (g.actionSpan + n) + ')')
  486.                            .show();
  487.                 });
  488.                 g.colVisib[n] = 1;
  489.                 $(g.cList).find('.lDiv div:eq(' + n + ') input').prop('checked', true);
  490.             }
  491.             return true;
  492.         },
  493.  
  494.         /**
  495.          * This must be called if toggleCol() returns is true.
  496.          *
  497.          * This function is separated from toggleCol because, sometimes, we want to toggle
  498.          * some columns together at one time and do just one adjustment after it, e.g. in showAllColumns().
  499.          */
  500.         afterToggleCol: function () {
  501.             // some adjustments after hiding column
  502.             g.reposRsz();
  503.             g.reposDrop();
  504.             g.sendColPrefs();
  505.  
  506.             // check visible first row headers count
  507.             g.visibleHeadersCount = $(g.t).find('tr:first th.draggable:visible').length;
  508.             g.refreshRestoreButton();
  509.         },
  510.  
  511.         /**
  512.          * Show columns' visibility list.
  513.          *
  514.          * @param obj The drop down arrow of column visibility list
  515.          */
  516.         showColList: function (obj) {
  517.             // only show when not resizing or reordering
  518.             if (!g.colRsz && !g.colReorder) {
  519.                 var pos = $(obj).position();
  520.                 // check if the list position is too right
  521.                 if (pos.left + $(g.cList).outerWidth(true) > $(document).width()) {
  522.                     pos.left = $(document).width() - $(g.cList).outerWidth(true);
  523.                 }
  524.                 $(g.cList).css({
  525.                         left: pos.left,
  526.                         top: pos.top + $(obj).outerHeight(true)
  527.                     })
  528.                     .show();
  529.                 $(obj).addClass('coldrop-hover');
  530.             }
  531.         },
  532.  
  533.         /**
  534.          * Hide columns' visibility list.
  535.          */
  536.         hideColList: function () {
  537.             $(g.cList).hide();
  538.             $(g.cDrop).find('.coldrop-hover').removeClass('coldrop-hover');
  539.         },
  540.  
  541.         /**
  542.          * Reposition the column visibility drop-down arrow.
  543.          */
  544.         reposDrop: function () {
  545.             var $th = $(t).find('th:not(.draggable)');
  546.             for (var i = 0; i < $th.length; i++) {
  547.                 var $cd = $(g.cDrop).find('div:eq(' + i + ')');   // column drop-down arrow
  548.                 var pos = $($th[i]).position();
  549.                 $cd.css({
  550.                         left: pos.left + $($th[i]).width() - $cd.width(),
  551.                         top: pos.top
  552.                     });
  553.             }
  554.         },
  555.  
  556.         /**
  557.          * Show all hidden columns.
  558.          */
  559.         showAllColumns: function () {
  560.             for (var i = 0; i < g.colVisib.length; i++) {
  561.                 if (!g.colVisib[i]) {
  562.                     g.toggleCol(i);
  563.                 }
  564.             }
  565.             g.afterToggleCol();
  566.         },
  567.  
  568.         /**
  569.          * Show edit cell, if it can be shown
  570.          *
  571.          * @param cell <td> element to be edited
  572.          */
  573.         showEditCell: function (cell) {
  574.             if ($(cell).is('.grid_edit') &&
  575.                 !g.colRsz && !g.colReorder)
  576.             {
  577.                 if (!g.isCellEditActive) {
  578.                     var $cell = $(cell);
  579.  
  580.                     if ('string' === $cell.attr('data-type') ||
  581.                         'blob' === $cell.attr('data-type')
  582.                     ) {
  583.                         g.cEdit = g.cEditTextarea;
  584.                     } else {
  585.                         g.cEdit = g.cEditStd;
  586.                     }
  587.  
  588.                     // remove all edit area and hide it
  589.                     $(g.cEdit).find('.edit_area').empty().hide();
  590.                     // reposition the cEdit element
  591.                     $(g.cEdit).css({
  592.                             top: $cell.position().top,
  593.                             left: $cell.position().left
  594.                         })
  595.                         .show()
  596.                         .find('.edit_box')
  597.                         .css({
  598.                             width: $cell.outerWidth(),
  599.                             height: $cell.outerHeight()
  600.                         });
  601.                     // fill the cell edit with text from <td>
  602.                     var value = PMA_getCellValue(cell);
  603.                     $(g.cEdit).find('.edit_box').val(value);
  604.  
  605.                     g.currentEditCell = cell;
  606.                     $(g.cEdit).find('.edit_box').focus();
  607.                     moveCursorToEnd($(g.cEdit).find('.edit_box'));
  608.                     $(g.cEdit).find('*').prop('disabled', false);
  609.                 }
  610.             }
  611.  
  612.             function moveCursorToEnd(input) {
  613.                 var originalValue = input.val();
  614.                 var originallength = originalValue.length;
  615.                 input.val('');
  616.                 input.blur().focus().val(originalValue);
  617.                 input[0].setSelectionRange(originallength, originallength);
  618.             }
  619.         },
  620.  
  621.         /**
  622.          * Remove edit cell and the edit area, if it is shown.
  623.          *
  624.          * @param force Optional, force to hide edit cell without saving edited field.
  625.          * @param data  Optional, data from the POST AJAX request to save the edited field
  626.          *              or just specify "true", if we want to replace the edited field with the new value.
  627.          * @param field Optional, the edited <td>. If not specified, the function will
  628.          *              use currently edited <td> from g.currentEditCell.
  629.          * @param field Optional, this object contains a boolean named move (true, if called from move* functions)
  630.          *              and a <td> to which the grid_edit should move
  631.          */
  632.         hideEditCell: function (force, data, field, options) {
  633.             if (g.isCellEditActive && !force) {
  634.                 // cell is being edited, save or post the edited data
  635.                 if (options !== undefined) {
  636.                     g.saveOrPostEditedCell(options);
  637.                 } else {
  638.                     g.saveOrPostEditedCell();
  639.                 }
  640.                 return;
  641.             }
  642.  
  643.             // cancel any previous request
  644.             if (g.lastXHR !== null) {
  645.                 g.lastXHR.abort();
  646.                 g.lastXHR = null;
  647.             }
  648.  
  649.             if (data) {
  650.                 if (g.currentEditCell) {    // save value of currently edited cell
  651.                     // replace current edited field with the new value
  652.                     var $this_field = $(g.currentEditCell);
  653.                     var is_null = $this_field.data('value') === null;
  654.                     if (is_null) {
  655.                         $this_field.find('span').html('NULL');
  656.                         $this_field.addClass('null');
  657.                     } else {
  658.                         $this_field.removeClass('null');
  659.                         var value = data.isNeedToRecheck
  660.                             ? data.truncatableFieldValue
  661.                             : $this_field.data('value');
  662.  
  663.                         // Truncates the text.
  664.                         $this_field.removeClass('truncated');
  665.                         if (PMA_commonParams.get('pftext') === 'P' && value.length > g.maxTruncatedLen) {
  666.                             $this_field.addClass('truncated');
  667.                             value = value.substring(0, g.maxTruncatedLen) + '...';
  668.                         }
  669.  
  670.                         //Add <br> before carriage return.
  671.                         new_html = escapeHtml(value);
  672.                         new_html = new_html.replace(/\n/g, '<br>\n');
  673.  
  674.                         //remove decimal places if column type not supported
  675.                         if (($this_field.attr('data-decimals') == 0) && ( $this_field.attr('data-type').indexOf('time') != -1)) {
  676.                             new_html = new_html.substring(0, new_html.indexOf('.'));
  677.                         }
  678.  
  679.                         //remove addtional decimal places
  680.                         if (($this_field.attr('data-decimals') > 0) && ( $this_field.attr('data-type').indexOf('time') != -1)){
  681.                             new_html = new_html.substring(0, new_html.length - (6 - $this_field.attr('data-decimals')));
  682.                         }
  683.  
  684.                         var selector = 'span';
  685.                         if ($this_field.hasClass('hex') && $this_field.find('a').length) {
  686.                             selector = 'a';
  687.                         }
  688.  
  689.                         // Updates the code keeping highlighting (if any).
  690.                         var $target = $this_field.find(selector);
  691.                         if (!PMA_updateCode($target, new_html, value)) {
  692.                             $target.html(new_html);
  693.                         }
  694.                     }
  695.                     if ($this_field.is('.bit')) {
  696.                         $this_field.find('span').text($this_field.data('value'));
  697.                     }
  698.                 }
  699.                 if (data.transformations !== undefined) {
  700.                     $.each(data.transformations, function (cell_index, value) {
  701.                         var $this_field = $(g.t).find('.to_be_saved:eq(' + cell_index + ')');
  702.                         $this_field.find('span').html(value);
  703.                     });
  704.                 }
  705.                 if (data.relations !== undefined) {
  706.                     $.each(data.relations, function (cell_index, value) {
  707.                         var $this_field = $(g.t).find('.to_be_saved:eq(' + cell_index + ')');
  708.                         $this_field.find('span').html(value);
  709.                     });
  710.                 }
  711.  
  712.                 // refresh the grid
  713.                 g.reposRsz();
  714.                 g.reposDrop();
  715.             }
  716.  
  717.             // hide the cell editing area
  718.             $(g.cEdit).hide();
  719.             $(g.cEdit).find('.edit_box').blur();
  720.             g.isCellEditActive = false;
  721.             g.currentEditCell = null;
  722.             // destroy datepicker in edit area, if exist
  723.             var $dp = $(g.cEdit).find('.hasDatepicker');
  724.             if ($dp.length > 0) {
  725.                 $(document).bind('mousedown', $.datepicker._checkExternalClick);
  726.                 $dp.datepicker('destroy');
  727.                 // change the cursor in edit box back to normal
  728.                 // (the cursor become a hand pointer when we add datepicker)
  729.                 $(g.cEdit).find('.edit_box').css('cursor', 'inherit');
  730.             }
  731.         },
  732.  
  733.         /**
  734.          * Show drop-down edit area when edit cell is focused.
  735.          */
  736.         showEditArea: function () {
  737.             if (!g.isCellEditActive) {   // make sure the edit area has not been shown
  738.                 g.isCellEditActive = true;
  739.                 g.isEditCellTextEditable = false;
  740.                 /**
  741.                  * @var $td current edited cell
  742.                  */
  743.                 var $td = $(g.currentEditCell);
  744.                 /**
  745.                  * @var $editArea the editing area
  746.                  */
  747.                 var $editArea = $(g.cEdit).find('.edit_area');
  748.                 /**
  749.                  * @var where_clause WHERE clause for the edited cell
  750.                  */
  751.                 var where_clause = $td.parent('tr').find('.where_clause').val();
  752.                 /**
  753.                  * @var field_name  String containing the name of this field.
  754.                  * @see getFieldName()
  755.                  */
  756.                 var field_name = getFieldName($(t), $td);
  757.                 /**
  758.                  * @var relation_curr_value String current value of the field (for fields that are foreign keyed).
  759.                  */
  760.                 var relation_curr_value = $td.text();
  761.                 /**
  762.                  * @var relation_key_or_display_column String relational key if in 'Relational display column' mode,
  763.                  * relational display column if in 'Relational key' mode (for fields that are foreign keyed).
  764.                  */
  765.                 var relation_key_or_display_column = $td.find('a').attr('title');
  766.                 /**
  767.                  * @var curr_value String current value of the field (for fields that are of type enum or set).
  768.                  */
  769.                 var curr_value = $td.find('span').text();
  770.  
  771.                 // empty all edit area, then rebuild it based on $td classes
  772.                 $editArea.empty();
  773.  
  774.                 // remember this instead of testing more than once
  775.                 var is_null = $td.is('.null');
  776.  
  777.                 // add goto link, if this cell contains a link
  778.                 if ($td.find('a').length > 0) {
  779.                     var gotoLink = document.createElement('div');
  780.                     gotoLink.className = 'goto_link';
  781.                     $(gotoLink).append(g.gotoLinkText + ' ').append($td.find('a').clone());
  782.                     $editArea.append(gotoLink);
  783.                 }
  784.  
  785.                 g.wasEditedCellNull = false;
  786.                 if ($td.is(':not(.not_null)')) {
  787.                     // append a null checkbox
  788.                     $editArea.append('<div class="null_div">Null:<input type="checkbox"></div>');
  789.  
  790.                     var $checkbox = $editArea.find('.null_div input');
  791.                     // check if current <td> is NULL
  792.                     if (is_null) {
  793.                         $checkbox.prop('checked', true);
  794.                         g.wasEditedCellNull = true;
  795.                     }
  796.  
  797.                     // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'.
  798.                     if ($td.is('.enum, .set')) {
  799.                         $editArea.on('change', 'select', function () {
  800.                             $checkbox.prop('checked', false);
  801.                         });
  802.                     } else if ($td.is('.relation')) {
  803.                         $editArea.on('change', 'select', function () {
  804.                             $checkbox.prop('checked', false);
  805.                         });
  806.                         $editArea.on('click', '.browse_foreign', function () {
  807.                             $checkbox.prop('checked', false);
  808.                         });
  809.                     } else {
  810.                         $(g.cEdit).on('keypress change paste', '.edit_box', function () {
  811.                             $checkbox.prop('checked', false);
  812.                         });
  813.                         // Capture ctrl+v (on IE and Chrome)
  814.                         $(g.cEdit).on('keydown', '.edit_box', function (e) {
  815.                             if (e.ctrlKey && e.which == 86) {
  816.                                 $checkbox.prop('checked', false);
  817.                             }
  818.                         });
  819.                         $editArea.on('keydown', 'textarea', function () {
  820.                             $checkbox.prop('checked', false);
  821.                         });
  822.                     }
  823.  
  824.                     // if null checkbox is clicked empty the corresponding select/editor.
  825.                     $checkbox.click(function () {
  826.                         if ($td.is('.enum')) {
  827.                             $editArea.find('select').val('');
  828.                         } else if ($td.is('.set')) {
  829.                             $editArea.find('select').find('option').each(function () {
  830.                                 var $option = $(this);
  831.                                 $option.prop('selected', false);
  832.                             });
  833.                         } else if ($td.is('.relation')) {
  834.                             // if the dropdown is there to select the foreign value
  835.                             if ($editArea.find('select').length > 0) {
  836.                                 $editArea.find('select').val('');
  837.                             }
  838.                         } else {
  839.                             $editArea.find('textarea').val('');
  840.                         }
  841.                         $(g.cEdit).find('.edit_box').val('');
  842.                     });
  843.                 }
  844.  
  845.                 //reset the position of the edit_area div after closing datetime picker
  846.                 $(g.cEdit).find('.edit_area').css({'top' :'0','position':''});
  847.  
  848.                 if ($td.is('.relation')) {
  849.                     //handle relations
  850.                     $editArea.addClass('edit_area_loading');
  851.  
  852.                     // initialize the original data
  853.                     $td.data('original_data', null);
  854.  
  855.                     /**
  856.                      * @var post_params Object containing parameters for the POST request
  857.                      */
  858.                     var post_params = {
  859.                         'ajax_request' : true,
  860.                         'get_relational_values' : true,
  861.                         'server' : g.server,
  862.                         'db' : g.db,
  863.                         'table' : g.table,
  864.                         'column' : field_name,
  865.                         'token' : g.token,
  866.                         'curr_value' : relation_curr_value,
  867.                         'relation_key_or_display_column' : relation_key_or_display_column
  868.                     };
  869.  
  870.                     g.lastXHR = $.post('sql.php', post_params, function (data) {
  871.                         g.lastXHR = null;
  872.                         $editArea.removeClass('edit_area_loading');
  873.                         if ($(data.dropdown).is('select')) {
  874.                             // save original_data
  875.                             var value = $(data.dropdown).val();
  876.                             $td.data('original_data', value);
  877.                             // update the text input field, in case where the "Relational display column" is checked
  878.                             $(g.cEdit).find('.edit_box').val(value);
  879.                         }
  880.  
  881.                         $editArea.append(data.dropdown);
  882.                         $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>');
  883.  
  884.                         // for 'Browse foreign values' options,
  885.                         // hide the value next to 'Browse foreign values' link
  886.                         $editArea.find('span.curr_value').hide();
  887.                         // handle update for new values selected from new window
  888.                         $editArea.find('span.curr_value').change(function () {
  889.                             $(g.cEdit).find('.edit_box').val($(this).text());
  890.                         });
  891.                     }); // end $.post()
  892.  
  893.                     $editArea.show();
  894.                     $editArea.on('change', 'select', function () {
  895.                         $(g.cEdit).find('.edit_box').val($(this).val());
  896.                     });
  897.                     g.isEditCellTextEditable = true;
  898.                 }
  899.                 else if ($td.is('.enum')) {
  900.                     //handle enum fields
  901.                     $editArea.addClass('edit_area_loading');
  902.  
  903.                     /**
  904.                      * @var post_params Object containing parameters for the POST request
  905.                      */
  906.                     var post_params = {
  907.                         'ajax_request' : true,
  908.                         'get_enum_values' : true,
  909.                         'server' : g.server,
  910.                         'db' : g.db,
  911.                         'table' : g.table,
  912.                         'column' : field_name,
  913.                         'token' : g.token,
  914.                         'curr_value' : curr_value
  915.                     };
  916.                     g.lastXHR = $.post('sql.php', post_params, function (data) {
  917.                         g.lastXHR = null;
  918.                         $editArea.removeClass('edit_area_loading');
  919.                         $editArea.append(data.dropdown);
  920.                         $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>');
  921.                     }); // end $.post()
  922.  
  923.                     $editArea.show();
  924.                     $editArea.on('change', 'select', function () {
  925.                         $(g.cEdit).find('.edit_box').val($(this).val());
  926.                     });
  927.                 }
  928.                 else if ($td.is('.set')) {
  929.                     //handle set fields
  930.                     $editArea.addClass('edit_area_loading');
  931.  
  932.                     /**
  933.                      * @var post_params Object containing parameters for the POST request
  934.                      */
  935.                     var post_params = {
  936.                         'ajax_request' : true,
  937.                         'get_set_values' : true,
  938.                         'server' : g.server,
  939.                         'db' : g.db,
  940.                         'table' : g.table,
  941.                         'column' : field_name,
  942.                         'token' : g.token,
  943.                         'curr_value' : curr_value
  944.                     };
  945.  
  946.                     // if the data is truncated, get the full data
  947.                     if ($td.is('.truncated')) {
  948.                         post_params.get_full_values = true;
  949.                         post_params.where_clause = PMA_urldecode(where_clause);
  950.                     }
  951.  
  952.                     g.lastXHR = $.post('sql.php', post_params, function (data) {
  953.                         g.lastXHR = null;
  954.                         $editArea.removeClass('edit_area_loading');
  955.                         $editArea.append(data.select);
  956.                         $td.data('original_data', $(data.select).val().join());
  957.                         $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>');
  958.                     }); // end $.post()
  959.  
  960.                     $editArea.show();
  961.                     $editArea.on('change', 'select', function () {
  962.                         $(g.cEdit).find('.edit_box').val($(this).val());
  963.                     });
  964.                 }
  965.                 else if ($td.is('.truncated, .transformed')) {
  966.                     if ($td.is('.to_be_saved')) {   // cell has been edited
  967.                         var value = $td.data('value');
  968.                         $(g.cEdit).find('.edit_box').val(value);
  969.                         $editArea.append('<textarea></textarea>');
  970.                         $editArea.find('textarea').val(value);
  971.                         $editArea
  972.                             .on('keyup', 'textarea', function () {
  973.                                 $(g.cEdit).find('.edit_box').val($(this).val());
  974.                             });
  975.                         $(g.cEdit).on('keyup', '.edit_box', function () {
  976.                             $editArea.find('textarea').val($(this).val());
  977.                         });
  978.                         $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>');
  979.                     } else {
  980.                         //handle truncated/transformed values values
  981.                         $editArea.addClass('edit_area_loading');
  982.  
  983.                         // initialize the original data
  984.                         $td.data('original_data', null);
  985.  
  986.                         /**
  987.                          * @var sql_query   String containing the SQL query used to retrieve value of truncated/transformed data
  988.                          */
  989.                         var sql_query = 'SELECT `' + field_name + '` FROM `' + g.table + '` WHERE ' + PMA_urldecode(where_clause);
  990.  
  991.                         // Make the Ajax call and get the data, wrap it and insert it
  992.                         g.lastXHR = $.post('sql.php', {
  993.                             'token' : g.token,
  994.                             'server' : g.server,
  995.                             'db' : g.db,
  996.                             'ajax_request' : true,
  997.                             'sql_query' : sql_query,
  998.                             'grid_edit' : true
  999.                         }, function (data) {
  1000.                             g.lastXHR = null;
  1001.                             $editArea.removeClass('edit_area_loading');
  1002.                             if (typeof data !== 'undefined' && data.success === true) {
  1003.                                 $td.data('original_data', data.value);
  1004.                                 $(g.cEdit).find('.edit_box').val(data.value);
  1005.                             } else {
  1006.                                 PMA_ajaxShowMessage(data.error, false);
  1007.                             }
  1008.                         }); // end $.post()
  1009.                     }
  1010.                     g.isEditCellTextEditable = true;
  1011.                 } else if ($td.is('.timefield, .datefield, .datetimefield, .timestampfield')) {
  1012.                     var $input_field = $(g.cEdit).find('.edit_box');
  1013.  
  1014.                     // remember current datetime value in $input_field, if it is not null
  1015.                     var datetime_value = !is_null ? $input_field.val() : '';
  1016.  
  1017.                     var showMillisec = false;
  1018.                     var showMicrosec = false;
  1019.                     var timeFormat = 'HH:mm:ss';
  1020.                     // check for decimal places of seconds
  1021.                     if (($td.attr('data-decimals') > 0) && ($td.attr('data-type').indexOf('time') != -1)){
  1022.                         if (datetime_value && datetime_value.indexOf('.') === false) {
  1023.                             datetime_value += '.';
  1024.                         }
  1025.                         if ($td.attr('data-decimals') > 3) {
  1026.                             showMillisec = true;
  1027.                             showMicrosec = true;
  1028.                             timeFormat = 'HH:mm:ss.lc';
  1029.  
  1030.                             if (datetime_value) {
  1031.                                 datetime_value += '000000';
  1032.                                 var datetime_value = datetime_value.substring(0, datetime_value.indexOf('.') + 7);
  1033.                                 $input_field.val(datetime_value);
  1034.                             }
  1035.                         } else {
  1036.                             showMillisec = true;
  1037.                             timeFormat = 'HH:mm:ss.l';
  1038.  
  1039.                             if (datetime_value) {
  1040.                                 datetime_value += '000';
  1041.                                 var datetime_value = datetime_value.substring(0, datetime_value.indexOf('.') + 4);
  1042.                                 $input_field.val(datetime_value);
  1043.                             }
  1044.                         }
  1045.                     }
  1046.  
  1047.                     // add datetime picker
  1048.                     PMA_addDatepicker($input_field, $td.attr('data-type'), {
  1049.                         showMillisec: showMillisec,
  1050.                         showMicrosec: showMicrosec,
  1051.                         timeFormat: timeFormat
  1052.                     });
  1053.  
  1054.                     $input_field.datepicker("show");
  1055.                     // unbind the mousedown event to prevent the problem of
  1056.                     // datepicker getting closed, needs to be checked for any
  1057.                     // change in names when updating
  1058.                     $(document).unbind('mousedown', $.datepicker._checkExternalClick);
  1059.  
  1060.                     //move ui-datepicker-div inside cEdit div
  1061.                     var datepicker_div = $('#ui-datepicker-div');
  1062.                     datepicker_div.css({'top': 0, 'left': 0, 'position': 'relative'});
  1063.                     $(g.cEdit).append(datepicker_div);
  1064.  
  1065.                     // cancel any click on the datepicker element
  1066.                     $editArea.find('> *').click(function (e) {
  1067.                         e.stopPropagation();
  1068.                     });
  1069.  
  1070.                     g.isEditCellTextEditable = true;
  1071.                 } else {
  1072.                     g.isEditCellTextEditable = true;
  1073.                     // only append edit area hint if there is a null checkbox
  1074.                     if ($editArea.children().length > 0) {
  1075.                         $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>');
  1076.                     }
  1077.                 }
  1078.                 if ($editArea.children().length > 0) {
  1079.                     $editArea.show();
  1080.                 }
  1081.             }
  1082.         },
  1083.  
  1084.         /**
  1085.          * Post the content of edited cell.
  1086.          *
  1087.          * @param field Optional, this object contains a boolean named move (true, if called from move* functions)
  1088.          *              and a <td> to which the grid_edit should move
  1089.          */
  1090.         postEditedCell: function (options) {
  1091.             if (g.isSaving) {
  1092.                 return;
  1093.             }
  1094.             g.isSaving = true;
  1095.             /**
  1096.              * @var relation_fields Array containing the name/value pairs of relational fields
  1097.              */
  1098.             var relation_fields = {};
  1099.             /**
  1100.              * @var relational_display string 'K' if relational key, 'D' if relational display column
  1101.              */
  1102.             var relational_display = $(g.o).find("input[name=relational_display]:checked").val();
  1103.             /**
  1104.              * @var transform_fields    Array containing the name/value pairs for transformed fields
  1105.              */
  1106.             var transform_fields = {};
  1107.             /**
  1108.              * @var transformation_fields   Boolean, if there are any transformed fields in the edited cells
  1109.              */
  1110.             var transformation_fields = false;
  1111.             /**
  1112.              * @var full_sql_query String containing the complete SQL query to update this table
  1113.              */
  1114.             var full_sql_query = '';
  1115.             /**
  1116.              * @var rel_fields_list  String, url encoded representation of {@link relations_fields}
  1117.              */
  1118.             var rel_fields_list = '';
  1119.             /**
  1120.              * @var transform_fields_list  String, url encoded representation of {@link transform_fields}
  1121.              */
  1122.             var transform_fields_list = '';
  1123.             /**
  1124.              * @var where_clause Array containing where clause for updated fields
  1125.              */
  1126.             var full_where_clause = [];
  1127.             /**
  1128.              * @var is_unique   Boolean, whether the rows in this table is unique or not
  1129.              */
  1130.             var is_unique = $(g.t).find('td.edit_row_anchor').is('.nonunique') ? 0 : 1;
  1131.             /**
  1132.              * multi edit variables
  1133.              */
  1134.             var me_fields_name = [];
  1135.             var me_fields_type = [];
  1136.             var me_fields = [];
  1137.             var me_fields_null = [];
  1138.  
  1139.             // alert user if edited table is not unique
  1140.             if (!is_unique) {
  1141.                 alert(g.alertNonUnique);
  1142.             }
  1143.  
  1144.             // loop each edited row
  1145.             $(g.t).find('td.to_be_saved').parents('tr').each(function () {
  1146.                 var $tr = $(this);
  1147.                 var where_clause = $tr.find('.where_clause').val();
  1148.                 if (typeof where_clause === 'undefined') {
  1149.                     where_clause = '';
  1150.                 }
  1151.                 full_where_clause.push(PMA_urldecode(where_clause));
  1152.                 var condition_array = jQuery.parseJSON($tr.find('.condition_array').val());
  1153.  
  1154.                 /**
  1155.                  * multi edit variables, for current row
  1156.                  * @TODO array indices are still not correct, they should be md5 of field's name
  1157.                  */
  1158.                 var fields_name = [];
  1159.                 var fields_type = [];
  1160.                 var fields = [];
  1161.                 var fields_null = [];
  1162.  
  1163.                 // loop each edited cell in a row
  1164.                 $tr.find('.to_be_saved').each(function () {
  1165.                     /**
  1166.                      * @var $this_field    Object referring to the td that is being edited
  1167.                      */
  1168.                     var $this_field = $(this);
  1169.  
  1170.                     /**
  1171.                      * @var field_name  String containing the name of this field.
  1172.                      * @see getFieldName()
  1173.                      */
  1174.                     var field_name = getFieldName($(g.t), $this_field);
  1175.  
  1176.                     /**
  1177.                      * @var this_field_params   Array temporary storage for the name/value of current field
  1178.                      */
  1179.                     var this_field_params = {};
  1180.  
  1181.                     if ($this_field.is('.transformed')) {
  1182.                         transformation_fields =  true;
  1183.                     }
  1184.                     this_field_params[field_name] = $this_field.data('value');
  1185.  
  1186.                     /**
  1187.                      * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked.
  1188.                      */
  1189.                     var is_null = this_field_params[field_name] === null;
  1190.  
  1191.                     fields_name.push(field_name);
  1192.  
  1193.                     if (is_null) {
  1194.                         fields_null.push('on');
  1195.                         fields.push('');
  1196.                     } else {
  1197.                         if ($this_field.is('.bit')) {
  1198.                             fields_type.push('bit');
  1199.                         } else if ($this_field.hasClass('hex')) {
  1200.                             fields_type.push('hex');
  1201.                         }
  1202.                         fields_null.push('');
  1203.                         fields.push($this_field.data('value'));
  1204.  
  1205.                         var cell_index = $this_field.index('.to_be_saved');
  1206.                         if ($this_field.is(":not(.relation, .enum, .set, .bit)")) {
  1207.                             if ($this_field.is('.transformed')) {
  1208.                                 transform_fields[cell_index] = {};
  1209.                                 $.extend(transform_fields[cell_index], this_field_params);
  1210.                             }
  1211.                         } else if ($this_field.is('.relation')) {
  1212.                             relation_fields[cell_index] = {};
  1213.                             $.extend(relation_fields[cell_index], this_field_params);
  1214.                         }
  1215.                     }
  1216.                     // check if edited field appears in WHERE clause
  1217.                     if (where_clause.indexOf(PMA_urlencode(field_name)) > -1) {
  1218.                         var field_str = '`' + g.table + '`.' + '`' + field_name + '`';
  1219.                         for (var field in condition_array) {
  1220.                             if (field.indexOf(field_str) > -1) {
  1221.                                 condition_array[field] = is_null ? 'IS NULL' : "= '" + this_field_params[field_name].replace(/'/g, "''") + "'";
  1222.                                 break;
  1223.                             }
  1224.                         }
  1225.                     }
  1226.  
  1227.                 }); // end of loop for every edited cells in a row
  1228.  
  1229.                 // save new_clause
  1230.                 var new_clause = '';
  1231.                 for (var field in condition_array) {
  1232.                     new_clause += field + ' ' + condition_array[field] + ' AND ';
  1233.                 }
  1234.                 new_clause = new_clause.substring(0, new_clause.length - 5); // remove the last AND
  1235.                 new_clause = PMA_urlencode(new_clause);
  1236.                 $tr.data('new_clause', new_clause);
  1237.                 // save condition_array
  1238.                 $tr.find('.condition_array').val(JSON.stringify(condition_array));
  1239.  
  1240.                 me_fields_name.push(fields_name);
  1241.                 me_fields_type.push(fields_type);
  1242.                 me_fields.push(fields);
  1243.                 me_fields_null.push(fields_null);
  1244.  
  1245.             }); // end of loop for every edited rows
  1246.  
  1247.             rel_fields_list = $.param(relation_fields);
  1248.             transform_fields_list = $.param(transform_fields);
  1249.  
  1250.             // Make the Ajax post after setting all parameters
  1251.             /**
  1252.              * @var post_params Object containing parameters for the POST request
  1253.              */
  1254.             var post_params = {'ajax_request' : true,
  1255.                             'sql_query' : full_sql_query,
  1256.                             'token' : g.token,
  1257.                             'server' : g.server,
  1258.                             'db' : g.db,
  1259.                             'table' : g.table,
  1260.                             'clause_is_unique' : is_unique,
  1261.                             'where_clause' : full_where_clause,
  1262.                             'fields[multi_edit]' : me_fields,
  1263.                             'fields_name[multi_edit]' : me_fields_name,
  1264.                             'fields_type[multi_edit]' : me_fields_type,
  1265.                             'fields_null[multi_edit]' : me_fields_null,
  1266.                             'rel_fields_list' : rel_fields_list,
  1267.                             'do_transformations' : transformation_fields,
  1268.                             'transform_fields_list' : transform_fields_list,
  1269.                             'relational_display' : relational_display,
  1270.                             'goto' : 'sql.php',
  1271.                             'submit_type' : 'save'
  1272.                           };
  1273.  
  1274.             if (!g.saveCellsAtOnce) {
  1275.                 $(g.cEdit).find('*').prop('disabled', true);
  1276.                 $(g.cEdit).find('.edit_box').addClass('edit_box_posting');
  1277.             } else {
  1278.                 $(g.o).find('div.save_edited').addClass('saving_edited_data')
  1279.                     .find('input').prop('disabled', true);    // disable the save button
  1280.             }
  1281.  
  1282.             $.ajax({
  1283.                 type: 'POST',
  1284.                 url: 'tbl_replace.php',
  1285.                 data: post_params,
  1286.                 success:
  1287.                     function (data) {
  1288.                         g.isSaving = false;
  1289.                         if (!g.saveCellsAtOnce) {
  1290.                             $(g.cEdit).find('*').prop('disabled', false);
  1291.                             $(g.cEdit).find('.edit_box').removeClass('edit_box_posting');
  1292.                         } else {
  1293.                             $(g.o).find('div.save_edited').removeClass('saving_edited_data')
  1294.                                 .find('input').prop('disabled', false);  // enable the save button back
  1295.                         }
  1296.                         if (typeof data !== 'undefined' && data.success === true) {
  1297.                             if (typeof options === 'undefined' || ! options.move) {
  1298.                                 PMA_ajaxShowMessage(data.message);
  1299.                             }
  1300.  
  1301.                             // update where_clause related data in each edited row
  1302.                             $(g.t).find('td.to_be_saved').parents('tr').each(function () {
  1303.                                 var new_clause = $(this).data('new_clause');
  1304.                                 var $where_clause = $(this).find('.where_clause');
  1305.                                 var old_clause = $where_clause.val();
  1306.                                 var decoded_old_clause = PMA_urldecode(old_clause);
  1307.                                 var decoded_new_clause = PMA_urldecode(new_clause);
  1308.  
  1309.                                 $where_clause.val(new_clause);
  1310.                                 // update Edit, Copy, and Delete links also
  1311.                                 $(this).find('a').each(function () {
  1312.                                     $(this).attr('href', $(this).attr('href').replace(old_clause, new_clause));
  1313.                                     // update delete confirmation in Delete link
  1314.                                     if ($(this).attr('href').indexOf('DELETE') > -1) {
  1315.                                         $(this).removeAttr('onclick')
  1316.                                             .unbind('click')
  1317.                                             .bind('click', function () {
  1318.                                                 return confirmLink(this, 'DELETE FROM `' + g.db + '`.`' + g.table + '` WHERE ' +
  1319.                                                        decoded_new_clause + (is_unique ? '' : ' LIMIT 1'));
  1320.                                             });
  1321.                                     }
  1322.                                 });
  1323.                                 // update the multi edit checkboxes
  1324.                                 $(this).find('input[type=checkbox]').each(function () {
  1325.                                     var $checkbox = $(this);
  1326.                                     var checkbox_name = $checkbox.attr('name');
  1327.                                     var checkbox_value = $checkbox.val();
  1328.  
  1329.                                     $checkbox.attr('name', checkbox_name.replace(old_clause, new_clause));
  1330.                                     $checkbox.val(checkbox_value.replace(decoded_old_clause, decoded_new_clause));
  1331.                                 });
  1332.                             });
  1333.                             // update the display of executed SQL query command
  1334.                             if (typeof data.sql_query != 'undefined') {
  1335.                                 //extract query box
  1336.                                 var $result_query = $($.parseHTML(data.sql_query));
  1337.                                 var sqlOuter = $result_query.find('.sqlOuter').wrap('<p>').parent().html();
  1338.                                 var tools = $result_query.find('.tools').wrap('<p>').parent().html();
  1339.                                 // sqlOuter and tools will not be present if 'Show SQL queries' configuration is off
  1340.                                 if (typeof sqlOuter != 'undefined' && typeof tools != 'undefined') {
  1341.                                     $(g.o).find('.result_query:not(:last)').remove();
  1342.                                     var $existing_query = $(g.o).find('.result_query');
  1343.                                     // If two query box exists update query in second else add a second box
  1344.                                     if ($existing_query.find('div.sqlOuter').length > 1) {
  1345.                                         $existing_query.children(":nth-child(4)").remove();
  1346.                                         $existing_query.children(":nth-child(4)").remove();
  1347.                                         $existing_query.append(sqlOuter + tools);
  1348.                                     } else {
  1349.                                         $existing_query.append(sqlOuter + tools);
  1350.                                     }
  1351.                                     PMA_highlightSQL($existing_query);
  1352.                                 }
  1353.                             }
  1354.                             // hide and/or update the successfully saved cells
  1355.                             g.hideEditCell(true, data);
  1356.  
  1357.                             // remove the "Save edited cells" button
  1358.                             $(g.o).find('div.save_edited').hide();
  1359.                             // update saved fields
  1360.                             $(g.t).find('.to_be_saved')
  1361.                                 .removeClass('to_be_saved')
  1362.                                 .data('value', null)
  1363.                                 .data('original_data', null);
  1364.  
  1365.                             g.isCellEdited = false;
  1366.                         } else {
  1367.                             PMA_ajaxShowMessage(data.error, false);
  1368.                             if (!g.saveCellsAtOnce) {
  1369.                                 $(g.t).find('.to_be_saved')
  1370.                                     .removeClass('to_be_saved');
  1371.                             }
  1372.                         }
  1373.                     }
  1374.             }).done(function(){
  1375.                 if (options !== undefined && options.move) {
  1376.                     g.showEditCell(options.cell);
  1377.                 }
  1378.             }); // end $.ajax()
  1379.         },
  1380.  
  1381.         /**
  1382.          * Save edited cell, so it can be posted later.
  1383.          */
  1384.         saveEditedCell: function () {
  1385.             /**
  1386.              * @var $this_field    Object referring to the td that is being edited
  1387.              */
  1388.             var $this_field = $(g.currentEditCell);
  1389.             var $test_element = ''; // to test the presence of a element
  1390.  
  1391.             var need_to_post = false;
  1392.  
  1393.             /**
  1394.              * @var field_name  String containing the name of this field.
  1395.              * @see getFieldName()
  1396.              */
  1397.             var field_name = getFieldName($(g.t), $this_field);
  1398.  
  1399.             /**
  1400.              * @var this_field_params   Array temporary storage for the name/value of current field
  1401.              */
  1402.             var this_field_params = {};
  1403.  
  1404.             /**
  1405.              * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked.
  1406.              */
  1407.             var is_null = $(g.cEdit).find('input:checkbox').is(':checked');
  1408.  
  1409.             if ($(g.cEdit).find('.edit_area').is('.edit_area_loading')) {
  1410.                 // the edit area is still loading (retrieving cell data), no need to post
  1411.                 need_to_post = false;
  1412.             } else if (is_null) {
  1413.                 if (!g.wasEditedCellNull) {
  1414.                     this_field_params[field_name] = null;
  1415.                     need_to_post = true;
  1416.                 }
  1417.             } else {
  1418.                 if ($this_field.is('.bit')) {
  1419.                     this_field_params[field_name] = $(g.cEdit).find('.edit_box').val();
  1420.                 } else if ($this_field.is('.set')) {
  1421.                     $test_element = $(g.cEdit).find('select');
  1422.                     this_field_params[field_name] = $test_element.map(function () {
  1423.                         return $(this).val();
  1424.                     }).get().join(",");
  1425.                 } else if ($this_field.is('.relation, .enum')) {
  1426.                     // for relation and enumeration, take the results from edit box value,
  1427.                     // because selected value from drop-down, new window or multiple
  1428.                     // selection list will always be updated to the edit box
  1429.                     this_field_params[field_name] = $(g.cEdit).find('.edit_box').val();
  1430.                 } else if ($this_field.hasClass('hex')) {
  1431.                     if ($(g.cEdit).find('.edit_box').val().match(/^[a-f0-9]*$/i) !== null) {
  1432.                         this_field_params[field_name] = $(g.cEdit).find('.edit_box').val();
  1433.                     } else {
  1434.                         var hexError = '<div class="error">' + PMA_messages.strEnterValidHex + '</div>';
  1435.                         PMA_ajaxShowMessage(hexError, false);
  1436.                         this_field_params[field_name] = PMA_getCellValue(g.currentEditCell);
  1437.                     }
  1438.                 } else {
  1439.                     this_field_params[field_name] = $(g.cEdit).find('.edit_box').val();
  1440.                 }
  1441.                 if (g.wasEditedCellNull || this_field_params[field_name] != PMA_getCellValue(g.currentEditCell)) {
  1442.                     need_to_post = true;
  1443.                 }
  1444.             }
  1445.  
  1446.             if (need_to_post) {
  1447.                 $(g.currentEditCell).addClass('to_be_saved')
  1448.                     .data('value', this_field_params[field_name]);
  1449.                 if (g.saveCellsAtOnce) {
  1450.                     $(g.o).find('div.save_edited').show();
  1451.                 }
  1452.                 g.isCellEdited = true;
  1453.             }
  1454.  
  1455.             return need_to_post;
  1456.         },
  1457.  
  1458.         /**
  1459.          * Save or post currently edited cell, depending on the "saveCellsAtOnce" configuration.
  1460.          *
  1461.          * @param field Optional, this object contains a boolean named move (true, if called from move* functions)
  1462.          *              and a <td> to which the grid_edit should move
  1463.          */
  1464.         saveOrPostEditedCell: function (options) {
  1465.             var saved = g.saveEditedCell();
  1466.             // Check if $cfg['SaveCellsAtOnce'] is false
  1467.             if (!g.saveCellsAtOnce) {
  1468.                 // Check if need_to_post is true
  1469.                 if (saved) {
  1470.                     // Check if this function called from 'move' functions
  1471.                     if (options !== undefined && options.move) {
  1472.                         g.postEditedCell(options);
  1473.                     } else {
  1474.                         g.postEditedCell();
  1475.                     }
  1476.                 // need_to_post is false
  1477.                 } else {
  1478.                     // Check if this function called from 'move' functions
  1479.                     if (options !== undefined && options.move) {
  1480.                         g.hideEditCell(true);
  1481.                         g.showEditCell(options.cell);
  1482.                     // NOT called from 'move' functions
  1483.                     } else {
  1484.                         g.hideEditCell(true);
  1485.                     }
  1486.                 }
  1487.             // $cfg['SaveCellsAtOnce'] is true
  1488.             } else {
  1489.                 // If need_to_post
  1490.                 if (saved) {
  1491.                     // If this function called from 'move' functions
  1492.                     if (options !== undefined && options.move) {
  1493.                         g.hideEditCell(true, true, false, options);
  1494.                         g.showEditCell(options.cell);
  1495.                     // NOT called from 'move' functions
  1496.                     } else {
  1497.                         g.hideEditCell(true, true);
  1498.                     }
  1499.                 } else {
  1500.                     // If this function called from 'move' functions
  1501.                     if (options !== undefined && options.move) {
  1502.                         g.hideEditCell(true, false, false, options);
  1503.                         g.showEditCell(options.cell);
  1504.                     // NOT called from 'move' functions
  1505.                     } else {
  1506.                         g.hideEditCell(true);
  1507.                     }
  1508.                 }
  1509.             }
  1510.         },
  1511.  
  1512.         /**
  1513.          * Initialize column resize feature.
  1514.          */
  1515.         initColResize: function () {
  1516.             // create column resizer div
  1517.             g.cRsz = document.createElement('div');
  1518.             g.cRsz.className = 'cRsz';
  1519.  
  1520.             // get data columns in the first row of the table
  1521.             var $firstRowCols = $(g.t).find('tr:first th.draggable');
  1522.  
  1523.             // create column borders
  1524.             $firstRowCols.each(function () {
  1525.                 var cb = document.createElement('div'); // column border
  1526.                 $(cb).addClass('colborder')
  1527.                     .mousedown(function (e) {
  1528.                         g.dragStartRsz(e, this);
  1529.                     });
  1530.                 $(g.cRsz).append(cb);
  1531.             });
  1532.             g.reposRsz();
  1533.  
  1534.             // attach to global div
  1535.             $(g.gDiv).prepend(g.cRsz);
  1536.         },
  1537.  
  1538.         /**
  1539.          * Initialize column reordering feature.
  1540.          */
  1541.         initColReorder: function () {
  1542.             g.cCpy = document.createElement('div');     // column copy, to store copy of dragged column header
  1543.             g.cPointer = document.createElement('div'); // column pointer, used when reordering column
  1544.  
  1545.             // adjust g.cCpy
  1546.             g.cCpy.className = 'cCpy';
  1547.             $(g.cCpy).hide();
  1548.  
  1549.             // adjust g.cPointer
  1550.             g.cPointer.className = 'cPointer';
  1551.             $(g.cPointer).css('visibility', 'hidden');  // set visibility to hidden instead of calling hide() to force browsers to cache the image in cPointer class
  1552.  
  1553.             // assign column reordering hint
  1554.             g.reorderHint = PMA_messages.strColOrderHint;
  1555.  
  1556.             // get data columns in the first row of the table
  1557.             var $firstRowCols = $(g.t).find('tr:first th.draggable');
  1558.  
  1559.             // initialize column order
  1560.             $col_order = $(g.o).find('.col_order');   // check if column order is passed from PHP
  1561.             if ($col_order.length > 0) {
  1562.                 g.colOrder = $col_order.val().split(',');
  1563.                 for (var i = 0; i < g.colOrder.length; i++) {
  1564.                     g.colOrder[i] = parseInt(g.colOrder[i], 10);
  1565.                 }
  1566.             } else {
  1567.                 g.colOrder = [];
  1568.                 for (var i = 0; i < $firstRowCols.length; i++) {
  1569.                     g.colOrder.push(i);
  1570.                 }
  1571.             }
  1572.  
  1573.             // register events
  1574.             $(g.t).find('th.draggable')
  1575.                 .mousedown(function (e) {
  1576.                     $(g.o).addClass("turnOffSelect");
  1577.                     if (g.visibleHeadersCount > 1) {
  1578.                         g.dragStartReorder(e, this);
  1579.                     }
  1580.                 })
  1581.                 .mouseenter(function () {
  1582.                     if (g.visibleHeadersCount > 1) {
  1583.                         $(this).css('cursor', 'move');
  1584.                     } else {
  1585.                         $(this).css('cursor', 'inherit');
  1586.                     }
  1587.                 })
  1588.                 .mouseleave(function () {
  1589.                     g.showReorderHint = false;
  1590.                     $(this).tooltip("option", {
  1591.                         content: g.updateHint()
  1592.                     });
  1593.                 })
  1594.                 .dblclick(function (e) {
  1595.                     e.preventDefault();
  1596.                     $("<div/>")
  1597.                     .prop("title", PMA_messages.strColNameCopyTitle)
  1598.                     .addClass("modal-copy")
  1599.                     .text(PMA_messages.strColNameCopyText)
  1600.                     .append(
  1601.                         $("<input/>")
  1602.                         .prop("readonly", true)
  1603.                         .val($(this).data("column"))
  1604.                         )
  1605.                     .dialog({
  1606.                         resizable: false,
  1607.                         modal: true
  1608.                     })
  1609.                     .find("input").focus().select();
  1610.                 });
  1611.             $(g.t).find('th.draggable a')
  1612.                 .dblclick(function (e) {
  1613.                     e.stopPropagation();
  1614.                 });
  1615.             // restore column order when the restore button is clicked
  1616.             $(g.o).find('div.restore_column').click(function () {
  1617.                 g.restoreColOrder();
  1618.             });
  1619.  
  1620.             // attach to global div
  1621.             $(g.gDiv).append(g.cPointer);
  1622.             $(g.gDiv).append(g.cCpy);
  1623.  
  1624.             // prevent default "dragstart" event when dragging a link
  1625.             $(g.t).find('th a').bind('dragstart', function () {
  1626.                 return false;
  1627.             });
  1628.  
  1629.             // refresh the restore column button state
  1630.             g.refreshRestoreButton();
  1631.         },
  1632.  
  1633.         /**
  1634.          * Initialize column visibility feature.
  1635.          */
  1636.         initColVisib: function () {
  1637.             g.cDrop = document.createElement('div');    // column drop-down arrows
  1638.             g.cList = document.createElement('div');    // column visibility list
  1639.  
  1640.             // adjust g.cDrop
  1641.             g.cDrop.className = 'cDrop';
  1642.  
  1643.             // adjust g.cList
  1644.             g.cList.className = 'cList';
  1645.             $(g.cList).hide();
  1646.  
  1647.             // assign column visibility related hints
  1648.             g.showAllColText = PMA_messages.strShowAllCol;
  1649.  
  1650.             // get data columns in the first row of the table
  1651.             var $firstRowCols = $(g.t).find('tr:first th.draggable');
  1652.  
  1653.             var i;
  1654.             // initialize column visibility
  1655.             var $col_visib = $(g.o).find('.col_visib');   // check if column visibility is passed from PHP
  1656.             if ($col_visib.length > 0) {
  1657.                 g.colVisib = $col_visib.val().split(',');
  1658.                 for (i = 0; i < g.colVisib.length; i++) {
  1659.                     g.colVisib[i] = parseInt(g.colVisib[i], 10);
  1660.                 }
  1661.             } else {
  1662.                 g.colVisib = [];
  1663.                 for (i = 0; i < $firstRowCols.length; i++) {
  1664.                     g.colVisib.push(1);
  1665.                 }
  1666.             }
  1667.  
  1668.             // make sure we have more than one column
  1669.             if ($firstRowCols.length > 1) {
  1670.                 var $colVisibTh = $(g.t).find('th:not(.draggable)');
  1671.                 PMA_tooltip(
  1672.                     $colVisibTh,
  1673.                     'th',
  1674.                     PMA_messages.strColVisibHint
  1675.                 );
  1676.  
  1677.                 // create column visibility drop-down arrow(s)
  1678.                 $colVisibTh.each(function () {
  1679.                         var $th = $(this);
  1680.                         var cd = document.createElement('div'); // column drop-down arrow
  1681.                         var pos = $th.position();
  1682.                         $(cd).addClass('coldrop')
  1683.                             .click(function () {
  1684.                                 if (g.cList.style.display == 'none') {
  1685.                                     g.showColList(this);
  1686.                                 } else {
  1687.                                     g.hideColList();
  1688.                                 }
  1689.                             });
  1690.                         $(g.cDrop).append(cd);
  1691.                     });
  1692.  
  1693.                 // add column visibility control
  1694.                 g.cList.innerHTML = '<div class="lDiv"></div>';
  1695.                 var $listDiv = $(g.cList).find('div');
  1696.  
  1697.                 var tempClick = function () {
  1698.                     if (g.toggleCol($(this).index())) {
  1699.                         g.afterToggleCol();
  1700.                     }
  1701.                 };
  1702.  
  1703.                 for (i = 0; i < $firstRowCols.length; i++) {
  1704.                     var currHeader = $firstRowCols[i];
  1705.                     var listElmt = document.createElement('div');
  1706.                     $(listElmt).text($(currHeader).text())
  1707.                         .prepend('<input type="checkbox" ' + (g.colVisib[i] ? 'checked="checked" ' : '') + '/>');
  1708.                     $listDiv.append(listElmt);
  1709.                     // add event on click
  1710.                     $(listElmt).click(tempClick);
  1711.                 }
  1712.                 // add "show all column" button
  1713.                 var showAll = document.createElement('div');
  1714.                 $(showAll).addClass('showAllColBtn')
  1715.                     .text(g.showAllColText);
  1716.                 $(g.cList).append(showAll);
  1717.                 $(showAll).click(function () {
  1718.                     g.showAllColumns();
  1719.                 });
  1720.                 // prepend "show all column" button at top if the list is too long
  1721.                 if ($firstRowCols.length > 10) {
  1722.                     var clone = showAll.cloneNode(true);
  1723.                     $(g.cList).prepend(clone);
  1724.                     $(clone).click(function () {
  1725.                         g.showAllColumns();
  1726.                     });
  1727.                 }
  1728.             }
  1729.  
  1730.             // hide column visibility list if we move outside the list
  1731.             $(g.t).find('td, th.draggable').mouseenter(function () {
  1732.                 g.hideColList();
  1733.             });
  1734.  
  1735.             // attach to global div
  1736.             $(g.gDiv).append(g.cDrop);
  1737.             $(g.gDiv).append(g.cList);
  1738.  
  1739.             // some adjustment
  1740.             g.reposDrop();
  1741.         },
  1742.  
  1743.         /**
  1744.          * Move currently Editing Cell to Up
  1745.          */
  1746.         moveUp: function(e) {
  1747.             e.preventDefault();
  1748.             var $this_field = $(g.currentEditCell);
  1749.             var field_name = getFieldName($(g.t), $this_field);
  1750.  
  1751.             var where_clause = $this_field.parents('tr').first().find('.where_clause').val();
  1752.             if (typeof where_clause === 'undefined') {
  1753.                 where_clause = '';
  1754.             }
  1755.             where_clause = PMA_urldecode(where_clause);
  1756.             var found = false;
  1757.             var $found_row;
  1758.             var $prev_row;
  1759.             var j = 0;
  1760.  
  1761.             $this_field.parents('tr').first().parents('tbody').children().each(function(){
  1762.                 if (PMA_urldecode($(this).find('.where_clause').val()) == where_clause) {
  1763.                     found = true;
  1764.                     $found_row = $(this);
  1765.                 }
  1766.                 if (!found) {
  1767.                     $prev_row = $(this);
  1768.                 }
  1769.             });
  1770.  
  1771.             var new_cell;
  1772.  
  1773.             if (found && $prev_row) {
  1774.                 $prev_row.children('td').each(function(){
  1775.                     if (getFieldName($(g.t), $(this)) == field_name) {
  1776.                         new_cell = this;
  1777.                     }
  1778.                 });
  1779.             }
  1780.  
  1781.             if (new_cell) {
  1782.                 g.hideEditCell(false, false, false, {move : true, cell : new_cell});
  1783.             }
  1784.         },
  1785.  
  1786.         /**
  1787.          * Move currently Editing Cell to Down
  1788.          */
  1789.         moveDown: function(e) {
  1790.             e.preventDefault();
  1791.  
  1792.             var $this_field = $(g.currentEditCell);
  1793.             var field_name = getFieldName($(g.t), $this_field);
  1794.  
  1795.             var where_clause = $this_field.parents('tr').first().find('.where_clause').val();
  1796.             if (typeof where_clause === 'undefined') {
  1797.                 where_clause = '';
  1798.             }
  1799.             where_clause = PMA_urldecode(where_clause);
  1800.             var found = false;
  1801.             var $found_row;
  1802.             var $next_row;
  1803.             var j = 0;
  1804.             var next_row_found = false;
  1805.             $this_field.parents('tr').first().parents('tbody').children().each(function(){
  1806.                 if (PMA_urldecode($(this).find('.where_clause').val()) == where_clause) {
  1807.                     found = true;
  1808.                     $found_row = $(this);
  1809.                 }
  1810.                 if (found) {
  1811.                     if (j >= 1 && ! next_row_found) {
  1812.                         $next_row = $(this);
  1813.                         next_row_found = true;
  1814.                     } else {
  1815.                         j++;
  1816.                     }
  1817.                 }
  1818.             });
  1819.  
  1820.             var new_cell;
  1821.             if (found && $next_row) {
  1822.                 $next_row.children('td').each(function(){
  1823.                     if (getFieldName($(g.t), $(this)) == field_name) {
  1824.                         new_cell = this;
  1825.                     }
  1826.                 });
  1827.             }
  1828.  
  1829.             if (new_cell) {
  1830.                 g.hideEditCell(false, false, false, {move : true, cell : new_cell});
  1831.             }
  1832.         },
  1833.  
  1834.         /**
  1835.          * Move currently Editing Cell to Left
  1836.          */
  1837.         moveLeft: function(e) {
  1838.             e.preventDefault();
  1839.  
  1840.             var $this_field = $(g.currentEditCell);
  1841.             var field_name = getFieldName($(g.t), $this_field);
  1842.  
  1843.             var where_clause = $this_field.parents('tr').first().find('.where_clause').val();
  1844.             if (typeof where_clause === 'undefined') {
  1845.                 where_clause = '';
  1846.             }
  1847.             where_clause = PMA_urldecode(where_clause);
  1848.             var found = false;
  1849.             var $found_row;
  1850.             var j = 0;
  1851.             $this_field.parents('tr').first().parents('tbody').children().each(function(){
  1852.                 if (PMA_urldecode($(this).find('.where_clause').val()) == where_clause) {
  1853.                     found = true;
  1854.                     $found_row = $(this);
  1855.                 }
  1856.             });
  1857.  
  1858.             var left_cell;
  1859.             var cell_found = false;
  1860.             if (found) {
  1861.                 $found_row.children('td.grid_edit').each(function(){
  1862.                     if (getFieldName($(g.t), $(this)) === field_name) {
  1863.                         cell_found = true;
  1864.                     }
  1865.                     if (!cell_found) {
  1866.                         left_cell = this;
  1867.                     }
  1868.                 });
  1869.             }
  1870.  
  1871.             if (left_cell) {
  1872.                 g.hideEditCell(false, false, false, {move : true, cell : left_cell});
  1873.             }
  1874.         },
  1875.  
  1876.         /**
  1877.          * Move currently Editing Cell to Right
  1878.          */
  1879.         moveRight: function(e) {
  1880.             e.preventDefault();
  1881.  
  1882.             var $this_field = $(g.currentEditCell);
  1883.             var field_name = getFieldName($(g.t), $this_field);
  1884.  
  1885.             var where_clause = $this_field.parents('tr').first().find('.where_clause').val();
  1886.             if (typeof where_clause === 'undefined') {
  1887.                 where_clause = '';
  1888.             }
  1889.             where_clause = PMA_urldecode(where_clause);
  1890.             var found = false;
  1891.             var $found_row;
  1892.             var j = 0;
  1893.             $this_field.parents('tr').first().parents('tbody').children().each(function(){
  1894.                 if (PMA_urldecode($(this).find('.where_clause').val()) == where_clause) {
  1895.                     found = true;
  1896.                     $found_row = $(this);
  1897.                 }
  1898.             });
  1899.  
  1900.             var right_cell;
  1901.             var cell_found = false;
  1902.             var next_cell_found = false;
  1903.             if (found) {
  1904.                 $found_row.children('td.grid_edit').each(function(){
  1905.                     if (getFieldName($(g.t), $(this)) === field_name) {
  1906.                         cell_found = true;
  1907.                     }
  1908.                     if (cell_found) {
  1909.                         if (j >= 1 && ! next_cell_found) {
  1910.                             right_cell = this;
  1911.                             next_cell_found = true;
  1912.                         } else {
  1913.                             j++;
  1914.                         }
  1915.                     }
  1916.                 });
  1917.             }
  1918.  
  1919.             if (right_cell) {
  1920.                 g.hideEditCell(false, false, false, {move : true, cell : right_cell});
  1921.             }
  1922.         },
  1923.  
  1924.         /**
  1925.          * Initialize grid editing feature.
  1926.          */
  1927.         initGridEdit: function () {
  1928.  
  1929.             function startGridEditing(e, cell) {
  1930.                 if (g.isCellEditActive) {
  1931.                     g.saveOrPostEditedCell();
  1932.                 } else {
  1933.                     g.showEditCell(cell);
  1934.                 }
  1935.                 e.stopPropagation();
  1936.             }
  1937.  
  1938.             function handleCtrlNavigation(e) {
  1939.                 if ((e.ctrlKey && e.which == 38 ) || (e.altKey && e.which == 38)) {
  1940.                     g.moveUp(e);
  1941.                 } else if ((e.ctrlKey && e.which == 40)  || (e.altKey && e.which == 40)) {
  1942.                     g.moveDown(e);
  1943.                 } else if ((e.ctrlKey && e.which == 37 ) || (e.altKey && e.which == 37)) {
  1944.                     g.moveLeft(e);
  1945.                 } else if ((e.ctrlKey && e.which == 39)  || (e.altKey && e.which == 39)) {
  1946.                     g.moveRight(e);
  1947.                 }
  1948.             }
  1949.  
  1950.             // create cell edit wrapper element
  1951.             g.cEditStd = document.createElement('div');
  1952.             g.cEdit = g.cEditStd;
  1953.             g.cEditTextarea = document.createElement('div');
  1954.  
  1955.             // adjust g.cEditStd
  1956.             g.cEditStd.className = 'cEdit';
  1957.             $(g.cEditStd).html('<input class="edit_box" rows="1" ></input><div class="edit_area" />');
  1958.             $(g.cEditStd).hide();
  1959.  
  1960.             // adjust g.cEdit
  1961.             g.cEditTextarea.className = 'cEdit';
  1962.             $(g.cEditTextarea).html('<textarea class="edit_box" rows="1" ></textarea><div class="edit_area" />');
  1963.             $(g.cEditTextarea).hide();
  1964.  
  1965.             // assign cell editing hint
  1966.             g.cellEditHint = PMA_messages.strCellEditHint;
  1967.             g.saveCellWarning = PMA_messages.strSaveCellWarning;
  1968.             g.alertNonUnique = PMA_messages.strAlertNonUnique;
  1969.             g.gotoLinkText = PMA_messages.strGoToLink;
  1970.  
  1971.             // initialize cell editing configuration
  1972.             g.saveCellsAtOnce = $(g.o).find('.save_cells_at_once').val();
  1973.             g.maxTruncatedLen = PMA_commonParams.get('LimitChars');
  1974.  
  1975.             // register events
  1976.             $(g.t).find('td.data.click1')
  1977.                 .click(function (e) {
  1978.                     startGridEditing(e, this);
  1979.                     // prevent default action when clicking on "link" in a table
  1980.                     if ($(e.target).is('.grid_edit a')) {
  1981.                         e.preventDefault();
  1982.                     }
  1983.                 });
  1984.  
  1985.             $(g.t).find('td.data.click2')
  1986.                 .click(function (e) {
  1987.                     var $cell = $(this);
  1988.                     // In the case of relational link, We want single click on the link
  1989.                     // to goto the link and double click to start grid-editing.
  1990.                     var $link = $(e.target);
  1991.                     if ($link.is('.grid_edit.relation a')) {
  1992.                         e.preventDefault();
  1993.                         // get the click count and increase
  1994.                         var clicks = $cell.data('clicks');
  1995.                         clicks = (typeof clicks === 'undefined') ? 1 : clicks + 1;
  1996.  
  1997.                         if (clicks == 1) {
  1998.                             // if there are no previous clicks,
  1999.                             // start the single click timer
  2000.                             var timer = setTimeout(function () {
  2001.                                 // temporarily remove ajax class so the page loader will not handle it,
  2002.                                 // submit and then add it back
  2003.                                 $link.removeClass('ajax');
  2004.                                 AJAX.requestHandler.call($link[0]);
  2005.                                 $link.addClass('ajax');
  2006.                                 $cell.data('clicks', 0);
  2007.                             }, 700);
  2008.                             $cell.data('clicks', clicks);
  2009.                             $cell.data('timer', timer);
  2010.                         } else {
  2011.                             // this is a double click, cancel the single click timer
  2012.                             // and make the click count 0
  2013.                             clearTimeout($cell.data('timer'));
  2014.                             $cell.data('clicks', 0);
  2015.                             // start grid-editing
  2016.                             startGridEditing(e, this);
  2017.                         }
  2018.                     }
  2019.                 })
  2020.                 .dblclick(function (e) {
  2021.                     if ($(e.target).is('.grid_edit a')) {
  2022.                         e.preventDefault();
  2023.                     } else {
  2024.                         startGridEditing(e, this);
  2025.                     }
  2026.                 });
  2027.  
  2028.             $(g.cEditStd).on('keydown', 'input.edit_box, select', handleCtrlNavigation);
  2029.  
  2030.             $(g.cEditStd).find('.edit_box').focus(function () {
  2031.                 g.showEditArea();
  2032.             });
  2033.             $(g.cEditStd).on('keydown', '.edit_box, select', function (e) {
  2034.                 if (e.which == 13) {
  2035.                     // post on pressing "Enter"
  2036.                     e.preventDefault();
  2037.                     g.saveOrPostEditedCell();
  2038.                 }
  2039.             });
  2040.             $(g.cEditStd).keydown(function (e) {
  2041.                 if (!g.isEditCellTextEditable) {
  2042.                     // prevent text editing
  2043.                     e.preventDefault();
  2044.                 }
  2045.             });
  2046.  
  2047.             $(g.cEditTextarea).on('keydown', 'textarea.edit_box, select', handleCtrlNavigation);
  2048.  
  2049.             $(g.cEditTextarea).find('.edit_box').focus(function () {
  2050.                 g.showEditArea();
  2051.             });
  2052.             $(g.cEditTextarea).on('keydown', '.edit_box, select', function (e) {
  2053.                 if (e.which == 13 && !e.shiftKey) {
  2054.                     // post on pressing "Enter"
  2055.                     e.preventDefault();
  2056.                     g.saveOrPostEditedCell();
  2057.                 }
  2058.             });
  2059.             $(g.cEditTextarea).keydown(function (e) {
  2060.                 if (!g.isEditCellTextEditable) {
  2061.                     // prevent text editing
  2062.                     e.preventDefault();
  2063.                 }
  2064.             });
  2065.             $('html').click(function (e) {
  2066.                 // hide edit cell if the click is not fromDat edit area
  2067.                 if ($(e.target).parents().index($(g.cEdit)) == -1 &&
  2068.                     !$(e.target).parents('.ui-datepicker-header').length &&
  2069.                     !$('.browse_foreign_modal.ui-dialog:visible').length
  2070.                 ) {
  2071.                     g.hideEditCell();
  2072.                 }
  2073.             }).keydown(function (e) {
  2074.                 if (e.which == 27 && g.isCellEditActive) {
  2075.  
  2076.                     // cancel on pressing "Esc"
  2077.                     g.hideEditCell(true);
  2078.                 }
  2079.             });
  2080.             $(g.o).find('div.save_edited').click(function () {
  2081.                 g.hideEditCell();
  2082.                 g.postEditedCell();
  2083.             });
  2084.             $(window).bind('beforeunload', function () {
  2085.                 if (g.isCellEdited) {
  2086.                     return g.saveCellWarning;
  2087.                 }
  2088.             });
  2089.  
  2090.             // attach to global div
  2091.             $(g.gDiv).append(g.cEditStd);
  2092.             $(g.gDiv).append(g.cEditTextarea);
  2093.  
  2094.             // add hint for grid editing feature when hovering "Edit" link in each table row
  2095.             if (PMA_messages.strGridEditFeatureHint !== undefined) {
  2096.                 PMA_tooltip(
  2097.                     $(g.t).find('.edit_row_anchor a'),
  2098.                     'a',
  2099.                     PMA_messages.strGridEditFeatureHint
  2100.                 );
  2101.             }
  2102.         }
  2103.     };
  2104.  
  2105.     /******************
  2106.      * Initialize grid
  2107.      ******************/
  2108.  
  2109.     // wrap all truncated data cells with span indicating the original length
  2110.     // todo update the original length after a grid edit
  2111.     $(t).find('td.data.truncated:not(:has(span))')
  2112.         .wrapInner(function() {
  2113.             return '<span title="' + PMA_messages.strOriginalLength + ' ' +
  2114.                 $(this).data('originallength') + '"></span>';
  2115.         });
  2116.  
  2117.     // wrap remaining cells, except actions cell, with span
  2118.     $(t).find('th, td:not(:has(span))')
  2119.         .wrapInner('<span />');
  2120.  
  2121.     // create grid elements
  2122.     g.gDiv = document.createElement('div');     // create global div
  2123.  
  2124.     // initialize the table variable
  2125.     g.t = t;
  2126.  
  2127.     // enclosing .sqlqueryresults div
  2128.     g.o = $(t).parents('.sqlqueryresults');
  2129.  
  2130.     // get data columns in the first row of the table
  2131.     var $firstRowCols = $(t).find('tr:first th.draggable');
  2132.  
  2133.     // initialize visible headers count
  2134.     g.visibleHeadersCount = $firstRowCols.filter(':visible').length;
  2135.  
  2136.     // assign first column (actions) span
  2137.     if (! $(t).find('tr:first th:first').hasClass('draggable')) {  // action header exist
  2138.         g.actionSpan = $(t).find('tr:first th:first').prop('colspan');
  2139.     } else {
  2140.         g.actionSpan = 0;
  2141.     }
  2142.  
  2143.     // assign table create time
  2144.     // table_create_time will only available if we are in "Browse" tab
  2145.     g.tableCreateTime = $(g.o).find('.table_create_time').val();
  2146.  
  2147.     // assign the hints
  2148.     g.sortHint = PMA_messages.strSortHint;
  2149.     g.strMultiSortHint = PMA_messages.strMultiSortHint;
  2150.     g.markHint = PMA_messages.strColMarkHint;
  2151.     g.copyHint = PMA_messages.strColNameCopyHint;
  2152.  
  2153.     // assign common hidden inputs
  2154.     var $common_hidden_inputs = $(g.o).find('div.common_hidden_inputs');
  2155.     g.token = $common_hidden_inputs.find('input[name=token]').val();
  2156.     g.server = $common_hidden_inputs.find('input[name=server]').val();
  2157.     g.db = $common_hidden_inputs.find('input[name=db]').val();
  2158.     g.table = $common_hidden_inputs.find('input[name=table]').val();
  2159.  
  2160.     // add table class
  2161.     $(t).addClass('pma_table');
  2162.  
  2163.     // add relative position to global div so that resize handlers are correctly positioned
  2164.     $(g.gDiv).css('position', 'relative');
  2165.  
  2166.     // link the global div
  2167.     $(t).before(g.gDiv);
  2168.     $(g.gDiv).append(t);
  2169.  
  2170.     // FEATURES
  2171.     enableResize    = enableResize === undefined ? true : enableResize;
  2172.     enableReorder   = enableReorder === undefined ? true : enableReorder;
  2173.     enableVisib     = enableVisib === undefined ? true : enableVisib;
  2174.     enableGridEdit  = enableGridEdit === undefined ? true : enableGridEdit;
  2175.     if (enableResize) {
  2176.         g.initColResize();
  2177.     }
  2178.     if (enableReorder &&
  2179.         $(g.o).find('table.navigation').length > 0)    // disable reordering for result from EXPLAIN or SHOW syntax, which do not have a table navigation panel
  2180.     {
  2181.         g.initColReorder();
  2182.     }
  2183.     if (enableVisib) {
  2184.         g.initColVisib();
  2185.     }
  2186.     if (enableGridEdit &&
  2187.         $(t).is('.ajax'))   // make sure we have the ajax class
  2188.     {
  2189.         g.initGridEdit();
  2190.     }
  2191.  
  2192.     // create tooltip for each <th> with draggable class
  2193.     PMA_tooltip(
  2194.             $(t).find("th.draggable"),
  2195.             'th',
  2196.             g.updateHint()
  2197.     );
  2198.  
  2199.     // register events for hint tooltip (anchors inside draggable th)
  2200.     $(t).find('th.draggable a')
  2201.         .mouseenter(function () {
  2202.             g.showSortHint = true;
  2203.             g.showMultiSortHint = true;
  2204.             $(t).find("th.draggable").tooltip("option", {
  2205.                 content: g.updateHint()
  2206.             });
  2207.         })
  2208.         .mouseleave(function () {
  2209.             g.showSortHint = false;
  2210.             g.showMultiSortHint = false;
  2211.             $(t).find("th.draggable").tooltip("option", {
  2212.                 content: g.updateHint()
  2213.             });
  2214.         });
  2215.  
  2216.     // register events for dragging-related feature
  2217.     if (enableResize || enableReorder) {
  2218.         $(document).mousemove(function (e) {
  2219.             g.dragMove(e);
  2220.         });
  2221.         $(document).mouseup(function (e) {
  2222.             $(g.o).removeClass("turnOffSelect");
  2223.             g.dragEnd(e);
  2224.         });
  2225.     }
  2226.  
  2227.     // some adjustment
  2228.     $(t).removeClass('data');
  2229.     $(g.gDiv).addClass('data');
  2230. }
  2231.  
  2232. /**
  2233.  * jQuery plugin to cancel selection in HTML code.
  2234.  */
  2235. (function ($) {
  2236.     $.fn.noSelect = function (p) { //no select plugin by Paulo P.Marinas
  2237.         var prevent = (p === null) ? true : p;
  2238.         var is_msie = navigator.userAgent.indexOf('MSIE') > -1 || !!window.navigator.userAgent.match(/Trident.*rv\:11\./);
  2239.         var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
  2240.         var is_safari = navigator.userAgent.indexOf("Safari") > -1;
  2241.         var is_opera = navigator.userAgent.indexOf("Presto") > -1;
  2242.         if (prevent) {
  2243.             return this.each(function () {
  2244.                 if (is_msie || is_safari) {
  2245.                     $(this).bind('selectstart', function () {
  2246.                         return false;
  2247.                     });
  2248.                 } else if (is_firefox) {
  2249.                     $(this).css('MozUserSelect', 'none');
  2250.                     $('body').trigger('focus');
  2251.                 } else if (is_opera) {
  2252.                     $(this).bind('mousedown', function () {
  2253.                         return false;
  2254.                     });
  2255.                 } else {
  2256.                     $(this).attr('unselectable', 'on');
  2257.                 }
  2258.             });
  2259.         } else {
  2260.             return this.each(function () {
  2261.                 if (is_msie || is_safari) {
  2262.                     $(this).unbind('selectstart');
  2263.                 } else if (is_firefox) {
  2264.                     $(this).css('MozUserSelect', 'inherit');
  2265.                 } else if (is_opera) {
  2266.                     $(this).unbind('mousedown');
  2267.                 } else {
  2268.                     $(this).removeAttr('unselectable');
  2269.                 }
  2270.             });
  2271.         }
  2272.     }; //end noSelect
  2273. })(jQuery);

Paste-bin is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste
'); $editArea.find('textarea').val(value); $editArea .on('keyup', 'textarea', function () { $(g.cEdit).find('.edit_box').val($(this).val()); }); $(g.cEdit).on('keyup', '.edit_box', function () { $editArea.find('textarea').val($(this).val()); }); $editArea.append('
' + g.cellEditHint + '
'); } else { //handle truncated/transformed values values $editArea.addClass('edit_area_loading'); // initialize the original data $td.data('original_data', null); /** * @var sql_query String containing the SQL query used to retrieve value of truncated/transformed data */ var sql_query = 'SELECT `' + field_name + '` FROM `' + g.table + '` WHERE ' + PMA_urldecode(where_clause); // Make the Ajax call and get the data, wrap it and insert it g.lastXHR = $.post('sql.php', { 'token' : g.token, 'server' : g.server, 'db' : g.db, 'ajax_request' : true, 'sql_query' : sql_query, 'grid_edit' : true }, function (data) { g.lastXHR = null; $editArea.removeClass('edit_area_loading'); if (typeof data !== 'undefined' && data.success === true) { $td.data('original_data', data.value); $(g.cEdit).find('.edit_box').val(data.value); } else { PMA_ajaxShowMessage(data.error, false); } }); // end $.post() } g.isEditCellTextEditable = true; } else if ($td.is('.timefield, .datefield, .datetimefield, .timestampfield')) { var $input_field = $(g.cEdit).find('.edit_box'); // remember current datetime value in $input_field, if it is not null var datetime_value = !is_null ? $input_field.val() : ''; var showMillisec = false; var showMicrosec = false; var timeFormat = 'HH:mm:ss'; // check for decimal places of seconds if (($td.attr('data-decimals') > 0) && ($td.attr('data-type').indexOf('time') != -1)){ if (datetime_value && datetime_value.indexOf('.') === false) { datetime_value += '.'; } if ($td.attr('data-decimals') > 3) { showMillisec = true; showMicrosec = true; timeFormat = 'HH:mm:ss.lc'; if (datetime_value) { datetime_value += '000000'; var datetime_value = datetime_value.substring(0, datetime_value.indexOf('.') + 7); $input_field.val(datetime_value); } } else { showMillisec = true; timeFormat = 'HH:mm:ss.l'; if (datetime_value) { datetime_value += '000'; var datetime_value = datetime_value.substring(0, datetime_value.indexOf('.') + 4); $input_field.val(datetime_value); } } } // add datetime picker PMA_addDatepicker($input_field, $td.attr('data-type'), { showMillisec: showMillisec, showMicrosec: showMicrosec, timeFormat: timeFormat }); $input_field.datepicker("show"); // unbind the mousedown event to prevent the problem of // datepicker getting closed, needs to be checked for any // change in names when updating $(document).unbind('mousedown', $.datepicker._checkExternalClick); //move ui-datepicker-div inside cEdit div var datepicker_div = $('#ui-datepicker-div'); datepicker_div.css({'top': 0, 'left': 0, 'position': 'relative'}); $(g.cEdit).append(datepicker_div); // cancel any click on the datepicker element $editArea.find('> *').click(function (e) { e.stopPropagation(); }); g.isEditCellTextEditable = true; } else { g.isEditCellTextEditable = true; // only append edit area hint if there is a null checkbox if ($editArea.children().length > 0) { $editArea.append('
' + g.cellEditHint + '
'); } } if ($editArea.children().length > 0) { $editArea.show(); } } }, /** * Post the content of edited cell. * * @param field Optional, this object contains a boolean named move (true, if called from move* functions) * and a to which the grid_edit should move */ postEditedCell: function (options) { if (g.isSaving) { return; } g.isSaving = true; /** * @var relation_fields Array containing the name/value pairs of relational fields */ var relation_fields = {}; /** * @var relational_display string 'K' if relational key, 'D' if relational display column */ var relational_display = $(g.o).find("input[name=relational_display]:checked").val(); /** * @var transform_fields Array containing the name/value pairs for transformed fields */ var transform_fields = {}; /** * @var transformation_fields Boolean, if there are any transformed fields in the edited cells */ var transformation_fields = false; /** * @var full_sql_query String containing the complete SQL query to update this table */ var full_sql_query = ''; /** * @var rel_fields_list String, url encoded representation of {@link relations_fields} */ var rel_fields_list = ''; /** * @var transform_fields_list String, url encoded representation of {@link transform_fields} */ var transform_fields_list = ''; /** * @var where_clause Array containing where clause for updated fields */ var full_where_clause = []; /** * @var is_unique Boolean, whether the rows in this table is unique or not */ var is_unique = $(g.t).find('td.edit_row_anchor').is('.nonunique') ? 0 : 1; /** * multi edit variables */ var me_fields_name = []; var me_fields_type = []; var me_fields = []; var me_fields_null = []; // alert user if edited table is not unique if (!is_unique) { alert(g.alertNonUnique); } // loop each edited row $(g.t).find('td.to_be_saved').parents('tr').each(function () { var $tr = $(this); var where_clause = $tr.find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } full_where_clause.push(PMA_urldecode(where_clause)); var condition_array = jQuery.parseJSON($tr.find('.condition_array').val()); /** * multi edit variables, for current row * @TODO array indices are still not correct, they should be md5 of field's name */ var fields_name = []; var fields_type = []; var fields = []; var fields_null = []; // loop each edited cell in a row $tr.find('.to_be_saved').each(function () { /** * @var $this_field Object referring to the td that is being edited */ var $this_field = $(this); /** * @var field_name String containing the name of this field. * @see getFieldName() */ var field_name = getFieldName($(g.t), $this_field); /** * @var this_field_params Array temporary storage for the name/value of current field */ var this_field_params = {}; if ($this_field.is('.transformed')) { transformation_fields = true; } this_field_params[field_name] = $this_field.data('value'); /** * @var is_null String capturing whether 'checkbox_null__' is checked. */ var is_null = this_field_params[field_name] === null; fields_name.push(field_name); if (is_null) { fields_null.push('on'); fields.push(''); } else { if ($this_field.is('.bit')) { fields_type.push('bit'); } else if ($this_field.hasClass('hex')) { fields_type.push('hex'); } fields_null.push(''); fields.push($this_field.data('value')); var cell_index = $this_field.index('.to_be_saved'); if ($this_field.is(":not(.relation, .enum, .set, .bit)")) { if ($this_field.is('.transformed')) { transform_fields[cell_index] = {}; $.extend(transform_fields[cell_index], this_field_params); } } else if ($this_field.is('.relation')) { relation_fields[cell_index] = {}; $.extend(relation_fields[cell_index], this_field_params); } } // check if edited field appears in WHERE clause if (where_clause.indexOf(PMA_urlencode(field_name)) > -1) { var field_str = '`' + g.table + '`.' + '`' + field_name + '`'; for (var field in condition_array) { if (field.indexOf(field_str) > -1) { condition_array[field] = is_null ? 'IS NULL' : "= '" + this_field_params[field_name].replace(/'/g, "''") + "'"; break; } } } }); // end of loop for every edited cells in a row // save new_clause var new_clause = ''; for (var field in condition_array) { new_clause += field + ' ' + condition_array[field] + ' AND '; } new_clause = new_clause.substring(0, new_clause.length - 5); // remove the last AND new_clause = PMA_urlencode(new_clause); $tr.data('new_clause', new_clause); // save condition_array $tr.find('.condition_array').val(JSON.stringify(condition_array)); me_fields_name.push(fields_name); me_fields_type.push(fields_type); me_fields.push(fields); me_fields_null.push(fields_null); }); // end of loop for every edited rows rel_fields_list = $.param(relation_fields); transform_fields_list = $.param(transform_fields); // Make the Ajax post after setting all parameters /** * @var post_params Object containing parameters for the POST request */ var post_params = {'ajax_request' : true, 'sql_query' : full_sql_query, 'token' : g.token, 'server' : g.server, 'db' : g.db, 'table' : g.table, 'clause_is_unique' : is_unique, 'where_clause' : full_where_clause, 'fields[multi_edit]' : me_fields, 'fields_name[multi_edit]' : me_fields_name, 'fields_type[multi_edit]' : me_fields_type, 'fields_null[multi_edit]' : me_fields_null, 'rel_fields_list' : rel_fields_list, 'do_transformations' : transformation_fields, 'transform_fields_list' : transform_fields_list, 'relational_display' : relational_display, 'goto' : 'sql.php', 'submit_type' : 'save' }; if (!g.saveCellsAtOnce) { $(g.cEdit).find('*').prop('disabled', true); $(g.cEdit).find('.edit_box').addClass('edit_box_posting'); } else { $(g.o).find('div.save_edited').addClass('saving_edited_data') .find('input').prop('disabled', true); // disable the save button } $.ajax({ type: 'POST', url: 'tbl_replace.php', data: post_params, success: function (data) { g.isSaving = false; if (!g.saveCellsAtOnce) { $(g.cEdit).find('*').prop('disabled', false); $(g.cEdit).find('.edit_box').removeClass('edit_box_posting'); } else { $(g.o).find('div.save_edited').removeClass('saving_edited_data') .find('input').prop('disabled', false); // enable the save button back } if (typeof data !== 'undefined' && data.success === true) { if (typeof options === 'undefined' || ! options.move) { PMA_ajaxShowMessage(data.message); } // update where_clause related data in each edited row $(g.t).find('td.to_be_saved').parents('tr').each(function () { var new_clause = $(this).data('new_clause'); var $where_clause = $(this).find('.where_clause'); var old_clause = $where_clause.val(); var decoded_old_clause = PMA_urldecode(old_clause); var decoded_new_clause = PMA_urldecode(new_clause); $where_clause.val(new_clause); // update Edit, Copy, and Delete links also $(this).find('a').each(function () { $(this).attr('href', $(this).attr('href').replace(old_clause, new_clause)); // update delete confirmation in Delete link if ($(this).attr('href').indexOf('DELETE') > -1) { $(this).removeAttr('onclick') .unbind('click') .bind('click', function () { return confirmLink(this, 'DELETE FROM `' + g.db + '`.`' + g.table + '` WHERE ' + decoded_new_clause + (is_unique ? '' : ' LIMIT 1')); }); } }); // update the multi edit checkboxes $(this).find('input[type=checkbox]').each(function () { var $checkbox = $(this); var checkbox_name = $checkbox.attr('name'); var checkbox_value = $checkbox.val(); $checkbox.attr('name', checkbox_name.replace(old_clause, new_clause)); $checkbox.val(checkbox_value.replace(decoded_old_clause, decoded_new_clause)); }); }); // update the display of executed SQL query command if (typeof data.sql_query != 'undefined') { //extract query box var $result_query = $($.parseHTML(data.sql_query)); var sqlOuter = $result_query.find('.sqlOuter').wrap('

').parent().html(); var tools = $result_query.find('.tools').wrap('

').parent().html(); // sqlOuter and tools will not be present if 'Show SQL queries' configuration is off if (typeof sqlOuter != 'undefined' && typeof tools != 'undefined') { $(g.o).find('.result_query:not(:last)').remove(); var $existing_query = $(g.o).find('.result_query'); // If two query box exists update query in second else add a second box if ($existing_query.find('div.sqlOuter').length > 1) { $existing_query.children(":nth-child(4)").remove(); $existing_query.children(":nth-child(4)").remove(); $existing_query.append(sqlOuter + tools); } else { $existing_query.append(sqlOuter + tools); } PMA_highlightSQL($existing_query); } } // hide and/or update the successfully saved cells g.hideEditCell(true, data); // remove the "Save edited cells" button $(g.o).find('div.save_edited').hide(); // update saved fields $(g.t).find('.to_be_saved') .removeClass('to_be_saved') .data('value', null) .data('original_data', null); g.isCellEdited = false; } else { PMA_ajaxShowMessage(data.error, false); if (!g.saveCellsAtOnce) { $(g.t).find('.to_be_saved') .removeClass('to_be_saved'); } } } }).done(function(){ if (options !== undefined && options.move) { g.showEditCell(options.cell); } }); // end $.ajax() }, /** * Save edited cell, so it can be posted later. */ saveEditedCell: function () { /** * @var $this_field Object referring to the td that is being edited */ var $this_field = $(g.currentEditCell); var $test_element = ''; // to test the presence of a element var need_to_post = false; /** * @var field_name String containing the name of this field. * @see getFieldName() */ var field_name = getFieldName($(g.t), $this_field); /** * @var this_field_params Array temporary storage for the name/value of current field */ var this_field_params = {}; /** * @var is_null String capturing whether 'checkbox_null__' is checked. */ var is_null = $(g.cEdit).find('input:checkbox').is(':checked'); if ($(g.cEdit).find('.edit_area').is('.edit_area_loading')) { // the edit area is still loading (retrieving cell data), no need to post need_to_post = false; } else if (is_null) { if (!g.wasEditedCellNull) { this_field_params[field_name] = null; need_to_post = true; } } else { if ($this_field.is('.bit')) { this_field_params[field_name] = $(g.cEdit).find('.edit_box').val(); } else if ($this_field.is('.set')) { $test_element = $(g.cEdit).find('select'); this_field_params[field_name] = $test_element.map(function () { return $(this).val(); }).get().join(","); } else if ($this_field.is('.relation, .enum')) { // for relation and enumeration, take the results from edit box value, // because selected value from drop-down, new window or multiple // selection list will always be updated to the edit box this_field_params[field_name] = $(g.cEdit).find('.edit_box').val(); } else if ($this_field.hasClass('hex')) { if ($(g.cEdit).find('.edit_box').val().match(/^[a-f0-9]*$/i) !== null) { this_field_params[field_name] = $(g.cEdit).find('.edit_box').val(); } else { var hexError = '

' + PMA_messages.strEnterValidHex + '
'; PMA_ajaxShowMessage(hexError, false); this_field_params[field_name] = PMA_getCellValue(g.currentEditCell); } } else { this_field_params[field_name] = $(g.cEdit).find('.edit_box').val(); } if (g.wasEditedCellNull || this_field_params[field_name] != PMA_getCellValue(g.currentEditCell)) { need_to_post = true; } } if (need_to_post) { $(g.currentEditCell).addClass('to_be_saved') .data('value', this_field_params[field_name]); if (g.saveCellsAtOnce) { $(g.o).find('div.save_edited').show(); } g.isCellEdited = true; } return need_to_post; }, /** * Save or post currently edited cell, depending on the "saveCellsAtOnce" configuration. * * @param field Optional, this object contains a boolean named move (true, if called from move* functions) * and a to which the grid_edit should move */ saveOrPostEditedCell: function (options) { var saved = g.saveEditedCell(); // Check if $cfg['SaveCellsAtOnce'] is false if (!g.saveCellsAtOnce) { // Check if need_to_post is true if (saved) { // Check if this function called from 'move' functions if (options !== undefined && options.move) { g.postEditedCell(options); } else { g.postEditedCell(); } // need_to_post is false } else { // Check if this function called from 'move' functions if (options !== undefined && options.move) { g.hideEditCell(true); g.showEditCell(options.cell); // NOT called from 'move' functions } else { g.hideEditCell(true); } } // $cfg['SaveCellsAtOnce'] is true } else { // If need_to_post if (saved) { // If this function called from 'move' functions if (options !== undefined && options.move) { g.hideEditCell(true, true, false, options); g.showEditCell(options.cell); // NOT called from 'move' functions } else { g.hideEditCell(true, true); } } else { // If this function called from 'move' functions if (options !== undefined && options.move) { g.hideEditCell(true, false, false, options); g.showEditCell(options.cell); // NOT called from 'move' functions } else { g.hideEditCell(true); } } } }, /** * Initialize column resize feature. */ initColResize: function () { // create column resizer div g.cRsz = document.createElement('div'); g.cRsz.className = 'cRsz'; // get data columns in the first row of the table var $firstRowCols = $(g.t).find('tr:first th.draggable'); // create column borders $firstRowCols.each(function () { var cb = document.createElement('div'); // column border $(cb).addClass('colborder') .mousedown(function (e) { g.dragStartRsz(e, this); }); $(g.cRsz).append(cb); }); g.reposRsz(); // attach to global div $(g.gDiv).prepend(g.cRsz); }, /** * Initialize column reordering feature. */ initColReorder: function () { g.cCpy = document.createElement('div'); // column copy, to store copy of dragged column header g.cPointer = document.createElement('div'); // column pointer, used when reordering column // adjust g.cCpy g.cCpy.className = 'cCpy'; $(g.cCpy).hide(); // adjust g.cPointer g.cPointer.className = 'cPointer'; $(g.cPointer).css('visibility', 'hidden'); // set visibility to hidden instead of calling hide() to force browsers to cache the image in cPointer class // assign column reordering hint g.reorderHint = PMA_messages.strColOrderHint; // get data columns in the first row of the table var $firstRowCols = $(g.t).find('tr:first th.draggable'); // initialize column order $col_order = $(g.o).find('.col_order'); // check if column order is passed from PHP if ($col_order.length > 0) { g.colOrder = $col_order.val().split(','); for (var i = 0; i < g.colOrder.length; i++) { g.colOrder[i] = parseInt(g.colOrder[i], 10); } } else { g.colOrder = []; for (var i = 0; i < $firstRowCols.length; i++) { g.colOrder.push(i); } } // register events $(g.t).find('th.draggable') .mousedown(function (e) { $(g.o).addClass("turnOffSelect"); if (g.visibleHeadersCount > 1) { g.dragStartReorder(e, this); } }) .mouseenter(function () { if (g.visibleHeadersCount > 1) { $(this).css('cursor', 'move'); } else { $(this).css('cursor', 'inherit'); } }) .mouseleave(function () { g.showReorderHint = false; $(this).tooltip("option", { content: g.updateHint() }); }) .dblclick(function (e) { e.preventDefault(); $("
") .prop("title", PMA_messages.strColNameCopyTitle) .addClass("modal-copy") .text(PMA_messages.strColNameCopyText) .append( $("") .prop("readonly", true) .val($(this).data("column")) ) .dialog({ resizable: false, modal: true }) .find("input").focus().select(); }); $(g.t).find('th.draggable a') .dblclick(function (e) { e.stopPropagation(); }); // restore column order when the restore button is clicked $(g.o).find('div.restore_column').click(function () { g.restoreColOrder(); }); // attach to global div $(g.gDiv).append(g.cPointer); $(g.gDiv).append(g.cCpy); // prevent default "dragstart" event when dragging a link $(g.t).find('th a').bind('dragstart', function () { return false; }); // refresh the restore column button state g.refreshRestoreButton(); }, /** * Initialize column visibility feature. */ initColVisib: function () { g.cDrop = document.createElement('div'); // column drop-down arrows g.cList = document.createElement('div'); // column visibility list // adjust g.cDrop g.cDrop.className = 'cDrop'; // adjust g.cList g.cList.className = 'cList'; $(g.cList).hide(); // assign column visibility related hints g.showAllColText = PMA_messages.strShowAllCol; // get data columns in the first row of the table var $firstRowCols = $(g.t).find('tr:first th.draggable'); var i; // initialize column visibility var $col_visib = $(g.o).find('.col_visib'); // check if column visibility is passed from PHP if ($col_visib.length > 0) { g.colVisib = $col_visib.val().split(','); for (i = 0; i < g.colVisib.length; i++) { g.colVisib[i] = parseInt(g.colVisib[i], 10); } } else { g.colVisib = []; for (i = 0; i < $firstRowCols.length; i++) { g.colVisib.push(1); } } // make sure we have more than one column if ($firstRowCols.length > 1) { var $colVisibTh = $(g.t).find('th:not(.draggable)'); PMA_tooltip( $colVisibTh, 'th', PMA_messages.strColVisibHint ); // create column visibility drop-down arrow(s) $colVisibTh.each(function () { var $th = $(this); var cd = document.createElement('div'); // column drop-down arrow var pos = $th.position(); $(cd).addClass('coldrop') .click(function () { if (g.cList.style.display == 'none') { g.showColList(this); } else { g.hideColList(); } }); $(g.cDrop).append(cd); }); // add column visibility control g.cList.innerHTML = '
'; var $listDiv = $(g.cList).find('div'); var tempClick = function () { if (g.toggleCol($(this).index())) { g.afterToggleCol(); } }; for (i = 0; i < $firstRowCols.length; i++) { var currHeader = $firstRowCols[i]; var listElmt = document.createElement('div'); $(listElmt).text($(currHeader).text()) .prepend(''); $listDiv.append(listElmt); // add event on click $(listElmt).click(tempClick); } // add "show all column" button var showAll = document.createElement('div'); $(showAll).addClass('showAllColBtn') .text(g.showAllColText); $(g.cList).append(showAll); $(showAll).click(function () { g.showAllColumns(); }); // prepend "show all column" button at top if the list is too long if ($firstRowCols.length > 10) { var clone = showAll.cloneNode(true); $(g.cList).prepend(clone); $(clone).click(function () { g.showAllColumns(); }); } } // hide column visibility list if we move outside the list $(g.t).find('td, th.draggable').mouseenter(function () { g.hideColList(); }); // attach to global div $(g.gDiv).append(g.cDrop); $(g.gDiv).append(g.cList); // some adjustment g.reposDrop(); }, /** * Move currently Editing Cell to Up */ moveUp: function(e) { e.preventDefault(); var $this_field = $(g.currentEditCell); var field_name = getFieldName($(g.t), $this_field); var where_clause = $this_field.parents('tr').first().find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } where_clause = PMA_urldecode(where_clause); var found = false; var $found_row; var $prev_row; var j = 0; $this_field.parents('tr').first().parents('tbody').children().each(function(){ if (PMA_urldecode($(this).find('.where_clause').val()) == where_clause) { found = true; $found_row = $(this); } if (!found) { $prev_row = $(this); } }); var new_cell; if (found && $prev_row) { $prev_row.children('td').each(function(){ if (getFieldName($(g.t), $(this)) == field_name) { new_cell = this; } }); } if (new_cell) { g.hideEditCell(false, false, false, {move : true, cell : new_cell}); } }, /** * Move currently Editing Cell to Down */ moveDown: function(e) { e.preventDefault(); var $this_field = $(g.currentEditCell); var field_name = getFieldName($(g.t), $this_field); var where_clause = $this_field.parents('tr').first().find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } where_clause = PMA_urldecode(where_clause); var found = false; var $found_row; var $next_row; var j = 0; var next_row_found = false; $this_field.parents('tr').first().parents('tbody').children().each(function(){ if (PMA_urldecode($(this).find('.where_clause').val()) == where_clause) { found = true; $found_row = $(this); } if (found) { if (j >= 1 && ! next_row_found) { $next_row = $(this); next_row_found = true; } else { j++; } } }); var new_cell; if (found && $next_row) { $next_row.children('td').each(function(){ if (getFieldName($(g.t), $(this)) == field_name) { new_cell = this; } }); } if (new_cell) { g.hideEditCell(false, false, false, {move : true, cell : new_cell}); } }, /** * Move currently Editing Cell to Left */ moveLeft: function(e) { e.preventDefault(); var $this_field = $(g.currentEditCell); var field_name = getFieldName($(g.t), $this_field); var where_clause = $this_field.parents('tr').first().find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } where_clause = PMA_urldecode(where_clause); var found = false; var $found_row; var j = 0; $this_field.parents('tr').first().parents('tbody').children().each(function(){ if (PMA_urldecode($(this).find('.where_clause').val()) == where_clause) { found = true; $found_row = $(this); } }); var left_cell; var cell_found = false; if (found) { $found_row.children('td.grid_edit').each(function(){ if (getFieldName($(g.t), $(this)) === field_name) { cell_found = true; } if (!cell_found) { left_cell = this; } }); } if (left_cell) { g.hideEditCell(false, false, false, {move : true, cell : left_cell}); } }, /** * Move currently Editing Cell to Right */ moveRight: function(e) { e.preventDefault(); var $this_field = $(g.currentEditCell); var field_name = getFieldName($(g.t), $this_field); var where_clause = $this_field.parents('tr').first().find('.where_clause').val(); if (typeof where_clause === 'undefined') { where_clause = ''; } where_clause = PMA_urldecode(where_clause); var found = false; var $found_row; var j = 0; $this_field.parents('tr').first().parents('tbody').children().each(function(){ if (PMA_urldecode($(this).find('.where_clause').val()) == where_clause) { found = true; $found_row = $(this); } }); var right_cell; var cell_found = false; var next_cell_found = false; if (found) { $found_row.children('td.grid_edit').each(function(){ if (getFieldName($(g.t), $(this)) === field_name) { cell_found = true; } if (cell_found) { if (j >= 1 && ! next_cell_found) { right_cell = this; next_cell_found = true; } else { j++; } } }); } if (right_cell) { g.hideEditCell(false, false, false, {move : true, cell : right_cell}); } }, /** * Initialize grid editing feature. */ initGridEdit: function () { function startGridEditing(e, cell) { if (g.isCellEditActive) { g.saveOrPostEditedCell(); } else { g.showEditCell(cell); } e.stopPropagation(); } function handleCtrlNavigation(e) { if ((e.ctrlKey && e.which == 38 ) || (e.altKey && e.which == 38)) { g.moveUp(e); } else if ((e.ctrlKey && e.which == 40) || (e.altKey && e.which == 40)) { g.moveDown(e); } else if ((e.ctrlKey && e.which == 37 ) || (e.altKey && e.which == 37)) { g.moveLeft(e); } else if ((e.ctrlKey && e.which == 39) || (e.altKey && e.which == 39)) { g.moveRight(e); } } // create cell edit wrapper element g.cEditStd = document.createElement('div'); g.cEdit = g.cEditStd; g.cEditTextarea = document.createElement('div'); // adjust g.cEditStd g.cEditStd.className = 'cEdit'; $(g.cEditStd).html('
'); $(g.cEditStd).hide(); // adjust g.cEdit g.cEditTextarea.className = 'cEdit'; $(g.cEditTextarea).html('
'); $(g.cEditTextarea).hide(); // assign cell editing hint g.cellEditHint = PMA_messages.strCellEditHint; g.saveCellWarning = PMA_messages.strSaveCellWarning; g.alertNonUnique = PMA_messages.strAlertNonUnique; g.gotoLinkText = PMA_messages.strGoToLink; // initialize cell editing configuration g.saveCellsAtOnce = $(g.o).find('.save_cells_at_once').val(); g.maxTruncatedLen = PMA_commonParams.get('LimitChars'); // register events $(g.t).find('td.data.click1') .click(function (e) { startGridEditing(e, this); // prevent default action when clicking on "link" in a table if ($(e.target).is('.grid_edit a')) { e.preventDefault(); } }); $(g.t).find('td.data.click2') .click(function (e) { var $cell = $(this); // In the case of relational link, We want single click on the link // to goto the link and double click to start grid-editing. var $link = $(e.target); if ($link.is('.grid_edit.relation a')) { e.preventDefault(); // get the click count and increase var clicks = $cell.data('clicks'); clicks = (typeof clicks === 'undefined') ? 1 : clicks + 1; if (clicks == 1) { // if there are no previous clicks, // start the single click timer var timer = setTimeout(function () { // temporarily remove ajax class so the page loader will not handle it, // submit and then add it back $link.removeClass('ajax'); AJAX.requestHandler.call($link[0]); $link.addClass('ajax'); $cell.data('clicks', 0); }, 700); $cell.data('clicks', clicks); $cell.data('timer', timer); } else { // this is a double click, cancel the single click timer // and make the click count 0 clearTimeout($cell.data('timer')); $cell.data('clicks', 0); // start grid-editing startGridEditing(e, this); } } }) .dblclick(function (e) { if ($(e.target).is('.grid_edit a')) { e.preventDefault(); } else { startGridEditing(e, this); } }); $(g.cEditStd).on('keydown', 'input.edit_box, select', handleCtrlNavigation); $(g.cEditStd).find('.edit_box').focus(function () { g.showEditArea(); }); $(g.cEditStd).on('keydown', '.edit_box, select', function (e) { if (e.which == 13) { // post on pressing "Enter" e.preventDefault(); g.saveOrPostEditedCell(); } }); $(g.cEditStd).keydown(function (e) { if (!g.isEditCellTextEditable) { // prevent text editing e.preventDefault(); } }); $(g.cEditTextarea).on('keydown', 'textarea.edit_box, select', handleCtrlNavigation); $(g.cEditTextarea).find('.edit_box').focus(function () { g.showEditArea(); }); $(g.cEditTextarea).on('keydown', '.edit_box, select', function (e) { if (e.which == 13 && !e.shiftKey) { // post on pressing "Enter" e.preventDefault(); g.saveOrPostEditedCell(); } }); $(g.cEditTextarea).keydown(function (e) { if (!g.isEditCellTextEditable) { // prevent text editing e.preventDefault(); } }); $('html').click(function (e) { // hide edit cell if the click is not fromDat edit area if ($(e.target).parents().index($(g.cEdit)) == -1 && !$(e.target).parents('.ui-datepicker-header').length && !$('.browse_foreign_modal.ui-dialog:visible').length ) { g.hideEditCell(); } }).keydown(function (e) { if (e.which == 27 && g.isCellEditActive) { // cancel on pressing "Esc" g.hideEditCell(true); } }); $(g.o).find('div.save_edited').click(function () { g.hideEditCell(); g.postEditedCell(); }); $(window).bind('beforeunload', function () { if (g.isCellEdited) { return g.saveCellWarning; } }); // attach to global div $(g.gDiv).append(g.cEditStd); $(g.gDiv).append(g.cEditTextarea); // add hint for grid editing feature when hovering "Edit" link in each table row if (PMA_messages.strGridEditFeatureHint !== undefined) { PMA_tooltip( $(g.t).find('.edit_row_anchor a'), 'a', PMA_messages.strGridEditFeatureHint ); } } }; /****************** * Initialize grid ******************/ // wrap all truncated data cells with span indicating the original length // todo update the original length after a grid edit $(t).find('td.data.truncated:not(:has(span))') .wrapInner(function() { return ''; }); // wrap remaining cells, except actions cell, with span $(t).find('th, td:not(:has(span))') .wrapInner(''); // create grid elements g.gDiv = document.createElement('div'); // create global div // initialize the table variable g.t = t; // enclosing .sqlqueryresults div g.o = $(t).parents('.sqlqueryresults'); // get data columns in the first row of the table var $firstRowCols = $(t).find('tr:first th.draggable'); // initialize visible headers count g.visibleHeadersCount = $firstRowCols.filter(':visible').length; // assign first column (actions) span if (! $(t).find('tr:first th:first').hasClass('draggable')) { // action header exist g.actionSpan = $(t).find('tr:first th:first').prop('colspan'); } else { g.actionSpan = 0; } // assign table create time // table_create_time will only available if we are in "Browse" tab g.tableCreateTime = $(g.o).find('.table_create_time').val(); // assign the hints g.sortHint = PMA_messages.strSortHint; g.strMultiSortHint = PMA_messages.strMultiSortHint; g.markHint = PMA_messages.strColMarkHint; g.copyHint = PMA_messages.strColNameCopyHint; // assign common hidden inputs var $common_hidden_inputs = $(g.o).find('div.common_hidden_inputs'); g.token = $common_hidden_inputs.find('input[name=token]').val(); g.server = $common_hidden_inputs.find('input[name=server]').val(); g.db = $common_hidden_inputs.find('input[name=db]').val(); g.table = $common_hidden_inputs.find('input[name=table]').val(); // add table class $(t).addClass('pma_table'); // add relative position to global div so that resize handlers are correctly positioned $(g.gDiv).css('position', 'relative'); // link the global div $(t).before(g.gDiv); $(g.gDiv).append(t); // FEATURES enableResize = enableResize === undefined ? true : enableResize; enableReorder = enableReorder === undefined ? true : enableReorder; enableVisib = enableVisib === undefined ? true : enableVisib; enableGridEdit = enableGridEdit === undefined ? true : enableGridEdit; if (enableResize) { g.initColResize(); } if (enableReorder && $(g.o).find('table.navigation').length > 0) // disable reordering for result from EXPLAIN or SHOW syntax, which do not have a table navigation panel { g.initColReorder(); } if (enableVisib) { g.initColVisib(); } if (enableGridEdit && $(t).is('.ajax')) // make sure we have the ajax class { g.initGridEdit(); } // create tooltip for each with draggable class PMA_tooltip( $(t).find("th.draggable"), 'th', g.updateHint() ); // register events for hint tooltip (anchors inside draggable th) $(t).find('th.draggable a') .mouseenter(function () { g.showSortHint = true; g.showMultiSortHint = true; $(t).find("th.draggable").tooltip("option", { content: g.updateHint() }); }) .mouseleave(function () { g.showSortHint = false; g.showMultiSortHint = false; $(t).find("th.draggable").tooltip("option", { content: g.updateHint() }); }); // register events for dragging-related feature if (enableResize || enableReorder) { $(document).mousemove(function (e) { g.dragMove(e); }); $(document).mouseup(function (e) { $(g.o).removeClass("turnOffSelect"); g.dragEnd(e); }); } // some adjustment $(t).removeClass('data'); $(g.gDiv).addClass('data'); } /** * jQuery plugin to cancel selection in HTML code. */ (function ($) { $.fn.noSelect = function (p) { //no select plugin by Paulo P.Marinas var prevent = (p === null) ? true : p; var is_msie = navigator.userAgent.indexOf('MSIE') > -1 || !!window.navigator.userAgent.match(/Trident.*rv\:11\./); var is_firefox = navigator.userAgent.indexOf('Firefox') > -1; var is_safari = navigator.userAgent.indexOf("Safari") > -1; var is_opera = navigator.userAgent.indexOf("Presto") > -1; if (prevent) { return this.each(function () { if (is_msie || is_safari) { $(this).bind('selectstart', function () { return false; }); } else if (is_firefox) { $(this).css('MozUserSelect', 'none'); $('body').trigger('focus'); } else if (is_opera) { $(this).bind('mousedown', function () { return false; }); } else { $(this).attr('unselectable', 'on'); } }); } else { return this.each(function () { if (is_msie || is_safari) { $(this).unbind('selectstart'); } else if (is_firefox) { $(this).css('MozUserSelect', 'inherit'); } else if (is_opera) { $(this).unbind('mousedown'); } else { $(this).removeAttr('unselectable'); } }); } }; //end noSelect })(jQuery);

Login or Register to edit or fork this paste. It's free.