jquery – JQGRID:任何简单的方法来实现对excel的撤消,如jqGrid实现

5/14/12编辑:
我终于能够跳出我的懒惰,并准备好分享实际的 EXCEL LIKE JQGRID implementation.单元格选择可能会在几个浏览器上的jsfiddle上奇怪,但它应该在您的开发框中正常工作.玩的开心!!!!

9/13/11编辑:
这是我第一次使用JQGrid.我使用ver 4.1.2.我花了几个星期把excel和grid一起放在一起,最大的挑战就是找到关于如何使用JQGrid的正确的信息.我目前的设置有很多ajax更新和图像画廊和使用jqgrid格式化程序,但我在这里放置的主要代码是能够使用JQgrid与服务器端分页,excel像复制粘贴和演示几个其他功能jqGrid的.这只是我给予我从这个社区获得的所有帮助的方式.

对于刚刚跳到JQGrid的人来说,很快就会发现在jqgrid中使用Textarea有一些挑战.你可以找到一些解决方案here.

原帖:
只是给我一些更新,然后再提出我的问题….

我已经能够在我正在使用的jqgrid上提供一些额外的功能(经过很多论坛),包括:从Excel复制粘贴到jqgrid,在按键和dblclick上编辑单元格,复制和粘贴多个单元格从一个块到另一个在同一个网格上使用鼠标选择(从这里Using Javascript to ‘sum selected cells’ in IE6)

大多数复制粘贴功能仅在现在的IE上起作用.我保存所有更改在“保存”按钮单击,所以单元格上的所有更新都在屏幕上,直到用户点击“保存”按钮.

虽然现在还有一些事情,我现在想在纸上实现设计.我正在寻找一个简单的方式来UNDO只有最后的变化.我一直在想使用jQuery的“data()”和“removeData()”方法来实现这一点,但是如果jqgrid框架中已经存在任何可以帮助的内容,我想知道.有什么建议么??

