The branch, master has been updated via a84fd8e151225beb59f4c4dd480ddd847b1bc4b2 (commit) via e3d069f6536e90dd743fb85b0ee5003efea5d9ca (commit) via ba5598a190ff39225ef3d7527eecc54dfdf50760 (commit) via e65fc63e71496e338e549e14b1c3a958566c1277 (commit) from 341b75a99013570eafde267e1f04ae41bb28365b (commit)
- Log ----------------------------------------------------------------- commit a84fd8e151225beb59f4c4dd480ddd847b1bc4b2 Merge: 341b75a e3d069f Author: Marc Delisle marc@infomarc.info Date: Thu Aug 11 07:57:30 2011 -0400
Merge commit 'e3d069f6536e90dd743fb85b0ee5003efea5d9ca'
commit e3d069f6536e90dd743fb85b0ee5003efea5d9ca Author: Aris Feryanto aris_feryanto@yahoo.com Date: Thu Aug 11 14:08:37 2011 +0800
Add more comments in makegrid.js
commit ba5598a190ff39225ef3d7527eecc54dfdf50760 Author: Aris Feryanto aris_feryanto@yahoo.com Date: Thu Aug 11 13:35:51 2011 +0800
Refactor makegrid.js
commit e65fc63e71496e338e549e14b1c3a958566c1277 Author: Aris Feryanto aris_feryanto@yahoo.com Date: Wed Aug 10 22:49:23 2011 +0800
Incomplete inline edit feature removal
-----------------------------------------------------------------------
Summary of changes: js/makegrid.js | 2998 +++++++++++++++++++++++++++++--------------------------- js/sql.js | 11 +- sql.php | 126 +--- 3 files changed, 1567 insertions(+), 1568 deletions(-)
diff --git a/js/makegrid.js b/js/makegrid.js index 91834ac..b8ca5fa 100644 --- a/js/makegrid.js +++ b/js/makegrid.js @@ -1,828 +1,856 @@ -(function ($) { - $.grid = function(t) { - // prepare the grid - var g = { - // constant - minColWidth: 15, - - // variables, assigned with default value, changed later - actionSpan: 5, - colOrder: new Array(), // array of column order - colVisib: new Array(), // array of column visibility - tableCreateTime: null, // table creation time, only available in "Browse tab" - qtip: null, // qtip API - reorderHint: '', // string, hint for column reordering - sortHint: '', // string, hint for column sorting - markHint: '', // string, hint for column marking - colVisibHint: '', // string, hint for column visibility drop-down - showReorderHint: false, - showSortHint: false, - showMarkHint: false, - showColVisibHint: false, - showAllColText: '', // string, text for "show all" button under column visibility list - visibleHeadersCount: 0, // number of visible data headers - isCellEditActive: false, // true if current focus is in edit cell - isEditCellTextEditable: false, // true if current edit cell is editable in the text input box (not textarea) - currentEditCell: null, // reference to <td> that currently being edited - inEditMode: false, // true if grid is in edit mode - cellEditHint: '', // hint shown when doing grid edit - gotoLinkText: 'Go to link', // "Go to link" text - wasEditedCellNull: false, // true if last value of the edited cell was NULL - maxTruncatedLen: 0, // number of characters that can be displayed in a cell - saveCellsAtOnce: false, // $cfg[saveCellsAtOnce] - isCellEdited: false, // true if at least one cell has been edited - saveCellWarning: '', // string, warning text when user want to leave a page with unsaved edited data - lastXHR : null, // last XHR object used in AJAX request - 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 - alertNonUnique: '', // string, alert shown when saving edited nonunique table +/** + * Create advanced table (resize, reorder, and show/hide columns; and also grid editing). + * This function is designed mainly for table DOM generated from browsing a table in the database. + * For using this function in other table DOM, you may need to: + * - add "draggable" class in the table header <th>, in order to make it resizable, sortable or hidable + * - have at least one non-"draggable" header in the table DOM for placing column visibility drop-down arrow + * - pass the value "false" for the parameter "enableGridEdit" + * - adjust other parameter value, to select which features that will be enabled + * + * @param t the table DOM element + * @param enableResize Optional, if false, column resizing feature will be disabled + * @param enableReorder Optional, if false, column reordering feature will be disabled + * @param enableVisib Optional, if false, show/hide column feature will be disabled + * @param enableGridEdit Optional, if false, grid editing feature will be disabled + */ +function PMA_makegrid(t, enableResize, enableReorder, enableVisib, enableGridEdit) { + var g = { + /*********** + * Constant + ***********/ + minColWidth: 15, + + + /*********** + * Variables, assigned with default value, changed later + ***********/ + actionSpan: 5, // number of colspan in Actions header in a table + tableCreateTime: null, // table creation time, used for saving column order and visibility to server, only available in "Browse tab" + + // Column reordering variables + colOrder: new Array(), // array of column order + + // Column visibility variables + colVisib: new Array(), // array of column visibility + showAllColText: '', // string, text for "show all" button under column visibility list + visibleHeadersCount: 0, // number of visible data headers + + // Table hint variables + qtip: null, // qtip API + reorderHint: '', // string, hint for column reordering + sortHint: '', // string, hint for column sorting + markHint: '', // string, hint for column marking + colVisibHint: '', // string, hint for column visibility drop-down + showReorderHint: false, + showSortHint: false, + showMarkHint: false, + showColVisibHint: false, + + // Grid editing + isCellEditActive: false, // true if current focus is in edit cell + isEditCellTextEditable: false, // true if current edit cell is editable in the text input box (not textarea) + currentEditCell: null, // reference to <td> that currently being edited + cellEditHint: '', // hint shown when doing grid edit + gotoLinkText: '', // "Go to link" text + wasEditedCellNull: false, // true if last value of the edited cell was NULL + maxTruncatedLen: 0, // number of characters that can be displayed in a cell + saveCellsAtOnce: false, // $cfg[saveCellsAtOnce] + isCellEdited: false, // true if at least one cell has been edited + saveCellWarning: '', // string, warning text when user want to leave a page with unsaved edited data + lastXHR : null, // last XHR object used in AJAX request + 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 + alertNonUnique: '', // string, alert shown when saving edited nonunique table + + // Common hidden inputs + token: null, + server: null, + db: null, + table: null, + + + /************ + * Functions + ************/ + + /** + * Start to resize column. Called when clicking on column separator. + * + * @param e event + * @param obj dragged div object + */ + dragStartRsz: function(e, obj) { + var n = $(g.cRsz).find('div').index(obj); // get the index of separator (i.e., column index) + g.colRsz = { + x0: e.pageX, + n: n, + obj: obj, + objLeft: $(obj).position().left, + objWidth: $(g.t).find('th.draggable:visible:eq(' + n + ') span').outerWidth() + }; + $('body').css('cursor', 'col-resize'); + $('body').noSelect(); + if (g.isCellEditActive) { + g.hideEditCell(); + } + }, + + /** + * Start to reorder column. Called when clicking on table header. + * + * @param e event + * @param obj table header object + */ + dragStartReorder: function(e, obj) { + // prepare the cCpy (column copy) and cPointer (column pointer) from the dragged column + $(g.cCpy).text($(obj).text()); + var objPos = $(obj).position(); + $(g.cCpy).css({ + top: objPos.top + 20, + left: objPos.left, + height: $(obj).height(), + width: $(obj).width() + }); + $(g.cPointer).css({ + top: objPos.top + });
- // common hidden inputs - token: null, - server: null, - db: null, - table: null, + // get the column index, zero-based + var n = g.getHeaderIdx(obj);
- // functions - dragStartRsz: function(e, obj) { // start column resize - var n = $(this.cRsz).find('div').index(obj); - this.colRsz = { - x0: e.pageX, - n: n, - obj: obj, - objLeft: $(obj).position().left, - objWidth: $(this.t).find('th.draggable:visible:eq(' + n + ') span').outerWidth() - }; - $('body').css('cursor', 'col-resize'); - $('body').noSelect(); - if (g.isCellEditActive) { - g.hideEditCell(); - } - }, - - dragStartMove: function(e, obj) { // start column move - // prepare the cCpy and cPointer from the dragged column - $(this.cCpy).text($(obj).text()); - var objPos = $(obj).position(); - $(this.cCpy).css({ - top: objPos.top + 20, - left: objPos.left, - height: $(obj).height(), - width: $(obj).width() - }); - $(this.cPointer).css({ - top: objPos.top - }); - - // get the column index, zero-based - var n = this.getHeaderIdx(obj); - - this.colMov = { - x0: e.pageX, - y0: e.pageY, - n: n, - newn: n, - obj: obj, - objTop: objPos.top, - objLeft: objPos.left - }; - this.qtip.hide(); - $('body').css('cursor', 'move'); - $('body').noSelect(); - if (g.isCellEditActive) { - g.hideEditCell(); - } - }, - - dragMove: function(e) { - if (this.colRsz) { - var dx = e.pageX - this.colRsz.x0; - if (this.colRsz.objWidth + dx > this.minColWidth) { - $(this.colRsz.obj).css('left', this.colRsz.objLeft + dx + 'px'); - } - } else if (this.colMov) { - // dragged column animation - var dx = e.pageX - this.colMov.x0; - $(this.cCpy) - .css('left', this.colMov.objLeft + dx) - .show(); - - // pointer animation - var hoveredCol = this.getHoveredCol(e); - if (hoveredCol) { - var newn = this.getHeaderIdx(hoveredCol); - this.colMov.newn = newn; - if (newn != this.colMov.n) { - // show the column pointer in the right place - var colPos = $(hoveredCol).position(); - var newleft = newn < this.colMov.n ? - colPos.left : - colPos.left + $(hoveredCol).outerWidth(); - $(this.cPointer) - .css({ - left: newleft, - visibility: 'visible' - }); - } else { - // no movement to other column, hide the column pointer - $(this.cPointer).css('visibility', 'hidden'); - } - } + g.colReorder = { + x0: e.pageX, + y0: e.pageY, + n: n, + newn: n, + obj: obj, + objTop: objPos.top, + objLeft: objPos.left + }; + g.hideHint(); + $('body').css('cursor', 'move'); + $('body').noSelect(); + if (g.isCellEditActive) { + g.hideEditCell(); + } + }, + + /** + * Handle mousemove event when dragging. + * + * @param e event + */ + dragMove: function(e) { + if (g.colRsz) { + var dx = e.pageX - g.colRsz.x0; + if (g.colRsz.objWidth + dx > g.minColWidth) { + $(g.colRsz.obj).css('left', g.colRsz.objLeft + dx + 'px'); } - }, - - dragEnd: function(e) { - if (this.colRsz) { - var dx = e.pageX - this.colRsz.x0; - var nw = this.colRsz.objWidth + dx; - if (nw < this.minColWidth) { - nw = this.minColWidth; - } - var n = this.colRsz.n; - // do the resizing - this.resize(n, nw); - - $('body').css('cursor', 'default'); - this.reposRsz(); - this.reposDrop(); - this.colRsz = false; - } else if (this.colMov) { - // shift columns - if (this.colMov.newn != this.colMov.n) { - this.shiftCol(this.colMov.n, this.colMov.newn); - // assign new position - var objPos = $(this.colMov.obj).position(); - this.colMov.objTop = objPos.top; - this.colMov.objLeft = objPos.left; - this.colMov.n = this.colMov.newn; - // send request to server to remember the column order - if (this.tableCreateTime) { - this.sendColPrefs(); - } - this.refreshRestoreButton(); + } else if (g.colReorder) { + // dragged column animation + var dx = e.pageX - g.colReorder.x0; + $(g.cCpy) + .css('left', g.colReorder.objLeft + dx) + .show(); + + // pointer animation + var hoveredCol = g.getHoveredCol(e); + if (hoveredCol) { + var newn = g.getHeaderIdx(hoveredCol); + g.colReorder.newn = newn; + if (newn != g.colReorder.n) { + // show the column pointer in the right place + var colPos = $(hoveredCol).position(); + var newleft = newn < g.colReorder.n ? + colPos.left : + colPos.left + $(hoveredCol).outerWidth(); + $(g.cPointer) + .css({ + left: newleft, + visibility: 'visible' + }); + } else { + // no movement to other column, hide the column pointer + $(g.cPointer).css('visibility', 'hidden'); } - - // animate new column position - $(this.cCpy).stop(true, true) - .animate({ - top: g.colMov.objTop, - left: g.colMov.objLeft - }, 'fast') - .fadeOut(); - $(this.cPointer).css('visibility', 'hidden'); - - this.colMov = false; } - $('body').noSelect(false); - }, - - /** - * Resize column n to new width "nw" - */ - resize: function(n, nw) { - $(this.t).find('tr').each(function() { - $(this).find('th.draggable:visible:eq(' + n + ') span,' + - 'td:visible:eq(' + (g.actionSpan + n) + ') span') - .css('width', nw); - }); - }, - - /** - * Reposition column resize bars. - */ - reposRsz: function() { - $(this.cRsz).find('div').hide(); - var $firstRowCols = $(this.t).find('tr:first th.draggable:visible'); - for (var n = 0; n < $firstRowCols.length; n++) { - $this = $($firstRowCols[n]); - $cb = $(g.cRsz).find('div:eq(' + n + ')'); // column border - $cb.css('left', $this.position().left + $this.outerWidth(true)) - .show(); + } + }, + + /** + * Stop the dragging action. + * + * @param e event + */ + dragEnd: function(e) { + if (g.colRsz) { + var dx = e.pageX - g.colRsz.x0; + var nw = g.colRsz.objWidth + dx; + if (nw < g.minColWidth) { + nw = g.minColWidth; } - $(this.cRsz).css('height', $(this.t).height()); - }, - - /** - * Shift column from index oldn to newn. - */ - shiftCol: function(oldn, newn) { - $(this.t).find('tr').each(function() { - if (newn < oldn) { - $(this).find('th.draggable:eq(' + newn + '),' + - 'td:eq(' + (g.actionSpan + newn) + ')') - .before($(this).find('th.draggable:eq(' + oldn + '),' + - 'td:eq(' + (g.actionSpan + oldn) + ')')); - } else { - $(this).find('th.draggable:eq(' + newn + '),' + - 'td:eq(' + (g.actionSpan + newn) + ')') - .after($(this).find('th.draggable:eq(' + oldn + '),' + - 'td:eq(' + (g.actionSpan + oldn) + ')')); + var n = g.colRsz.n; + // do the resizing + g.resize(n, nw); + + g.reposRsz(); + g.reposDrop(); + g.colRsz = false; + } else if (g.colReorder) { + // shift columns + if (g.colReorder.newn != g.colReorder.n) { + g.shiftCol(g.colReorder.n, g.colReorder.newn); + // assign new position + var objPos = $(g.colReorder.obj).position(); + g.colReorder.objTop = objPos.top; + g.colReorder.objLeft = objPos.left; + g.colReorder.n = g.colReorder.newn; + // send request to server to remember the column order + if (g.tableCreateTime) { + g.sendColPrefs(); } - }); - // reposition the column resize bars - this.reposRsz(); - - // adjust the column visibility list + g.refreshRestoreButton(); + } + + // animate new column position + $(g.cCpy).stop(true, true) + .animate({ + top: g.colReorder.objTop, + left: g.colReorder.objLeft + }, 'fast') + .fadeOut(); + $(g.cPointer).css('visibility', 'hidden'); + + g.colReorder = false; + } + $('body').css('cursor', 'inherit'); + $('body').noSelect(false); + }, + + /** + * Resize column n to new width "nw" + * + * @param n zero-based column index + * @param nw new width of the column in pixel + */ + resize: function(n, nw) { + $(g.t).find('tr').each(function() { + $(this).find('th.draggable:visible:eq(' + n + ') span,' + + 'td:visible:eq(' + (g.actionSpan + n) + ') span') + .css('width', nw); + }); + }, + + /** + * Reposition column resize bars. + */ + reposRsz: function() { + $(g.cRsz).find('div').hide(); + var $firstRowCols = $(g.t).find('tr:first th.draggable:visible'); + for (var n = 0; n < $firstRowCols.length; n++) { + var $col = $($firstRowCols[n]); + $cb = $(g.cRsz).find('div:eq(' + n + ')'); // column border + $cb.css('left', $col.position().left + $col.outerWidth(true)) + .show(); + } + $(g.cRsz).css('height', $(g.t).height()); + }, + + /** + * Shift column from index oldn to newn. + * + * @param oldn old zero-based column index + * @param newn new zero-based column index + */ + shiftCol: function(oldn, newn) { + $(g.t).find('tr').each(function() { if (newn < oldn) { - $(g.cList).find('.lDiv div:eq(' + newn + ')') - .before($(g.cList).find('.lDiv div:eq(' + oldn + ')')); + $(this).find('th.draggable:eq(' + newn + '),' + + 'td:eq(' + (g.actionSpan + newn) + ')') + .before($(this).find('th.draggable:eq(' + oldn + '),' + + 'td:eq(' + (g.actionSpan + oldn) + ')')); } else { - $(g.cList).find('.lDiv div:eq(' + newn + ')') - .after($(g.cList).find('.lDiv div:eq(' + oldn + ')')); + $(this).find('th.draggable:eq(' + newn + '),' + + 'td:eq(' + (g.actionSpan + newn) + ')') + .after($(this).find('th.draggable:eq(' + oldn + '),' + + 'td:eq(' + (g.actionSpan + oldn) + ')')); } - // adjust the colOrder - var tmp = this.colOrder[oldn]; - this.colOrder.splice(oldn, 1); - this.colOrder.splice(newn, 0, tmp); - // adjust the colVisib - var tmp = this.colVisib[oldn]; - this.colVisib.splice(oldn, 1); - this.colVisib.splice(newn, 0, tmp); - }, - - /** - * Find currently hovered table column's header (excluding actions column). - * @return the hovered column's th object or undefined if no hovered column found. - */ - getHoveredCol: function(e) { - var hoveredCol; - $headers = $(this.t).find('th.draggable:visible'); - $headers.each(function() { - var left = $(this).offset().left; - var right = left + $(this).outerWidth(); - if (left <= e.pageX && e.pageX <= right) { - hoveredCol = this; - } - }); - return hoveredCol; - }, - - /** - * Get a zero-based index from a <th class="draggable"> tag in a table. - */ - getHeaderIdx: function(obj) { - return $(obj).parents('tr').find('th.draggable').index(obj); - }, - - /** - * Reposition the table back to normal order. - */ - restoreColOrder: function() { - // use insertion sort, since we already have shiftCol function - for (var i = 1; i < this.colOrder.length; i++) { - var x = this.colOrder[i]; - var j = i - 1; - while (j >= 0 && x < this.colOrder[j]) { - j--; - } - if (j != i - 1) { - this.shiftCol(i, j + 1); - } + }); + // reposition the column resize bars + g.reposRsz(); + + // adjust the column visibility list + if (newn < oldn) { + $(g.cList).find('.lDiv div:eq(' + newn + ')') + .before($(g.cList).find('.lDiv div:eq(' + oldn + ')')); + } else { + $(g.cList).find('.lDiv div:eq(' + newn + ')') + .after($(g.cList).find('.lDiv div:eq(' + oldn + ')')); + } + // adjust the colOrder + var tmp = g.colOrder[oldn]; + g.colOrder.splice(oldn, 1); + g.colOrder.splice(newn, 0, tmp); + // adjust the colVisib + if (g.colVisib.length > 0) { + var tmp = g.colVisib[oldn]; + g.colVisib.splice(oldn, 1); + g.colVisib.splice(newn, 0, tmp); + } + }, + + /** + * Find currently hovered table column's header (excluding actions column). + * + * @param e event + * @return the hovered column's th object or undefined if no hovered column found. + */ + getHoveredCol: function(e) { + var hoveredCol; + $headers = $(g.t).find('th.draggable:visible'); + $headers.each(function() { + var left = $(this).offset().left; + var right = left + $(this).outerWidth(); + if (left <= e.pageX && e.pageX <= right) { + hoveredCol = this; } - if (this.tableCreateTime) { - // send request to server to remember the column order - this.sendColPrefs(); + }); + return hoveredCol; + }, + + /** + * Get a zero-based index from a <th class="draggable"> tag in a table. + * + * @param obj table header <th> object + * @return zero-based index of the specified table header in the set of table headers (visible or not) + */ + getHeaderIdx: function(obj) { + return $(obj).parents('tr').find('th.draggable').index(obj); + }, + + /** + * Reposition the columns back to normal order. + */ + restoreColOrder: function() { + // use insertion sort, since we already have shiftCol function + for (var i = 1; i < g.colOrder.length; i++) { + var x = g.colOrder[i]; + var j = i - 1; + while (j >= 0 && x < g.colOrder[j]) { + j--; } - this.refreshRestoreButton(); - }, - - /** - * Send column preferences (column order and visibility) to the server. - */ - sendColPrefs: function() { - $.post('sql.php', { - ajax_request: true, - db: g.db, - table: g.table, - token: g.token, - server: g.server, - set_col_prefs: true, - col_order: this.colOrder.toString(), - col_visib: this.colVisib.toString(), - table_create_time: this.tableCreateTime - }); - }, - - /** - * Refresh restore button state. - * Make restore button disabled if the table is similar with initial state. - */ - refreshRestoreButton: function() { - // check if table state is as initial state - var isInitial = true; - for (var i = 0; i < this.colOrder.length; i++) { - if (this.colOrder[i] != i) { - isInitial = false; - break; - } + if (j != i - 1) { + g.shiftCol(i, j + 1); } - // check if only one visible column left - var isOneColumn = this.visibleHeadersCount == 1; - // enable or disable restore button - if (isInitial || isOneColumn) { - $('.restore_column').hide(); - } else { - $('.restore_column').show(); + } + if (g.tableCreateTime) { + // send request to server to remember the column order + g.sendColPrefs(); + } + g.refreshRestoreButton(); + }, + + /** + * Send column preferences (column order and visibility) to the server. + */ + sendColPrefs: function() { + var post_params = { + ajax_request: true, + db: g.db, + table: g.table, + token: g.token, + server: g.server, + set_col_prefs: true, + table_create_time: g.tableCreateTime + }; + if (g.colOrder.length > 0) { + $.extend(post_params, { col_order: g.colOrder.toString() }); + } + if (g.colVisib.length > 0) { + $.extend(post_params, { col_visib: g.colVisib.toString() }); + } + $.post('sql.php', post_params); + }, + + /** + * Refresh restore button state. + * Make restore button disabled if the table is similar with initial state. + */ + refreshRestoreButton: function() { + // check if table state is as initial state + var isInitial = true; + for (var i = 0; i < g.colOrder.length; i++) { + if (g.colOrder[i] != i) { + isInitial = false; + break; } - }, - - /** - * Update current hint using the boolean values (showReorderHint, showSortHint, etc.). - * It will hide the hint if all the boolean values is false. - */ - updateHint: function(e) { - if (!this.colRsz && !this.colMov) { // if not resizing or dragging - var text = ''; - if (this.showReorderHint && this.reorderHint) { - text += this.reorderHint; - } - if (this.showSortHint && this.sortHint) { - text += text.length > 0 ? '<br />' : ''; - text += this.sortHint; - } - if (this.showMarkHint && this.markHint && - !this.showSortHint // we do not show mark hint, when sort hint is shown - ) { - text += text.length > 0 ? '<br />' : ''; - text += this.markHint; - } - if (this.showColVisibHint && this.colVisibHint) { - text += text.length > 0 ? '<br />' : ''; - text += this.colVisibHint; - } - - // hide the hint if no text - this.qtip.disable(!text && e.type == 'mouseenter'); - - this.qtip.updateContent(text, false); - } else { - this.qtip.disable(true); + } + // check if only one visible column left + var isOneColumn = g.visibleHeadersCount == 1; + // enable or disable restore button + if (isInitial || isOneColumn) { + $('.restore_column').hide(); + } else { + $('.restore_column').show(); + } + }, + + /** + * Update current hint using the boolean values (showReorderHint, showSortHint, etc.). + * It will hide the hint if all the boolean values is false. + * + * @param e event + */ + updateHint: function(e) { + if (!g.colRsz && !g.colReorder) { // if not resizing or dragging + var text = ''; + if (g.showReorderHint && g.reorderHint) { + text += g.reorderHint; } - }, - - /** - * Toggle column's visibility. - * After calling this function and it returns true, afterToggleCol() must be called. - * - * @return boolean True if the column is toggled successfully. - */ - toggleCol: function(n) { - if (this.colVisib[n]) { - // can hide if more than one column is visible - if (this.visibleHeadersCount > 1) { - $(this.t).find('tr').each(function() { - $(this).find('th.draggable:eq(' + n + '),' + - 'td:eq(' + (g.actionSpan + n) + ')') - .hide(); - }); - this.colVisib[n] = 0; - $(this.cList).find('.lDiv div:eq(' + n + ') input').removeAttr('checked'); - } else { - // cannot hide, force the checkbox to stay checked - $(this.cList).find('.lDiv div:eq(' + n + ') input').attr('checked', 'checked'); - return false; - } - } else { // column n is not visible - $(this.t).find('tr').each(function() { + if (g.showSortHint && g.sortHint) { + text += text.length > 0 ? '<br />' : ''; + text += g.sortHint; + } + if (g.showMarkHint && g.markHint && + !g.showSortHint // we do not show mark hint, when sort hint is shown + ) { + text += text.length > 0 ? '<br />' : ''; + text += g.markHint; + } + if (g.showColVisibHint && g.colVisibHint) { + text += text.length > 0 ? '<br />' : ''; + text += g.colVisibHint; + } + + // hide the hint if no text and the event is mouseenter + g.qtip.disable(!text && e.type == 'mouseenter'); + + g.qtip.updateContent(text, false); + } else { + g.hideHint(); + } + }, + + hideHint: function() { + if (g.qtip) { + g.qtip.hide(); + g.qtip.disable(true); + } + }, + + /** + * Toggle column's visibility. + * After calling this function and it returns true, afterToggleCol() must be called. + * + * @return boolean True if the column is toggled successfully. + */ + toggleCol: function(n) { + if (g.colVisib[n]) { + // can hide if more than one column is visible + if (g.visibleHeadersCount > 1) { + $(g.t).find('tr').each(function() { $(this).find('th.draggable:eq(' + n + '),' + 'td:eq(' + (g.actionSpan + n) + ')') - .show(); + .hide(); }); - this.colVisib[n] = 1; - $(this.cList).find('.lDiv div:eq(' + n + ') input').attr('checked', 'checked'); + g.colVisib[n] = 0; + $(g.cList).find('.lDiv div:eq(' + n + ') input').removeAttr('checked'); + } else { + // cannot hide, force the checkbox to stay checked + $(g.cList).find('.lDiv div:eq(' + n + ') input').attr('checked', 'checked'); + return false; } - return true; - }, - - /** - * This must be called after calling toggleCol() and the return value is true. - * - * This function is separated from toggleCol because, sometimes, we want to toggle - * some columns together at one time and do one adjustment after it, e.g. in showAllColumns(). - */ - afterToggleCol: function() { - // some adjustments after hiding column - this.reposRsz(); - this.reposDrop(); - this.sendColPrefs(); - - // check visible first row headers count - this.visibleHeadersCount = $(this.t).find('tr:first th.draggable:visible').length; - this.refreshRestoreButton(); - }, - - /** - * Show columns' visibility list. - */ - showColList: function(obj) { - // only show when not resizing or reordering - if (!this.colRsz && !this.colMov) { - var pos = $(obj).position(); - // check if the list position is too right - if (pos.left + $(this.cList).outerWidth(true) > $(document).width()) { - pos.left = $(document).width() - $(this.cList).outerWidth(true); - } - $(this.cList).css({ - left: pos.left, - top: pos.top + $(obj).outerHeight(true) - }) - .show(); - $(obj).addClass('coldrop-hover'); + } else { // column n is not visible + $(g.t).find('tr').each(function() { + $(this).find('th.draggable:eq(' + n + '),' + + 'td:eq(' + (g.actionSpan + n) + ')') + .show(); + }); + g.colVisib[n] = 1; + $(g.cList).find('.lDiv div:eq(' + n + ') input').attr('checked', 'checked'); + } + return true; + }, + + /** + * This must be called if toggleCol() returns is true. + * + * This function is separated from toggleCol because, sometimes, we want to toggle + * some columns together at one time and do just one adjustment after it, e.g. in showAllColumns(). + */ + afterToggleCol: function() { + // some adjustments after hiding column + g.reposRsz(); + g.reposDrop(); + g.sendColPrefs(); + + // check visible first row headers count + g.visibleHeadersCount = $(g.t).find('tr:first th.draggable:visible').length; + g.refreshRestoreButton(); + }, + + /** + * Show columns' visibility list. + * + * @param obj The drop down arrow of column visibility list + */ + showColList: function(obj) { + // only show when not resizing or reordering + if (!g.colRsz && !g.colReorder) { + var pos = $(obj).position(); + // check if the list position is too right + if (pos.left + $(g.cList).outerWidth(true) > $(document).width()) { + pos.left = $(document).width() - $(g.cList).outerWidth(true); } - }, - - /** - * Hide columns' visibility list. - */ - hideColList: function() { - $(this.cList).hide(); - $(g.cDrop).find('.coldrop-hover').removeClass('coldrop-hover'); - }, - - /** - * Reposition the column visibility drop-down arrow. - */ - reposDrop: function() { - $th = $(t).find('th:not(.draggable)'); - for (var i = 0; i < $th.length; i++) { - var $cd = $(this.cDrop).find('div:eq(' + i + ')'); // column drop-down arrow - var pos = $($th[i]).position(); - $cd.css({ - left: pos.left + $($th[i]).width() - $cd.width(), - top: pos.top - }); + $(g.cList).css({ + left: pos.left, + top: pos.top + $(obj).outerHeight(true) + }) + .show(); + $(obj).addClass('coldrop-hover'); + } + }, + + /** + * Hide columns' visibility list. + */ + hideColList: function() { + $(g.cList).hide(); + $(g.cDrop).find('.coldrop-hover').removeClass('coldrop-hover'); + }, + + /** + * Reposition the column visibility drop-down arrow. + */ + reposDrop: function() { + $th = $(t).find('th:not(.draggable)'); + for (var i = 0; i < $th.length; i++) { + var $cd = $(g.cDrop).find('div:eq(' + i + ')'); // column drop-down arrow + var pos = $($th[i]).position(); + $cd.css({ + left: pos.left + $($th[i]).width() - $cd.width(), + top: pos.top + }); + } + }, + + /** + * Show all hidden columns. + */ + showAllColumns: function() { + for (var i = 0; i < g.colVisib.length; i++) { + if (!g.colVisib[i]) { + g.toggleCol(i); } - }, - - /** - * Show all hidden columns. - */ - showAllColumns: function() { - for (var i = 0; i < this.colVisib.length; i++) { - if (!this.colVisib[i]) { - this.toggleCol(i); - } + } + g.afterToggleCol(); + }, + + /** + * Show edit cell, if it can be shown + * + * @param cell <td> element to be edited + */ + showEditCell: function(cell) { + if ($(cell).is('.grid_edit') && + !g.colRsz && !g.colReorder) + { + if (!g.isCellEditActive) { + $cell = $(cell); + // remove all edit area and hide it + $(g.cEdit).find('.edit_area').empty().hide(); + // reposition the cEdit element + $(g.cEdit).css({ + top: $cell.position().top, + left: $cell.position().left, + }) + .show() + .find('input') + .css({ + width: $cell.outerWidth(), + height: $cell.outerHeight() + }); + // fill the cell edit with text from <td>, if it is not null + var value = $cell.is(':not(.null)') ? PMA_getCellValue(cell) : ''; + $(g.cEdit).find('input') + .val(value); + + g.currentEditCell = cell; + $(g.cEdit).find('input[type=text]').focus(); + $(g.cEdit).find('*').removeAttr('disabled'); } - this.afterToggleCol(); - }, - - /** - * Show edit cell, if it can be shown or it is forced. - */ - showEditCell: function(cell, force) { - if ($(cell).is('.grid_edit') && - !g.colRsz && !g.colMov) - { - if (!g.isCellEditActive || force) { - $cell = $(cell); - // remove all edit area and hide it - $(g.cEdit).find('.edit_area').empty().hide(); - // reposition the cEdit element - $(g.cEdit).css({ - top: $cell.position().top, - left: $cell.position().left, - }) - .show() - .find('input') - .css({ - width: $cell.outerWidth(), - height: $cell.outerHeight() - }); - // fill the cell edit with text from <td>, if it is not null - var value = $cell.is(':not(.null)') ? PMA_getCellValue(cell) : ''; - $(g.cEdit).find('input') - .val(value); - - g.currentEditCell = cell; - $(g.cEdit).find('input[type=text]').focus(); - $(g.cEdit).find('*').removeAttr('disabled'); - } - } else { + } else { + if (g.isCellEditActive) { g.hideEditCell(); } - }, + } + }, + + /** + * Remove edit cell and the edit area, if it is shown. + * + * @param force Optional, force to hide edit cell without saving edited field. + * @param data Optional, data from the POST AJAX request to save the edited field + * or just specify "true", if we want to replace the edited field with the new value. + * @param field Optional, the edited <td>. If not specified, the function will + * use currently edited <td> from g.currentEditCell. + */ + hideEditCell: function(force, data, field) { + if (g.isCellEditActive && !force) { + // cell is being edited, post the edited data + g.saveOrPostEditedCell(); + return; + }
- /** - * Remove edit cell and the edit area, if it is shown. - * - * @param force Optional, force to hide edit cell without saving edited field. - * @param data Optional, data from the POST AJAX request to save the edited field - * or just specify "true", if we want to replace the edited field with the new value. - * @param field Optional, the edited <td>. If not specified, the function will - * use currently edited <td> from g.currentEditCell. - */ - hideEditCell: function(force, data, field) { - if (g.isCellEditActive && !force) { - // cell is being edited, post the edited data - g.saveOrPostEditedCell(); - return; - } - - // cancel any previous request - if (g.lastXHR != null) { - g.lastXHR.abort(); - g.lastXHR = null; - } - - if (data) { - if (g.currentEditCell) { // save value of currently edited cell - // replace current edited field with the new value - var $this_field = $(g.currentEditCell); - var new_html = $this_field.data('value'); - var is_null = $this_field.data('value') == null; - if (is_null) { - $this_field.find('span').html('NULL'); - $this_field.addClass('null'); - } else { - $this_field.removeClass('null'); - if ($this_field.is('.truncated')) { - if (new_html.length > g.maxTruncatedLen) { - new_html = new_html.substring(0, g.maxTruncatedLen) + '...'; - } + // cancel any previous request + if (g.lastXHR != null) { + g.lastXHR.abort(); + g.lastXHR = null; + } + + if (data) { + if (g.currentEditCell) { // save value of currently edited cell + // replace current edited field with the new value + var $this_field = $(g.currentEditCell); + var new_html = $this_field.data('value'); + var is_null = $this_field.data('value') == null; + if (is_null) { + $this_field.find('span').html('NULL'); + $this_field.addClass('null'); + } else { + $this_field.removeClass('null'); + if ($this_field.is('.truncated')) { + if (new_html.length > g.maxTruncatedLen) { + new_html = new_html.substring(0, g.maxTruncatedLen) + '...'; } - // replace '\n' with <br> - new_html = new_html.replace(/\n/g, '<br />'); - $this_field.find('span').html(new_html); } + // replace '\n' with <br> + new_html = new_html.replace(/\n/g, '<br />'); + $this_field.find('span').html(new_html); } - if (data.transformations != undefined) { - $.each(data.transformations, function(cell_index, value) { - var $this_field = $(g.t).find('.to_be_saved:eq(' + cell_index + ')'); - $this_field.find('span').html(value); - }); - } - if (data.relations != undefined) { - $.each(data.relations, function(cell_index, value) { - var $this_field = $(g.t).find('.to_be_saved:eq(' + cell_index + ')'); - $this_field.find('span').html(value); - }); - } - - // refresh the grid - this.reposRsz(); - this.reposDrop(); + } + if (data.transformations != undefined) { + $.each(data.transformations, function(cell_index, value) { + var $this_field = $(g.t).find('.to_be_saved:eq(' + cell_index + ')'); + $this_field.find('span').html(value); + }); + } + if (data.relations != undefined) { + $.each(data.relations, function(cell_index, value) { + var $this_field = $(g.t).find('.to_be_saved:eq(' + cell_index + ')'); + $this_field.find('span').html(value); + }); }
- // hide the cell editing area - $(g.cEdit).hide(); - $(g.cEdit).find('input[type=text]').blur(); - g.isCellEditActive = false; - g.currentEditCell = null; - }, + // refresh the grid + g.reposRsz(); + g.reposDrop(); + }
- /** - * Show drop-down edit area when edit cell is clicked. - */ - showEditArea: function() { - if (!this.isCellEditActive) { // make sure we don't have focus on other edit cell - g.isCellEditActive = true; - g.isEditCellTextEditable = false; - var $td = $(g.currentEditCell); - var $editArea = $(this.cEdit).find('.edit_area'); - var where_clause = $td.parent('tr').find('.where_clause').val(); - /** - * @var field_name String containing the name of this field. - * @see getFieldName() - */ - var field_name = getFieldName($td); - /** - * @var relation_curr_value String current value of the field (for fields that are foreign keyed). - */ - var relation_curr_value = $td.text(); - /** - * @var relation_key_or_display_column String relational key if in 'Relational display column' mode, - * relational display column if in 'Relational key' mode (for fields that are foreign keyed). - */ - var relation_key_or_display_column = $td.find('a').attr('title'); - /** - * @var curr_value String current value of the field (for fields that are of type enum or set). - */ - var curr_value = $td.find('span').text(); - - // empty all edit area, then rebuild it based on $td classes - $editArea.empty(); + // hide the cell editing area + $(g.cEdit).hide(); + $(g.cEdit).find('input[type=text]').blur(); + g.isCellEditActive = false; + g.currentEditCell = null; + }, + + /** + * Show drop-down edit area when edit cell is focused. + */ + showEditArea: function() { + if (!g.isCellEditActive) { // make sure the edit area has not been shown + g.isCellEditActive = true; + g.isEditCellTextEditable = false; + var $td = $(g.currentEditCell); + var $editArea = $(g.cEdit).find('.edit_area'); + var where_clause = $td.parent('tr').find('.where_clause').val(); + /** + * @var field_name String containing the name of this field. + * @see getFieldName() + */ + var field_name = getFieldName($td); + /** + * @var relation_curr_value String current value of the field (for fields that are foreign keyed). + */ + var relation_curr_value = $td.text(); + /** + * @var relation_key_or_display_column String relational key if in 'Relational display column' mode, + * relational display column if in 'Relational key' mode (for fields that are foreign keyed). + */ + var relation_key_or_display_column = $td.find('a').attr('title'); + /** + * @var curr_value String current value of the field (for fields that are of type enum or set). + */ + var curr_value = $td.find('span').text(); + + // empty all edit area, then rebuild it based on $td classes + $editArea.empty(); + + // add goto link, if this cell contains a link + if ($td.find('a').length > 0) { + var gotoLink = document.createElement('div'); + gotoLink.className = 'goto_link'; + $(gotoLink).append(g.gotoLinkText + ': ') + .append($td.find('a').clone()); + $editArea.append(gotoLink); + } + + g.wasEditedCellNull = false; + if ($td.is(':not(.not_null)')) { + // append a null checkbox + $editArea.append('<div class="null_div">Null :<input type="checkbox"></div>'); + var $checkbox = $editArea.find('.null_div input'); + // check if current <td> is NULL + if ($td.is('.null')) { + $checkbox.attr('checked', true); + g.wasEditedCellNull = true; + }
- // add goto link, if this cell contains a link - if ($td.find('a').length > 0) { - var gotoLink = document.createElement('div'); - gotoLink.className = 'goto_link'; - $(gotoLink).append(g.gotoLinkText + ': ') - .append($td.find('a').clone()); - $editArea.append(gotoLink); + // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'. + if ($td.is('.enum, .set')) { + $editArea.find('select').live('change', function(e) { + $checkbox.attr('checked', false); + }) + } else if ($td.is('.relation')) { + $editArea.find('select').live('change', function(e) { + $checkbox.attr('checked', false); + }) + $editArea.find('.browse_foreign').live('click', function(e) { + $checkbox.attr('checked', false); + }) + } else { + $(g.cEdit).find('input[type=text]').live('change', function(e) { + $checkbox.attr('checked', false); + }) + $editArea.find('textarea').live('keydown', function(e) { + $checkbox.attr('checked', false); + }) }
- g.wasEditedCellNull = false; - if ($td.is(':not(.not_null)')) { - // append a null checkbox - $editArea.append('<div class="null_div">Null :<input type="checkbox"></div>'); - var $checkbox = $editArea.find('.null_div input'); - // check if current <td> is NULL - if ($td.is('.null')) { - $checkbox.attr('checked', true); - g.wasEditedCellNull = true; - } - - // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'. - if ($td.is('.enum, .set')) { - $editArea.find('select').live('change', function(e) { - $checkbox.attr('checked', false); + // if 'checkbox_null_<field_name>_<row_index>' is clicked empty the corresponding select/editor. + $checkbox.click(function(e) { + if ($td.is('.enum')) { + $editArea.find('select').attr('value', ''); + } else if ($td.is('.set')) { + $editArea.find('select').find('option').each(function() { + var $option = $(this); + $option.attr('selected', false); }) } else if ($td.is('.relation')) { - $editArea.find('select').live('change', function(e) { - $checkbox.attr('checked', false); - }) - $editArea.find('.browse_foreign').live('click', function(e) { - $checkbox.attr('checked', false); - }) - } else { - $(g.cEdit).find('input[type=text]').live('change', function(e) { - $checkbox.attr('checked', false); - }) - $editArea.find('textarea').live('keydown', function(e) { - $checkbox.attr('checked', false); - }) - } - - // if 'checkbox_null_<field_name>_<row_index>' is clicked empty the corresponding select/editor. - $checkbox.click(function(e) { - if ($td.is('.enum')) { + // if the dropdown is there to select the foreign value + if ($editArea.find('select').length > 0) { $editArea.find('select').attr('value', ''); - } else if ($td.is('.set')) { - $editArea.find('select').find('option').each(function() { - var $option = $(this); - $option.attr('selected', false); - }) - } else if ($td.is('.relation')) { - // if the dropdown is there to select the foreign value - if ($editArea.find('select').length > 0) { - $editArea.find('select').attr('value', ''); - } - } else { - $editArea.find('textarea').val(''); } - $(g.cEdit).find('input[type=text]').val(''); - }) - } - - if($td.is('.relation')) { - /** @lends jQuery */ - //handle relations - $editArea.addClass('edit_area_loading'); - - // initialize the original data - $td.data('original_data', null); - - /** - * @var post_params Object containing parameters for the POST request - */ - var post_params = { - 'ajax_request' : true, - 'get_relational_values' : true, - 'server' : g.server, - 'db' : g.db, - 'table' : g.table, - 'column' : field_name, - 'token' : g.token, - 'curr_value' : relation_curr_value, - 'relation_key_or_display_column' : relation_key_or_display_column + } else { + $editArea.find('textarea').val(''); } + $(g.cEdit).find('input[type=text]').val(''); + }) + } + + if($td.is('.relation')) { + /** @lends jQuery */ + //handle relations + $editArea.addClass('edit_area_loading');
- g.lastXHR = $.post('sql.php', post_params, function(data) { - g.lastXHR = null; - $editArea.removeClass('edit_area_loading'); - // save original_data - var value = $(data.dropdown).val(); - $td.data('original_data', value); - // update the text input field, in case where the "Relational display column" is checked - $(g.cEdit).find('input[type=text]').val(value); - - $editArea.append(data.dropdown); - $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); - }) // end $.post() - - $editArea.find('select').live('change', function(e) { - $(g.cEdit).find('input[type=text]').val($(this).val()); - }) + // initialize the original data + $td.data('original_data', null); + + /** + * @var post_params Object containing parameters for the POST request + */ + var post_params = { + 'ajax_request' : true, + 'get_relational_values' : true, + 'server' : g.server, + 'db' : g.db, + 'table' : g.table, + 'column' : field_name, + 'token' : g.token, + 'curr_value' : relation_curr_value, + 'relation_key_or_display_column' : relation_key_or_display_column } - else if($td.is('.enum')) { - /** @lends jQuery */ - //handle enum fields - $editArea.addClass('edit_area_loading');
- /** - * @var post_params Object containing parameters for the POST request - */ - var post_params = { - 'ajax_request' : true, - 'get_enum_values' : true, - 'server' : g.server, - 'db' : g.db, - 'table' : g.table, - 'column' : field_name, - 'token' : g.token, - 'curr_value' : curr_value - } - g.lastXHR = $.post('sql.php', post_params, function(data) { - g.lastXHR = null; - $editArea.removeClass('edit_area_loading'); - $editArea.append(data.dropdown); - $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); - }) // end $.post() + g.lastXHR = $.post('sql.php', post_params, function(data) { + g.lastXHR = null; + $editArea.removeClass('edit_area_loading'); + // save original_data + var value = $(data.dropdown).val(); + $td.data('original_data', value); + // update the text input field, in case where the "Relational display column" is checked + $(g.cEdit).find('input[type=text]').val(value);
- $editArea.find('select').live('change', function(e) { - $(g.cEdit).find('input[type=text]').val($(this).val()); - }) - } - else if($td.is('.set')) { - /** @lends jQuery */ - //handle set fields - $editArea.addClass('edit_area_loading'); - - /** - * @var post_params Object containing parameters for the POST request - */ - var post_params = { - 'ajax_request' : true, - 'get_set_values' : true, - 'server' : g.server, - 'db' : g.db, - 'table' : g.table, - 'column' : field_name, - 'token' : g.token, - 'curr_value' : curr_value - } + $editArea.append(data.dropdown); + $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); + }) // end $.post() + + $editArea.find('select').live('change', function(e) { + $(g.cEdit).find('input[type=text]').val($(this).val()); + }) + } + else if($td.is('.enum')) { + /** @lends jQuery */ + //handle enum fields + $editArea.addClass('edit_area_loading');
- g.lastXHR = $.post('sql.php', post_params, function(data) { - g.lastXHR = null; - $editArea.removeClass('edit_area_loading'); - $editArea.append(data.select); - $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); - }) // end $.post() - - $editArea.find('select').live('change', function(e) { - $(g.cEdit).find('input[type=text]').val($(this).val()); - }) + /** + * @var post_params Object containing parameters for the POST request + */ + var post_params = { + 'ajax_request' : true, + 'get_enum_values' : true, + 'server' : g.server, + 'db' : g.db, + 'table' : g.table, + 'column' : field_name, + 'token' : g.token, + 'curr_value' : curr_value } - else if($td.is('.truncated, .transformed')) { - if ($td.is('.to_be_saved')) { // cell has been edited - var value = $td.data('value'); - $(g.cEdit).find('input[type=text]').val(value); - $editArea.append('<textarea>'+value+'</textarea>'); - $editArea.find('textarea').live('keyup', function(e) { - $(g.cEdit).find('input[type=text]').val($(this).val()); - }); - $(g.cEdit).find('input[type=text]').live('keyup', function(e) { - $editArea.find('textarea').val($(this).val()); - }); - $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); - } else { - /** @lends jQuery */ - //handle truncated/transformed values values - $editArea.addClass('edit_area_loading'); + g.lastXHR = $.post('sql.php', post_params, function(data) { + g.lastXHR = null; + $editArea.removeClass('edit_area_loading'); + $editArea.append(data.dropdown); + $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); + }) // end $.post() + + $editArea.find('select').live('change', function(e) { + $(g.cEdit).find('input[type=text]').val($(this).val()); + }) + } + else if($td.is('.set')) { + /** @lends jQuery */ + //handle set fields + $editArea.addClass('edit_area_loading');
- // initialize the original data - $td.data('original_data', null); + /** + * @var post_params Object containing parameters for the POST request + */ + var post_params = { + 'ajax_request' : true, + 'get_set_values' : true, + 'server' : g.server, + 'db' : g.db, + 'table' : g.table, + 'column' : field_name, + 'token' : g.token, + 'curr_value' : curr_value + }
- /** - * @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(data.success == true) { - if ($td.is('.truncated')) { - // get the truncated data length - g.maxTruncatedLen = $(g.currentEditCell).text().length - 3; - } - - $td.data('original_data', data.value); - $(g.cEdit).find('input[type=text]').val(data.value); - $editArea.append('<textarea>'+data.value+'</textarea>'); - $editArea.find('textarea').live('keyup', function(e) { - $(g.cEdit).find('input[type=text]').val($(this).val()); - }); - $(g.cEdit).find('input[type=text]').live('keyup', function(e) { - $editArea.find('textarea').val($(this).val()); - }); - $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); - } - else { - PMA_ajaxShowMessage(data.error); - } - }) // end $.post() - } - g.isEditCellTextEditable = true; - } else { - $editArea.append('<textarea>' + PMA_getCellValue(g.currentEditCell) + '</textarea>'); + g.lastXHR = $.post('sql.php', post_params, function(data) { + g.lastXHR = null; + $editArea.removeClass('edit_area_loading'); + $editArea.append(data.select); + $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); + }) // end $.post() + + $editArea.find('select').live('change', function(e) { + $(g.cEdit).find('input[type=text]').val($(this).val()); + }) + } + else if($td.is('.truncated, .transformed')) { + if ($td.is('.to_be_saved')) { // cell has been edited + var value = $td.data('value'); + $(g.cEdit).find('input[type=text]').val(value); + $editArea.append('<textarea>'+value+'</textarea>'); $editArea.find('textarea').live('keyup', function(e) { $(g.cEdit).find('input[type=text]').val($(this).val()); }); @@ -830,603 +858,489 @@ $editArea.find('textarea').val($(this).val()); }); $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); - g.isEditCellTextEditable = true; - } - - $editArea.show(); - } - }, - - /** - * Post the content of edited cell. - */ - postEditedCell: function() { - 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 = $("#relational_display_K").attr('checked') ? 'K' : 'D'; - /** - * @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 = Array(); - /** - * @var is_unique Boolean, whether the rows in this table is unique or not - */ - var is_unique = $('.edit_row_anchor').is('.nonunique') ? 0 : 1; - /** - * multi edit variables - */ - var me_fields_name = Array(); - var me_fields = Array(); - var me_fields_null = Array(); - - // alert user if edited table is not unique - if (!is_unique) { - alert(g.alertNonUnique); - } - - // loop each edited row - $('.to_be_saved').parents('tr').each(function() { - var $tr = $(this); - var where_clause = $tr.find('.where_clause').val(); - 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 = Array(); - var fields = Array(); - var fields_null = Array(); - - // 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($this_field); + } else { + /** @lends jQuery */ + //handle truncated/transformed values values + $editArea.addClass('edit_area_loading');
- /** - * @var this_field_params Array temporary storage for the name/value of current field - */ - var this_field_params = {}; + // initialize the original data + $td.data('original_data', null);
- 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_<field_name>_<row_index>' is checked. + * @var sql_query String containing the SQL query used to retrieve value of truncated/transformed data */ - var is_null = this_field_params[field_name] === null; + var sql_query = 'SELECT `' + field_name + '` FROM `' + g.table + '` WHERE ' + PMA_urldecode(where_clause);
- fields_name.push(field_name); - - if (is_null) { - fields_null.push('on'); - fields.push(''); - } else { - 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); + // 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(data.success == true) { + if ($td.is('.truncated')) { + // get the truncated data length + g.maxTruncatedLen = $(g.currentEditCell).text().length - 3; } - } else if($this_field.is('.relation')) { - relation_fields[cell_index] = {}; - $.extend(relation_fields[cell_index], this_field_params); + + $td.data('original_data', data.value); + $(g.cEdit).find('input[type=text]').val(data.value); + $editArea.append('<textarea>'+data.value+'</textarea>'); + $editArea.find('textarea').live('keyup', function(e) { + $(g.cEdit).find('input[type=text]').val($(this).val()); + }); + $(g.cEdit).find('input[type=text]').live('keyup', function(e) { + $editArea.find('textarea').val($(this).val()); + }); + $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); } - } - // 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; - } + else { + PMA_ajaxShowMessage(data.error); } - } - - }); // 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 '; + }) // end $.post() } - 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.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_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('*').attr('disabled', 'disabled'); - var $editArea = $(g.cEdit).find('.edit_area'); - $editArea.addClass('edit_area_posting'); + g.isEditCellTextEditable = true; } else { - $('.save_edited').addClass('saving_edited_data') - .find('input').attr('disabled', 'disabled'); // disable the save button + $editArea.append('<textarea>' + PMA_getCellValue(g.currentEditCell) + '</textarea>'); + $editArea.find('textarea').live('keyup', function(e) { + $(g.cEdit).find('input[type=text]').val($(this).val()); + }); + $(g.cEdit).find('input[type=text]').live('keyup', function(e) { + $editArea.find('textarea').val($(this).val()); + }); + $editArea.append('<div class="cell_edit_hint">' + g.cellEditHint + '</div>'); + g.isEditCellTextEditable = true; }
- $.ajax({ - type: 'POST', - url: 'tbl_replace.php', - data: post_params, - success: - function(data) { - g.isSaving = false; - if (!g.saveCellsAtOnce) { - $(g.cEdit).find('*').removeAttr('disabled'); - $editArea.removeClass('edit_area_posting'); - } else { - $('.save_edited').removeClass('saving_edited_data') - .find('input').removeAttr('disabled'); // enable the save button back - } - if(data.success == true) { - PMA_ajaxShowMessage(data.message); - $('.to_be_saved').each(function() { - var new_clause = $(this).parent('tr').data('new_clause'); - if (new_clause != '') { - var $where_clause = $(this).parent('tr').find('.where_clause'); - var old_clause = $where_clause.attr('value'); - var decoded_old_clause = PMA_urldecode(old_clause); - var decoded_new_clause = PMA_urldecode(new_clause); - - $where_clause.attr('value', new_clause); - // update Edit, Copy, and Delete links also - $(this).parent('tr').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).parent('tr').find('input[type=checkbox]').each(function() { - var $checkbox = $(this); - var checkbox_name = $checkbox.attr('name'); - var checkbox_value = $checkbox.attr('value'); - - $checkbox.attr('name', checkbox_name.replace(old_clause, new_clause)); - $checkbox.attr('value', checkbox_value.replace(decoded_old_clause, decoded_new_clause)); - }); - } - }); - // remove possible previous feedback message - $('#result_query').remove(); - if (typeof data.sql_query != 'undefined') { - // display feedback - $('#sqlqueryresults').prepend(data.sql_query); - } - g.hideEditCell(true, data); - - // remove the "Save edited cells" button - $('.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); - } - } - }) // end $.ajax() - }, + $editArea.show(); + } + }, + + /** + * Post the content of edited cell. + */ + postEditedCell: function() { + 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 = $("#relational_display_K").attr('checked') ? 'K' : 'D'; + /** + * @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 = Array(); + /** + * @var is_unique Boolean, whether the rows in this table is unique or not + */ + var is_unique = $('.edit_row_anchor').is('.nonunique') ? 0 : 1; + /** + * multi edit variables + */ + var me_fields_name = Array(); + var me_fields = Array(); + var me_fields_null = Array();
- // 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; - + // alert user if edited table is not unique + if (!is_unique) { + alert(g.alertNonUnique); + } + + // loop each edited row + $('.to_be_saved').parents('tr').each(function() { + var $tr = $(this); + var where_clause = $tr.find('.where_clause').val(); + full_where_clause.push(PMA_urldecode(where_clause)); + var condition_array = jQuery.parseJSON($tr.find('.condition_array').val()); + /** - * @var field_name String containing the name of this field. - * @see getFieldName() + * multi edit variables, for current row + * @TODO array indices are still not correct, they should be md5 of field's name */ - var field_name = getFieldName($this_field); + var fields_name = Array(); + var fields = Array(); + var fields_null = Array();
- /** - * @var this_field_params Array temporary storage for the name/value of current field - */ - var this_field_params = {}; + // 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($this_field);
- /** - * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked. - */ - var is_null = $(g.cEdit).find('input:checkbox').is(':checked'); - var value; + /** + * @var this_field_params Array temporary storage for the name/value of current field + */ + var this_field_params = {};
- if ($(g.cEdit).find('.edit_area').is('.edit_area_loading')) { - need_to_post = false; - } else if (is_null) { - if (!g.wasEditedCellNull) { - this_field_params[field_name] = null; - need_to_post = true; + if($this_field.is('.transformed')) { + transformation_fields = true; } - } else { - if($this_field.is(":not(.relation, .enum, .set, .bit)")) { - this_field_params[field_name] = $(g.cEdit).find('textarea').val(); - } else if ($this_field.is('.bit')) { - this_field_params[field_name] = '0b' + $(g.cEdit).find('textarea').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(","); + this_field_params[field_name] = $this_field.data('value'); + + /** + * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' 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 { - // results from a drop-down - $test_element = $(g.cEdit).find('select'); - if ($test_element.length != 0) { - this_field_params[field_name] = $test_element.val(); - } - - // results from Browse foreign value - $test_element = $(g.cEdit).find('span.curr_value'); - if ($test_element.length != 0) { - this_field_params[field_name] = $test_element.text(); + 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); } } - if (g.wasEditedCellNull || this_field_params[field_name] != PMA_getCellValue(g.currentEditCell)) { - need_to_post = true; + // 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
- if (need_to_post) { - $(g.currentEditCell).addClass('to_be_saved') - .data('value', this_field_params[field_name]); - if (g.saveCellsAtOnce) { - $('.save_edited').show(); - } - g.isCellEdited = true; + // 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));
- return need_to_post; - }, + me_fields_name.push(fields_name); + me_fields.push(fields); + me_fields_null.push(fields_null);
- // save or post edited cell, depending on the configuration - saveOrPostEditedCell: function() { - var saved = g.saveEditedCell(); - if (!g.saveCellsAtOnce) { - if (saved) { - g.postEditedCell(); - } else { - g.hideEditCell(true); - } - } else { - if (saved) { - g.hideEditCell(true, true); - } else { - g.hideEditCell(true); - } - } - }, + }); // 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_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' + };
- // initialize grid editing feature - initGridEdit: function() { - $(t).find('td.data') - .click(function(e) { - if (g.isCellEditActive) { - g.saveOrPostEditedCell(); - e.stopPropagation(); + if (!g.saveCellsAtOnce) { + $(g.cEdit).find('*').attr('disabled', 'disabled'); + var $editArea = $(g.cEdit).find('.edit_area'); + $editArea.addClass('edit_area_posting'); + } else { + $('.save_edited').addClass('saving_edited_data') + .find('input').attr('disabled', 'disabled'); // 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('*').removeAttr('disabled'); + $editArea.removeClass('edit_area_posting'); } else { - g.showEditCell(this); - e.stopPropagation(); + $('.save_edited').removeClass('saving_edited_data') + .find('input').removeAttr('disabled'); // enable the save button back } - // prevent default action when clicking on "link" in a table - if ($(e.target).is('a')) { - e.preventDefault(); + if(data.success == true) { + PMA_ajaxShowMessage(data.message); + $('.to_be_saved').each(function() { + var new_clause = $(this).parent('tr').data('new_clause'); + if (new_clause != '') { + var $where_clause = $(this).parent('tr').find('.where_clause'); + var old_clause = $where_clause.attr('value'); + var decoded_old_clause = PMA_urldecode(old_clause); + var decoded_new_clause = PMA_urldecode(new_clause); + + $where_clause.attr('value', new_clause); + // update Edit, Copy, and Delete links also + $(this).parent('tr').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).parent('tr').find('input[type=checkbox]').each(function() { + var $checkbox = $(this); + var checkbox_name = $checkbox.attr('name'); + var checkbox_value = $checkbox.attr('value'); + + $checkbox.attr('name', checkbox_name.replace(old_clause, new_clause)); + $checkbox.attr('value', checkbox_value.replace(decoded_old_clause, decoded_new_clause)); + }); + } + }); + // remove possible previous feedback message + $('#result_query').remove(); + if (typeof data.sql_query != 'undefined') { + // display feedback + $('#sqlqueryresults').prepend(data.sql_query); + } + g.hideEditCell(true, data); + + // remove the "Save edited cells" button + $('.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); } - }); - $(g.cEdit).find('input[type=text]').focus(function(e) { - g.showEditArea(); - }); - $(g.cEdit).find('input[type=text], select').live('keydown', function(e) { - if (e.which == 13) { - // post on pressing "Enter" - e.preventDefault(); - g.saveOrPostEditedCell(); - } - }); - $(g.cEdit).keydown(function(e) { - if (!g.isEditCellTextEditable) { - // prevent text editing - e.preventDefault(); - } - }); - $('html').click(function(e) { - // hide edit cell if the click is not from g.cEdit - if ($(e.target).parents().index(g.cEdit) == -1) { - g.hideEditCell(); - } - }); - $('html').keydown(function(e) { - if (e.which == 27 && g.isCellEditActive) { - - // cancel on pressing "Esc" - g.hideEditCell(true); - } - }); - $('.save_edited').click(function() { - g.hideEditCell(); - g.postEditedCell(); - }); - $(window).bind('beforeunload', function(e) { - if (g.isCellEdited) { - return g.saveCellWarning; } - }); - } - } - - // wrap all data cells, except actions cell, with span - $(t).find('th, td:not(:has(span))') - .wrapInner('<span />'); - - g.gDiv = document.createElement('div'); // create global div - g.cRsz = document.createElement('div'); // column resizer - 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 - g.cDrop = document.createElement('div'); // column drop-down arrows - g.cList = document.createElement('div'); // column visibility list - g.cEdit = document.createElement('div'); // cell edit - - // adjust g.cCpy - g.cCpy.className = 'cCpy'; - $(g.cCpy).hide(); - - // adjust g.cPoint - g.cPointer.className = 'cPointer'; - $(g.cPointer).css('visibility', 'hidden'); - - // adjust g.cDrop - g.cDrop.className = 'cDrop'; - - // adjust g.cList - g.cList.className = 'cList'; - $(g.cList).hide(); - - // adjust g.cEdit - g.cEdit.className = 'cEdit'; - $(g.cEdit).html('<input type="text" /><div class="edit_area" />'); - $(g.cEdit).hide(); + }) // end $.ajax() + },
- // chain table and grid together - t.grid = g; - g.t = t; + /** + * 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
- // get first row data columns - var $firstRowCols = $(t).find('tr:first th.draggable'); + var need_to_post = false;
- // initialize g.visibleHeadersCount - g.visibleHeadersCount = $firstRowCols.filter(':visible').length; + /** + * @var field_name String containing the name of this field. + * @see getFieldName() + */ + var field_name = getFieldName($this_field);
- // 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; - } + /** + * @var this_field_params Array temporary storage for the name/value of current field + */ + var this_field_params = {};
- // assign table create time - // #table_create_time will only available if we are in "Browse" tab - g.tableCreateTime = $('#table_create_time').val(); + /** + * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked. + */ + var is_null = $(g.cEdit).find('input:checkbox').is(':checked'); + var value; + + if ($(g.cEdit).find('.edit_area').is('.edit_area_loading')) { + 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(":not(.relation, .enum, .set, .bit)")) { + this_field_params[field_name] = $(g.cEdit).find('textarea').val(); + } else if ($this_field.is('.bit')) { + this_field_params[field_name] = '0b' + $(g.cEdit).find('textarea').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 { + // results from a drop-down + $test_element = $(g.cEdit).find('select'); + if ($test_element.length != 0) { + this_field_params[field_name] = $test_element.val(); + }
- // assign column reorder & column sort hint - g.reorderHint = PMA_messages['strColOrderHint']; - g.sortHint = PMA_messages['strSortHint']; - g.markHint = PMA_messages['strColMarkHint']; - g.colVisibHint = PMA_messages['strColVisibHint']; - g.showAllColText = PMA_messages['strShowAllCol']; - - // assign cell editing hint - g.cellEditHint = PMA_messages['strCellEditHint']; - g.saveCellWarning = PMA_messages['strSaveCellWarning']; - g.alertNonUnique = PMA_messages['strAlertNonUnique']; - - // initialize cell editing configuration - g.saveCellsAtOnce = $('#save_cells_at_once').val(); - - // assign common hidden inputs - var $common_hidden_inputs = $('.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(); - - // initialize column order - $col_order = $('#col_order'); - 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]); - } - } else { - g.colOrder = new Array(); - for (var i = 0; i < $firstRowCols.length; i++) { - g.colOrder.push(i); + // results from Browse foreign value + $test_element = $(g.cEdit).find('span.curr_value'); + if ($test_element.length != 0) { + this_field_params[field_name] = $test_element.text(); + } + } + if (g.wasEditedCellNull || this_field_params[field_name] != PMA_getCellValue(g.currentEditCell)) { + need_to_post = true; + } } - } - - // initialize column visibility - $col_visib = $('#col_visib'); - if ($col_visib.length > 0) { - g.colVisib = $col_visib.val().split(','); - for (var i = 0; i < g.colVisib.length; i++) { - g.colVisib[i] = parseInt(g.colVisib[i]); + + if (need_to_post) { + $(g.currentEditCell).addClass('to_be_saved') + .data('value', this_field_params[field_name]); + if (g.saveCellsAtOnce) { + $('.save_edited').show(); + } + g.isCellEdited = true; } - } else { - g.colVisib = new Array(); - for (var i = 0; i < $firstRowCols.length; i++) { - g.colVisib.push(1); + + return need_to_post; + }, + + /** + * Save or post currently edited cell, depending on the "saveCellsAtOnce" configuration. + */ + saveOrPostEditedCell: function() { + var saved = g.saveEditedCell(); + if (!g.saveCellsAtOnce) { + if (saved) { + g.postEditedCell(); + } else { + g.hideEditCell(true); + } + } else { + if (saved) { + g.hideEditCell(true, true); + } else { + g.hideEditCell(true); + } } - } - - if ($firstRowCols.length > 1) { - // create column drop-down arrow(s) - $(t).find('th:not(.draggable)').each(function() { - var cd = document.createElement('div'); // column drop-down arrow - var pos = $(this).position(); - $(cd).addClass('coldrop') - .css({ - left: pos.left + $(this).width() - $(cd).width(), - top: pos.top - }) - .click(function() { - if (g.cList.style.display == 'none') { - g.showColList(this); - } else { - g.hideColList(); - } + }, + + /** + * 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.cDrop).append(cd); - }); - - // add column visibility control - g.cList.innerHTML = '<div class="lDiv"></div>'; - var $listDiv = $(g.cList).find('div'); - for (var i = 0; i < $firstRowCols.length; i++) { - var currHeader = $firstRowCols[i]; - var listElmt = document.createElement('div'); - $(listElmt).text($(currHeader).text()) - .prepend('<input type="checkbox" ' + (g.colVisib[i] ? 'checked="checked" ' : '') + '/>'); - $listDiv.append(listElmt); - // add event on click - $(listElmt).click(function() { - if ( g.toggleCol($(this).index()) ) { - g.afterToggleCol(); - } - }); - } - // 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(); + $(g.cRsz).append(cb); }); - // 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(); - }); + 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 = $('#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]); + } + } else { + g.colOrder = new Array(); + for (var i = 0; i < $firstRowCols.length; i++) { + g.colOrder.push(i); + } } - } - - // create column borders - $firstRowCols.each(function() { - $this = $(this); - var cb = document.createElement('div'); // column border - $(cb).addClass('colborder') - .mousedown(function(e) { - g.dragStartRsz(e, this); - }); - $(g.cRsz).append(cb); - }); - g.reposRsz(); - - // bind event to update currently hovered qtip API - $(t).find('th').mouseenter(function(e) { - g.qtip = $(this).qtip('api'); - }); - - // create qtip for each <th> with draggable class - PMA_createqTip($(t).find('th.draggable')); - - // register events - if (g.reorderHint) { // make sure columns is reorderable + + // register events $(t).find('th.draggable') .mousedown(function(e) { if (g.visibleHeadersCount > 1) { - g.dragStartMove(e, this); + g.dragStartReorder(e, this); } }) .mouseenter(function(e) { @@ -1436,131 +1350,333 @@ } else { $(this).css('cursor', 'inherit'); } - g.updateHint(e); }) .mouseleave(function(e) { g.showReorderHint = false; - g.updateHint(e); }); - } - if ($firstRowCols.length > 1) { - var $colVisibTh = $(t).find('th:not(.draggable)'); - - PMA_createqTip($colVisibTh); - $colVisibTh.mouseenter(function(e) { - g.showColVisibHint = true; - g.updateHint(e); - }) - .mouseleave(function(e) { - g.showColVisibHint = false; - g.updateHint(e); - }); - } - $(t).find('th.draggable a') - .attr('title', '') // hide default tooltip for sorting - .mouseenter(function(e) { - g.showSortHint = true; - g.updateHint(e); - }) - .mouseleave(function(e) { - g.showSortHint = false; - g.updateHint(e); + // restore column order when the restore button is clicked + $('.restore_column').click(function() { + g.restoreColOrder(); }); - $(t).find('th.marker') - .mouseenter(function(e) { - g.showMarkHint = true; - g.updateHint(e); - }) - .mouseleave(function(e) { - g.showMarkHint = false; - g.updateHint(e); + + // attach to global div + $(g.gDiv).append(g.cPointer); + $(g.gDiv).append(g.cCpy); + + // prevent default "dragstart" event when dragging a link + $(t).find('th a').bind('dragstart', function() { + return false; }); - $(document).mousemove(function(e) { - g.dragMove(e); - }); - $(document).mouseup(function(e) { - g.dragEnd(e); - }); - $('.restore_column').click(function() { - g.restoreColOrder(); - }); - $(t).find('td, th.draggable').mouseenter(function() { - g.hideColList(); - }); - // edit cell event - if ($(t).is('.ajax')) { - g.initGridEdit(); - } + + // refresh the restore column button state + g.refreshRestoreButton(); + },
- // add table class - $(t).addClass('pma_table'); - - // link all divs - $(t).before(g.gDiv); - $(g.gDiv).append(t); - $(g.gDiv).prepend(g.cRsz); - $(g.gDiv).append(g.cPointer); - $(g.gDiv).append(g.cDrop); - $(g.gDiv).append(g.cList); - $(g.gDiv).append(g.cCpy); - $(g.gDiv).append(g.cEdit); - - // some adjustment - g.refreshRestoreButton(); - g.cRsz.className = 'cRsz'; - $(t).removeClass('data'); - $(g.gDiv).addClass('data'); - $(g.cRsz).css('height', $(t).height()); - $(t).find('th a').bind('dragstart', function() { - return false; - }); - }; - - // document ready checking - var docready = false; - $(document).ready(function() { - docready = true; - }); - - // Additional jQuery functions - /** - * Make resizable, reorderable grid. - */ - $.fn.makegrid = function() { - return this.each(function() { - if (!docready) { - var t = this; - $(document).ready(function() { - $.grid(t); - t.grid.reposDrop(); - }); + /** + * 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.colVisibHint = PMA_messages['strColVisibHint']; + g.showAllColText = PMA_messages['strShowAllCol']; + + // get data columns in the first row of the table + var $firstRowCols = $(g.t).find('tr:first th.draggable'); + + // initialize column visibility + $col_visib = $('#col_visib'); // check if column visibility is passed from PHP + if ($col_visib.length > 0) { + g.colVisib = $col_visib.val().split(','); + for (var i = 0; i < g.colVisib.length; i++) { + g.colVisib[i] = parseInt(g.colVisib[i]); + } } else { - $.grid(this); - this.grid.reposDrop(); + g.colVisib = new Array(); + for (var i = 0; i < $firstRowCols.length; i++) { + g.colVisib.push(1); + } } - }); - }; - /** - * Refresh grid. This must be called after changing the grid's content. - */ - $.fn.refreshgrid = function() { - return this.each(function() { - if (!docready) { - var t = this; - $(document).ready(function() { - if (t.grid) { - t.grid.reposRsz(); - t.grid.reposDrop(); - } + + // get data columns in the first row of the table + var $firstRowCols = $(t).find('tr:first th.draggable'); + + // make sure we have more than one column + if ($firstRowCols.length > 1) { + var $colVisibTh = $(g.t).find('th:not(.draggable)'); + PMA_createqTip($colVisibTh); + + // 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); + }) + .mouseenter(function(e) { + g.showColVisibHint = true; + }) + .mouseleave(function(e) { + g.showColVisibHint = false; + }); + + // add column visibility control + g.cList.innerHTML = '<div class="lDiv"></div>'; + var $listDiv = $(g.cList).find('div'); + for (var i = 0; i < $firstRowCols.length; i++) { + var currHeader = $firstRowCols[i]; + var listElmt = document.createElement('div'); + $(listElmt).text($(currHeader).text()) + .prepend('<input type="checkbox" ' + (g.colVisib[i] ? 'checked="checked" ' : '') + '/>'); + $listDiv.append(listElmt); + // add event on click + $(listElmt).click(function() { + if ( g.toggleCol($(this).index()) ) { + g.afterToggleCol(); + } + }); + } + // 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(); }); - } else { - if (this.grid) { - this.grid.reposRsz(); - this.grid.reposDrop(); + // 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 + $(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(); + }, + + /** + * Initialize grid editing feature. + */ + initGridEdit: function() { + // create cell edit wrapper element + g.cEdit = document.createElement('div'); + + // adjust g.cEdit + g.cEdit.className = 'cEdit'; + $(g.cEdit).html('<input type="text" /><div class="edit_area" />'); + $(g.cEdit).hide(); + + // assign cell editing hint + g.cellEditHint = PMA_messages['strCellEditHint']; + g.saveCellWarning = PMA_messages['strSaveCellWarning']; + g.alertNonUnique = PMA_messages['strAlertNonUnique']; + + // initialize cell editing configuration + g.saveCellsAtOnce = $('#save_cells_at_once').val(); + + // register events + $(t).find('td.data') + .click(function(e) { + if (g.isCellEditActive) { + g.saveOrPostEditedCell(); + e.stopPropagation(); + } else { + g.showEditCell(this); + e.stopPropagation(); + } + // prevent default action when clicking on "link" in a table + if ($(e.target).is('a')) { + e.preventDefault(); + } + }); + $(g.cEdit).find('input[type=text]').focus(function(e) { + g.showEditArea(); + }); + $(g.cEdit).find('input[type=text], select').live('keydown', function(e) { + if (e.which == 13) { + // post on pressing "Enter" + e.preventDefault(); + g.saveOrPostEditedCell(); + } + }); + $(g.cEdit).keydown(function(e) { + if (!g.isEditCellTextEditable) { + // prevent text editing + e.preventDefault(); + } + }); + $('html').click(function(e) { + // hide edit cell if the click is not from g.cEdit + if ($(e.target).parents().index(g.cEdit) == -1) { + g.hideEditCell(); + } + }); + $('html').keydown(function(e) { + if (e.which == 27 && g.isCellEditActive) { + + // cancel on pressing "Esc" + g.hideEditCell(true); + } + }); + $('.save_edited').click(function() { + g.hideEditCell(); + g.postEditedCell(); + }); + $(window).bind('beforeunload', function(e) { + if (g.isCellEdited) { + return g.saveCellWarning; + } + }); + + // attach to global div + $(g.gDiv).append(g.cEdit); + } + } + + /****************** + * Initialize grid + ******************/ + + // wrap all data cells, except actions cell, with span + $(t).find('th, td:not(:has(span))') + .wrapInner('<span />'); + + // create grid elements + g.gDiv = document.createElement('div'); // create global div + + // initialize the table variable + g.t = t; + + // 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 = $('#table_create_time').val(); + + // assign the hints + g.sortHint = PMA_messages['strSortHint']; + g.markHint = PMA_messages['strColMarkHint']; + + // assign common hidden inputs + var $common_hidden_inputs = $('.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'); + + // 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 && + $('.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 AjaxEnable is enabled in Settings + { + g.initGridEdit(); + } + + // create qtip for each <th> with draggable class + PMA_createqTip($(t).find('th.draggable')); + + // register events for hint tooltip + $(t).find('th.draggable a') + .attr('title', '') // hide default tooltip for sorting + .mouseenter(function(e) { + g.showSortHint = true; + g.updateHint(e); + }) + .mouseleave(function(e) { + g.showSortHint = false; + g.updateHint(e); + }); + $(t).find('th.marker') + .mouseenter(function(e) { + g.showMarkHint = true; + }) + .mouseleave(function(e) { + g.showMarkHint = false; + }); + }); .showMarkHint = false; / hide default tooltip for sorting s m EXPLAIN or SHOW syntax, which do not have a table navigation panel in cPointer class browser er ���L+ ��{�� � ��L+ �u{�� Pt{�� k��L+ 6 � �! �! �{�� ��{�� x���L+ �v{�� ���L+ ���L+ �{�� `��L+ _�{�� ��3�L+ u���L+ �3�L+ ش3�L+ ��3�L+ ���L+ x���L+ �v{�� Pu{�� k��L+ �! �! �{�� ��{�� H���L+ `w{�� ���L+ ���L+ �{�� `��L+ _�{�� P�{�� H�{�� 8��L+ �p� ��{�� u���L+ ���L+ `w{�� 0v{�� k��L+ G H I J K M N O P �{�� ��{�� HE��L+ y{�� ���L+ ���L+ �{�� 0�3�L+ u���L+ ���L+ �yc�L+ �3�L+ ش3�L+ ��3�L+ ���L+ HE��L+ y{�� @w{�� k��L+ 8E��L+ y{�� pw{�� k��L+ (E��L+ y{�� �w{�� k��L+ E��L+ y{�� �w{�� k��L+ ��3�L+ u���L+ ��3�L+ Pr{�� ��c�L+ e���L+ ش3�L+ px{�� y�c�L+ e���L+ �3�L+ �x{�� Z�c�L+ e���L+ �tc�L+ ���L+ �yc�L+ �3�L+ ����L+ ش3�L+ ��3�L+ ���L+ 8��L+ =/�L+ ��{�� pc�L+ Pz{�� y{�� k��L+ 5 6 7 8 : <