神马其余Audit Trail实现方式都是浮云 - 用Ext实现的Time machine(效果图+源码)

神马其他Audit Trail实现方式都是浮云 -- 用Ext实现的Time machine(效果图+源码)
效果图:
神马其余Audit Trail实现方式都是浮云 - 用Ext实现的Time machine(效果图+源码)
源代码:
Ext.ns('SCTMS.dlg');    
SCTMS.dlg.TimeMachine = Ext.extend(Ext.Window, {    
    maximized : true, modal : true, closeable: false, closeAction : "hide", layout : "fit", autoScroll : false, cls : "z-timemachine-dlg"
    , initComponent : function() {    
        this.northPanel = new Ext.Panel({region:'north', height:24, html:'<div style="position:absolute;top:5px;left:5px;color:#ffffff;font-weight:bold;"><a href="javascript:void(0)" onclick="SCTMS.dlg.timeMachine.hide();return false;" title="Go back to Global Clinical">Back</a></div><div style="padding-top:5px;color:#c3c3c3;font-weight:bold;"><center>Time Machine</center></div><div style="position:absolute;top:5px;right:5px;color:#ffffff;font-weight:bold;"><a id="timemachine-link-toggle-version-list" href="javascript:void(0);" onclick="SCTMS.dlg.timeMachine.toggleVersionList();return false;">Hide Version List</a></div>'});    
        this.dummyCenterPanel = new Ext.Panel({region:'center'});    
        this.versionListPanel = new Ext.grid.GridPanel({    
            region : "east", width: 270, header: false, autoScroll : true, cls:' panel-transparent'//, cls:' panel-transparent grid-no-header'    
            , columns: [{header:'#',align:'right',width: 20, dataIndex:'version', renderer:function(v,x,r){    
                return (v+1)
            }}, {header:'Author',width:110,dataIndex:'createdBy'}
             , {header:'Date Created',width:120,dataIndex:'dateCreated'}]    
            , store: new Ext.data.JsonStore({    
                url: Ext.CONTEXT_PATH + '/rpc/timeMachine/versions',    
                root: 'versions',    
                idProperty: 'version',    
                fields: ['version','dateCreated','createdBy']    
            })    
            , bbar: ['->',{xtype:'sexybutton',text:'Compare',handler:this.compare,scope:this}]    
            , listeners: {'rowclick':function(g,i,e){    
                this.loadVersion({mid:this.mid,version:g.getStore().getAt(i).get('version')});    
            },scope:this}    
        });    
        var a = this.panel = new Ext.Panel({    
            layout : "border", items : [this.northPanel, this.dummyCenterPanel, this.versionListPanel]}    
        );    
        this.items = [a];    
        SCTMS.dlg.TimeMachine.superclass.initComponent.apply(this, arguments);    
    }    
    , initEvents : function() {    
        SCTMS.dlg.TimeMachine.superclass.initEvents.apply(this, arguments);    
    }    
    , show : function(mid) {    
        this.mid = mid;    
        SCTMS.dlg.TimeMachine.superclass.show.call(this);    
        this.loadVersion({mid:mid});    
        var store = this.versionListPanel.getStore();    
        store.baseParams.mid = mid;    
        store.load();    
    }             
    , hide : function() {    
        this.dataWin.hide();    
        if(this.compareWin)this.compareWin.hide();    
        SCTMS.dlg.TimeMachine.superclass.hide.apply(this, arguments);    
    }    
    , toggleVersionList : function() {    
        var visible = this.versionListPanel.isVisible();    
        Ext.get('timemachine-link-toggle-version-list').update((visible ? 'Show' : 'Hide') + ' Version List');    
        this.versionListPanel[visible?'hide':'show']();    
    }    
    , loadVersion : function(p) {    
        if(!this.dataWin) {    
            this.dataWin = new Ext.Window({layout:'absolute', autoScroll:true, closable:false, resizable:false, cls:' panel-transparent', border:false, bbar:{height:100}});    
            this._resizeDataWin = function() {
                var adjustedH = Math.min(document.body.clientHeight/1.1, this.xform.height + 135);
                var adjustedW = Math.min(document.body.clientWidth/1.1, this.xform.width + 15 + ((document.body.clientHeight/1.1>=this.xform.height + 135)?0:17));
                this.dataWin.setSize(adjustedW, adjustedH);
                try{this.dataWin.center();}catch(e){}
            };
            this.on('resize', this._resizeDataWin, this);
        }
        GRS.dispatcher.dispatch("timeMachine/version?view=true", p, function(x) {
            this.xform = x.form;
            this.xchanges = x.changes;
            this.dataWin.setTitle('version ' + (x.oversion+1) + ', modified by ' + x.ocreatedBy+ ' on ' + x.odateCreated);    
            this._resizeDataWin.call(this);
            this.dataWin.show();    
            x.form.listeners = x.form.listeners || {};    
            var dw = this.dataWin;    
            x.form.listeners.subformrender = {
                scope: this,
                fn: function() {
                    if(this.xchanges) {
                        for(var k in this.xchanges) {
                            if(/Id$/.test(k)) {
                                continue;
                            }
                            if(this.xchanges.hasOwnProperty(k)) {
                                try{
                                    var ov = this.xchanges[k][1];
                                    if(ov == null) {ov = 'null'}
                                    var tooltip_html = 'In previous version it was:<div style="color:#0000ff;font-weight:bold;">' + (!ov||ov==''?'&nbsp;':ov.replace(/\n/g,'<br>')) + '</div>';
                                    var f = dw.form.findField(k);
                                    if(f) {
                                        f.addClass('x-form-different-field');
                                        new Ext.ToolTip({target:f.id, html:tooltip_html, dismissDelay: 0});
                                    } else {
                                        var special_cased_f = Ext.get(this.xform.id+'_'+k);
                                        if(special_cased_f) {
                                            special_cased_f.addClass('x-form-different-field');
                                            new Ext.ToolTip({target:this.xform.id+'_'+k, html:tooltip_html,  dismissDelay: 0})
                                        }
                                    }
                                }catch(err){}
                            }
                        }
                    }
                }
            };
            GRS.form.FormProcessor.addForm2Panel(this.dataWin, x, {callback:x.form.listeners.subformrender.fn, scope:this, hideEmptyText:true});
                 
            if(!x.changes) {    
                this.dataWin.getBottomToolbar().update('');    
                return;    
            }    
            var changes = [];    
            for(var k in x.changes) {    
                if(/Id$/.test(k)) continue;    
                if(x.changes.hasOwnProperty(k)) {    
                    changes.push('<p>&#9830;&nbsp;<font color="blue">' + k + '</font> <font color="gray">changed from</font> <font color="blue">' + x.changes[k][1] + '</font> <font color="gray">to</font> <font color="blue">' + x.changes[k][0] + '</font></p>');        
                }        
            }
            this.dataWin.getBottomToolbar().update('Change Summary<hr><div style="overflow:auto;height:70px;">' + (changes.length ? changes.join('') : 'No changes from previous version.') + '</div>');    
        }, this);        
    }    
    , compare :function() {    
        var selections = SCTMS.dlg.timeMachine.versionListPanel.getSelectionModel().getSelections();        
        if(!selections || selections.length < 2) {Ext.MessageBox.alert('', 'You need to select 2 versions to compare.');return}    
        if(!this.compareWin) {    
            this.compareWin = new Ext.Window({    
                cls:' panel-transparent', border:false    
                , title: '<center><b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">Global Comparator</span></b></center>'    
                , modal:true, resizable:false, closeAction:'hide'    
                , layout: 'border'    
                , items: [
                      this.comparePanel1 = new Ext.Panel({region:'west', layout:'absolute', autoScroll:false, title:'&nbsp;', split:true})
                    //, {region:'center',width:2,border:true,html:'<div style="height:2000px;overflow:hidden;width:2px;border-right:1px dashed #B5B8C8;">'}
                    , this.comparePanel2 = new Ext.Panel({region:'center', layout:'absolute', autoScroll:false, title:'&nbsp;'})
                    , this.vScroller = new Ext.Panel({region:'east', width:17, autoScroll:true, layout:'absolute', items:[this.ivScroller = new Ext.BoxComponent({width:17})]})
                    , this.hScroller = new Ext.Panel({region:'south', height:17, autoScroll:true, layout:'absolute', items:[this.ihScroller = new Ext.BoxComponent({height:17})]})
                ]        
            });
            this._resizeCompareWin = function() {
                var adjustedH = Math.min(this.xform.height+75, document.body.clientHeight/1.1) + 17;
                var adjustedW = Math.min(this.xform.width * 2, document.body.clientWidth/1.1) + 17;
                this.compareWin.setSize(adjustedW, adjustedH);

                var w = Math.min(document.body.clientWidth/2.2, this.xform.width)
                  , h = Math.min(document.body.clientHeight/1.1, this.xform.height);
                this.comparePanel1.setSize(w, h);
                this.comparePanel2.setSize(w, h);
                
                this.vScroller.setSize(17, h);this.ivScroller.setSize(17, this.xform.height);
                this.hScroller.setSize(w*2, 17);this.ihScroller.setSize(this.xform.width*2, 17);
                
                try{this.compareWin.center();}catch(e){}
            };
            this.comparePanel1.on('render', function(){    
                Ext.TaskMgr.start({interval : 300, scope : this, run : function(){    
                    if(this.comparePanel1.form && this.comparePanel2.form) {  
                        var st = SCTMS.dlg.timeMachine.ivScroller.el.dom.parentNode.scrollTop;
                        var sl = SCTMS.dlg.timeMachine.ihScroller.el.dom.parentNode.scrollLeft/2;
                        if(st>0)st+=17;if(sl>0)sl+=17;
                        Ext.get(Ext.get(this.comparePanel1.form.id).dom.parentNode.parentNode.id).dom.parentNode.scrollTop =     
                        Ext.get(Ext.get(this.comparePanel2.form.id).dom.parentNode.parentNode.id).dom.parentNode.scrollTop =
                        st;    
                        Ext.get(Ext.get(this.comparePanel1.form.id).dom.parentNode.parentNode.id).dom.parentNode.scrollLeft =     
                        Ext.get(Ext.get(this.comparePanel2.form.id).dom.parentNode.parentNode.id).dom.parentNode.scrollLeft =
                        sl;    
                    }    
                }});
                this.on('resize', this._resizeCompareWin, this);
            }, this);        
        }    
        var p = {mid:this.mid, v1:selections[0].get('version'), v2:selections[1].get('version')};    
        GRS.dispatcher.dispatch("timeMachine/compare?view=true", p, function(x) {
            this.xform = x.form;
            this._resizeCompareWin.call(this);
            this.compareWin.show();
            GRS.form.FormProcessor.addForms2ComparePanels(this.compareWin, this.comparePanel1, this.comparePanel2, x);    
        }, this);    
    }    
});