<style type="text/css">
    .sel {background-color: #96B9DC !important; }
    .altered {}
</style>
<script type="text/javascript">
    var enableOnSelectEvent = false; // handle text selection
</script>
<div style="width:100%; background-color:#FFF; border:1px solid #000;"><input id="btnsavechanges" value="Save Changes" style="width:120px;" class="formbutton ui-corner-all" type="button" onclick="getChanges(); return false;" /></div>
<table id="grd_asset" width="100%" onSelectStart="return enableOnSelectEvent;"></table>
<div id="pfrmac" style='width:100%;'></div>
<input type="hidden" id="hidSelected" value="" />

<!-- copy content from the grid cells -->
<input type="hidden" id="hidCopiedText" value="" />

<!-- Start and End of cell selection -->
<input type="hidden" id="hidStartCell" value="" />
<input type="hidden" id="hidEndCell" value="" />

<!-- Start and End of last modified cell(s) -->
<input type="hidden" id="hidModStartCell" value="" />
<input type="hidden" id="hidModEndCell" value="" />

<script type="text/javascript">
    /*************************************************/
    /**************** Grid Utilities  ****************/
    /*************************************************/
    FnGrid = function () {
        this.GridColumns = function () {
            return assetGrid.jqGrid('getGridParam','colModel');
        }
        this.GetSelCells = function () {
            return assetGrid.find("td.sel");
        }
        this.ClearSelection = function () {
            assetGrid.find("td").removeClass("sel");
        }
        this.ClearSavedHistory = function () {
            assetGrid.removeData();
        }
        this.ClearMarkedChanges = function () {
            assetGrid.find("tr").removeClass("altered");
        }
        this.GetRowCells = function (cell) {
            return cell.parent().children("td")
        }
        this.GetRowId = function (cell) {
            var row = cell.closest('tr.jqgrow');
            return row.attr('id');
        }
        this.GetRowIndex = function (cell) {
            var cellrow = cell.parent();
            return cellrow.parent().children("tr").index(cellrow);
        }
        this.GetColIndex = function (cell) {
            return cell.parent().children("td").index(cell);
        }
        this.IsInEditMode = function () {
            var savedRows = assetGrid.getGridParam('savedRow');
            return (savedRows && savedRows.length > 0);
        }
        this.PutCellInEdit = function (cell,irow,icol,edit) {
            assetGrid.editCell(irow,edit);
            // transfer focus to the input
            var inp = $(cell).children("input")
            if (inp && inp.length > 0) {
                $(inp[0]).val('');
                $(inp[0]).focus();
            }
        }
        this.HandleEditMode = function (cell,e) {
            var ctrl = e.ctrlKey;
            var alt = e.altKey;

            var keyCode = (e.keyCode ? e.keyCode : e.which);
            if (keyCode) {
                if (keyCode >= 32 && keyCode <= 126 && !ctrl && !alt) {
                    // switch the cell to edit mode if not already
                    if (!($(cell).hasClass("edit-cell"))) {
                        this.PutCellInEdit(cell,this.GetRowIndex($(cell)),this.GetColIndex($(cell)),true);                        }
                }
            }
            return true;
        }
        this.HandleInputNavigation = function (ele,evt) {
            evt = window.event || evt;

            switch (evt.keyCode) {
                // down arrow                   
                case 40:
                    if (!$(ele).parent().hasClass("altered"))
                        $(ele).parent().addClass("altered");

                    irow = this.GetRowIndex($(ele).parent());
                    icol = this.GetColIndex($(ele).parent())
                    var prevcell = irow + "," + icol;
                    $("#hidModStartCell").val(prevcell);
                    $("#hidModEndCell").val(prevcell);

                    downele = $(ele).parent()
                            .parent()
                            .next()
                            .children("td")[this.GetColIndex($(ele).parent())];

                    this.ClearSelection();
                    assetGrid.editCell(this.GetRowIndex($(downele)),this.GetColIndex($(downele)),true);
                    break;

                // up arrow                   
                case 38:
                    if (!$(ele).parent().hasClass("altered"))
                        $(ele).parent().addClass("altered");

                    irow = this.GetRowIndex($(ele).parent());
                    icol = this.GetColIndex($(ele).parent())
                    var prevcell = irow + "," + icol;
                    $("#hidModStartCell").val(prevcell);
                    $("#hidModEndCell").val(prevcell);

                    topele = $(ele).parent()
                            .parent()
                            .prev()
                            .children("td")[this.GetColIndex($(ele).parent())];

                    if (this.GetRowIndex($(topele)) <= 0) break;

                    this.ClearSelection();
                    assetGrid.editCell(this.GetRowIndex($(topele)),this.GetColIndex($(topele)),true);
                    break;
            }
        }
    }

    var autocomp = new AutoCompleteRequest();
    var lastSel = "";
    var assetGrid = $('#grd_asset');
    var start = null;
    var fnassetgrid = new FnGrid();
    var lastSel = -1;

    function selectTo(cell) {
        if (start == null)
            return;
        fnassetgrid.ClearSelection();
        var stop = $(cell);
        var tbl = start.closest("table");
        var rs = tbl.children("tbody").children("tr");
        var r0 = rs.index(start.parent()),c0 = fnassetgrid.GetColIndex(start);
        var r1 = rs.index(stop.parent()),c1 = fnassetgrid.GetColIndex(stop);
        var concat = "";
        for (var i = r0; i <= r1; i++) {
            var cells = $(rs.get(i)).children("td");
            var rowid = 0;
            for (var j = c0; j <= c1; j++) {
                var cell = $(cells.get(j));
                if (rowid == 0) rowid = fnassetgrid.GetRowId(cell);
                if (cell.is(":hidden")) continue;
                cell.addClass("sel");
                concat += assetGrid.getCell(rowid,j) + "\t";
            }
            if (concat.lastIndexOf("\t") == concat.length - 1)
                concat = concat.substring(0,concat.lastIndexOf("\t"));

            concat += escape("\r\n");
        }
        $("#hidSelected").val(concat.trim());
    }


    $(document).ready(function () {
        /*************************************************/
        /******************* THE GRID  *******************/
        /*************************************************/
        assetGrid.jqGrid({
            ajaxGridOptions: { contentType: "application/json; charset=utf-8",type: "POST" },url: '../api/yourservices.asmx/GetData',datatype: 'json',serializeGridData: function (postData) {
                if (postData.searchField === undefined) postData.searchField = null;
                if (postData.searchString === undefined) postData.searchString = null;
                if (postData.searchOper === undefined) postData.searchOper = null;
                if (postData.filters === undefined) postData.filters = null;
                return JSON.stringify(postData);
            },colNames: [' ','AssetId','Item#','Make','Description'],colModel: [
                { name: 'ctrls',width: 80,fixed: true,sortable: false,resize: false,formatter: 'actions',formatoptions: { keys: true }
                },{ name: 'AssetID',label: 'AssetID',width: 65,key: true,hidden: true },{ name: 'Sequence',label: 'Item#',width: 50,align: "right",sorttype: 'int',sortable: true,editoptions: { dataEvents: [{ type: 'keydown',fn: function (e) { fnassetgrid.HandleInputNavigation(this,e); } }]} },{ name: 'Make',label: 'Make',width: 105,editable: true,edittype: 'text',editoptions: {
                    size: 18,dataEvents: [{
                        type: 'focus',fn: function (e) {
                            $(this).autocomplete({
                                source: autocomp.source,delay: autocomp.delay,minLength: autocomp.minLength
                            });

                            $(this).bind("autocompleteopen",autocomp.open);
                            $(this).bind("autocompleteclose",autocomp.close);
                        }
                    }]
                }
                },{ name: 'Description',label: 'Description',fixed: false,edittype: 'textarea',unformat: unfrmttextarea,editoptions: { rows: "10",cols: "40"} }
            ],rowNum: 10,/* no of recs in a grid */
            width: 1330,rowList: [10,20,30],/* array to construct a select box element in the pager */
            pager: '#pfrmac',sortname: 'AssetID',/* initial sorting column */
            viewrecords: true,/* display the number of total records on the pager bar */
            pginput: true,sortorder: "desc",cellEdit: true,shrinkToFit: true,jsonReader: {
                root: function (obj) { return obj.d.SearchResultSet; },page: function (obj) { return obj.d.PageNum; },// current page of the query
                total: function (obj) { return obj.d.TotalPages; },// total pages for the query
                records: function (obj) { return obj.d.TotalNoOfSearchResultItems; },id: "AssetID",repeatitems: false,userdata: function (obj) {
                    extendUserSession();
                    return { "Error": obj.d.Error,"SearchResultSet": obj.d.SearchResultSet }
                }
            },loadonce: false,caption: "Asset list",height: '100%',cellsubmit: 'clientArray',beforeEditCell: function (rowid,cellname,value,iRow,iCol) {
                enableOnSelectEvent = true;
            },beforeSaveCell: function (rowid,iCol) {
                savedrow = assetGrid.getGridParam('savedRow');
                if (savedrow && savedrow.length > 0) {
                    if (savedrow[0].id == iRow && savedrow[0].ic == iCol && savedrow[0].v != value) {
                        tr = $('#' + rowid);
                        if (tr && !tr.hasClass("altered")) {
                            tr.addClass("altered");
                            there_are_unsaved_changes = 1;
                        }
                    }
                }
            },afterSaveCell: function (rowid,iCol) {
                enableOnSelectEvent = false;
            },afterRestoreCell: function (rowid,loadComplete: function (data) {
                if (assetGrid.getGridParam('userData').Error && assetGrid.getGridParam('userData').Error != '')
                    alert("Error: " + assetGrid.getGridParam('userData').Error);
            },gridComplete: function () {
                rowindex = 1;
                rows = assetGrid.find("tr");

                if (rows && rows.length > 1) {
                    for (i = 1; i < rows.length; i++) {
                        $(rows[i]).find("td").each(function (evt) {
                            evt = window.event || evt;

                            start = $(this);
                            colindex = fnassetgrid.GetColIndex(start);
                            if (colindex > 0) {
                                $(this).click(function () {
                                    if (!($(this).hasClass("edit-cell")))
                                        return false;
                                }).dblclick(function () {
                                    if (!($(this).hasClass("edit-cell"))) {
                                        fnassetgrid.PutCellInEdit(this,fnassetgrid.GetRowIndex($(this)),fnassetgrid.GetColIndex($(this)),true);
                                        return;
                                    }
                                    else
                                        return true;
                                }).mousedown(function () {
                                    if (fnassetgrid.IsInEditMode())
                                        return true;
                                    start = $(this);
                                    selectTo(this);
                                    return false;
                                }).mouseover(function () {
                                    if (fnassetgrid.IsInEditMode()) return true;
                                    selectTo(this);
                                }).mouseup(function () {
                                    if (fnassetgrid.IsInEditMode()) return true;
                                    selectTo(this);
                                    $("#hidEndCell").val(fnassetgrid.GetColIndex($(this)));
                                    start = null;
                                }).keypress(function (e) {
                                    fnassetgrid.HandleEditMode(this,e);
                                });
                            }
                        });
                        rowindex++;
                    }
                }
            }
        });

        function unfrmttextarea(cellvalue,options,cellobject) {
            return cellvalue;
        }

        $("body").mouseup(function () {
            start = null;
        });


        /*************************************************/
        /*********** Global KEYUP integration  ***********/
        /*************************************************/
        $(assetGrid).keyup(function (e) {
            var ctrl = e.ctrlKey
            var key = e.charCode || e.keyCode || 0;

            if ((ctrl && key == 88) /* CUT */ || (ctrl && key == 67) /* COPY */ || (ctrl && key == 86) /* PASTE */ || (ctrl && key == 90) /* UNDO */) {

                if ((ctrl && key == 88) /* CUT */ || (ctrl && key == 67) /* COPY */) {
                    if (fnassetgrid.IsInEditMode()) return true;
                    CopyToClipboard("hidSelected");

                    var selectedCells = fnassetgrid.GetSelCells();

                    if (selectedCells && selectedCells.length > 0) {
                        $("#hidStartCell").val(fnassetgrid.GetRowIndex($(selectedCells[0])) + "," + fnassetgrid.GetColIndex($(selectedCells[0])));
                        $("#hidEndCell").val(fnassetgrid.GetRowIndex($(selectedCells[selectedCells.length - 1])) + "," + fnassetgrid.GetColIndex($(selectedCells[selectedCells.length - 1])));
                        $("#hidCopiedText").val($("#hidSelected").val());
                    }
                    else {
                        $("#hidStartCell").val('');
                        $("#hidEndCell").val('');
                    }

                    if (ctrl && key == 88) /* CUT */{
                        assetGrid.find("td.sel").each(function () {
                            row = $(this).closest('tr.jqgrow');
                            rowId = row.attr('id');
                            assetGrid.setCell(rowId,(fnassetgrid.GridColumns())[fnassetgrid.GetColIndex($(this))].name,'',true);
                        });
                        fnassetgrid.ClearSelection();
                    }
                }
                else if (ctrl && key == 86) /* PASTE */{
                    var clipboardata = getClipboardData();
                    if (get_objtype(clipboardata) != "[object String]") {
                        alert("The data you are pasting either is empty or incompatible");
                        return false;
                    }

                    pasteinfo(assetGrid,clipboardata);
                }
                else if ((ctrl && key == 90) /* UNDO */) {
                // TBD : No jqgrid features available to get the help 
                }
                return false; // prevent bubbling
            }
            else
                return true; // let it bubble
        });
    });


    /********************************************************************/
    /*********** Method to retrieve and submit altered asset information ***********/
    /********************************************************************/
    function getChanges() {
        var editedxml = "<?xml version='1.0' encoding='utf-8' ?\>\n";
        editedxml += "<ASSETS>\n";
        assetGrid.find("tr.altered").each(function () {
            editedxml += "<ASSET>\n";
            $(this).children("td").each(function () {
                colindex = fnassetgrid.GetColIndex($(this));                    
                if (colindex > 0) {
                    editedxml += "<" + (fnassetgrid.GridColumns())[colindex].name.toUpperCase() + ">" + $(this).text().trim() + "</" + (fnassetgrid.GridColumns())[colindex].name.toUpperCase() + ">\n";
                }
            })
            editedxml += "</ASSET>\n";
        })
        editedxml += "</ASSETS>";

        fnassetgrid.ClearMarkedChanges();

        //TBD: submit XML to an AJAX service
    }


    var _browserPasteData = null;
    function getClipboardData() {
        if (_browserPasteData) // Safari/Chrome logic
            return _browserPasteData;
        if (window.clipboardData) // IE logic
        {
            return window.clipboardData.getData("Text");
        }
        else if (typeof (netscape) != "undefined") // Firefox logic
        {
            netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
            var clip = Components.classes["@mozilla.org/widget/clipboard;1"].createInstance(Components.interfaces.nsIClipboard);
            var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
            trans.addDataFlavor("text/unicode");
            clip.getData(trans,clip.kGlobalClipboard);
            var str = new Object();
            var len = new Object();
            trans.getTransferData("text/unicode",str,len);
            if (str)
                return str.value.QueryInterface(Components.interfaces.nsISupportsString).toString();
        }
        return null;
    }
    // In Safari/Chrome the clipboard data can only be accessed
    // from the onpaste event. In this sample the event is handled 
    // off the body element: <body onpaste="browserPaste(event)">
    function browserPaste(e) {
        _browserPasteData = e.clipboardData && e.clipboardData.getData ?
            e.clipboardData.getData('text/plain') : null;
    }

    function pasteinfo(objGrid,info) {
        selectedCells = fnassetgrid.GetSelCells();
        firstcell = $(selectedCells[0]);
        firstselectedcolindex = fnassetgrid.GetColIndex(firstcell);
        rowcellscount = fnassetgrid.GetRowCells(firstcell).length;

        if (firstselectedcolindex == 0) {
            alert("You cannot paste into an non-editable column");
            return false;
        }

        if (selectedCells && selectedCells.length > 0) {
            // if the clipboard info is from the asset grid
            if (info && info == $("#hidCopiedText").val()) {
                // get the index values of last copied source cell
                hidStartCell = -1;
                if ($("#hidStartCell").val() != '' && $("#hidStartCell").val().split(',').length > 1) {
                    hidStartCell = $("#hidStartCell").val().split(',')[1];
                }

                // if columns of source and dest do not match,throw warning
                if (firstselectedcolindex != hidStartCell) {
                    if (!confirm("The data you are pasting comes from a different set of \ncolumns than those that you are pasting into.\n\nAre you sure you want to paste into these columns?"))
                        return false;
                }
            }

            $("#hidModStartCell").val(fnassetgrid.GetRowIndex(firstcell) + "," + firstselectedcolindex);

            var prevcell = null;
            // remove the last "line break" and break clipboard info into lines
            datarows = unescape(info).replace(/\r\n$/,'').split("\r\n");
            if (datarows && datarows.length > 0) {
                currentrow = firstcell.parent();
                currentcell = firstcell;

                // if the source is a single cell,allow it to be pasted over multiple cells
                if (datarows.length == 1 && datarows[0].split("\t").length == 1) {
                    copydata = datarows[0].split("\t");

                    $.each(selectedCells,function (index,value) {
                        prevcell = $(value);
                        if (!prevcell.parent().hasClass("altered")) {
                            prevcell.parent().addClass("altered");
                            there_are_unsaved_changes = 1;
                        }
                        var rowId = prevcell.closest('tr.jqgrow').attr('id');
                        var icol = fnassetgrid.GetColIndex(prevcell);
                        assetGrid.setCell(rowId,(fnassetgrid.GridColumns())[icol].name,copydata[0],true);
                    });
                }
                else {
                    for (i = 0; i < datarows.length && currentrow.length > 0; ++i) {
                        if (datarows[i] == '') break;
                        // break each lines into columns
                        datarows[i] = datarows[i].split("\t");
                        var row = null;
                        var rowId = null;
                        var rowindex = null;
                        for (j = 0; j < datarows[i].length && currentcell.length > 0; ++j) {
                            // mark the row as altered
                            if (!currentcell.parent().hasClass("altered")) {
                                currentcell.parent().addClass("altered");
                                there_are_unsaved_changes = 1;
                            }
                            // for each outer iteration get the rowid
                            if (row == null) {
                                row = (currentcell).closest('tr.jqgrow');
                                rowId = row.attr('id');
                            }
                            var icol = fnassetgrid.GetColIndex(currentcell);
                            assetGrid.setCell(rowId,datarows[i][j],true);
                            prevcell = currentcell;

                            // advance to the next visible cell -- only consider pasting into visible columns
                            do {
                                currentcell = currentcell.next();
                            }
                            while ((currentcell.length > 0) && currentcell.is(":hidden"))
                        }

                        currentrow = currentrow.next();
                        currentcell = $(currentrow.children("td")[firstselectedcolindex]);
                    }
                }
            }
        }

        if (prevcell.length > 0)
            $("#hidModEndCell").val(fnassetgrid.GetRowIndex(prevcell) + "," + fnassetgrid.GetColIndex(prevcell));
    }

</script>

提前谢谢了!

解决方法

一种可能性是将最后一个值存储为可以使用以下方式完成的单元格的属性
$('#' + rowid + ' > td:eq(' + colIndex + ')').attr('lastval',valueToSave);

其中rowid是您正在处理的行,colIndex是要保存值的列的编号.这将创建一个名为lastval的属性,可以与您的undo功能一起使用.这种方法的缺点是,整个网格将在刷新时更新,并且您将丢失存储在网格中的属性.

假设这是可以接受的,那么您可以保存每个单元格的最后一个值

loadComplete: function() {
    $("#list").find("td").each(function(index,elem) {
        $(elem).attr('lastval',$(elem).html());
    });
},

其中’list’是您最初创建的jqGrid的id.

您可以根据您希望维护lastval的方式,将lastval作为beforeSubmit或其他回调的一部分进行更新.

我相信有更有效的技巧来做上面的工作,但是随着刷新过程中的数据丢失,我不知道这将真正有助于你所要做的.更好的方法是将这些属性存储在DOM中的其他位置或服务器上.但是,如果我正确地阅读上述意见,您希望保留网格中的最后一个.

相关文章

1.第一步 设置响应头 header(&#39;Access-Control-Allow...
$.inArray()方法介绍 $.inArray()函数用于在数组中搜索指定的...
jquery.serializejson.min.js的妙用 关于这个jquery.seriali...
JS 将form表单数据快速转化为object对象(json对象) jaymou...
jQuery插件之jquery.spinner数字智能增减插件 参考地址:http...