Browse Source

版式正文痕迹保留修改

huqi 5 năm trước cách đây
mục cha
commit
82fb90c84b
18 tập tin đã thay đổi với 867 bổ sung160 xóa
  1. 34 5
      o2web/source/o2_core/o2/o2.more.js
  2. 1 0
      o2web/source/o2_core/o2/xDesktop/WebSocket.js
  3. 1 1
      o2web/source/o2_lib/diff-match-patch/diff_match_patch_uncompressed.js
  4. 19 0
      o2web/source/x_component_process_Xform/$Form/default/doc.wcss
  5. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/exit.png
  6. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/next.png
  7. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/next_gray.png
  8. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/pause.png
  9. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/pause_gray.png
  10. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/play.png
  11. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/play_gray.png
  12. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/prev.png
  13. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/prev_gray.png
  14. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/stop.png
  15. BIN
      o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/stop_gray.png
  16. 71 153
      o2web/source/x_component_process_Xform/Documenteditor.js
  17. 16 1
      o2web/source/x_component_process_Xform/lp/zh-cn.js
  18. 725 0
      o2web/source/x_component_process_Xform/widget/DocumentHistory.js

+ 34 - 5
o2web/source/o2_core/o2/o2.more.js

@@ -219,15 +219,18 @@
     });
     });
     if (window.Element && Element.implement) Element.implement({
     if (window.Element && Element.implement) Element.implement({
         "isIntoView": function() {
         "isIntoView": function() {
-            var pNode = this.getParent();
-            while (pNode && ((pNode.getScrollSize().y-(pNode.getComputedSize().height+1)<=0) || pNode.getStyle("overflow")==="visible")) pNode = pNode.getParent();
+            // var pNode = this.getParent();
+            // while (pNode && ((pNode.getScrollSize().y-(pNode.getComputedSize().height+1)<=0) || pNode.getStyle("overflow")==="visible")) pNode = pNode.getParent();
+            //
+            var pNode = this.getParentSrcollNode();
 
 
             if (!pNode) pNode = document.body;
             if (!pNode) pNode = document.body;
             var size = pNode.getSize();
             var size = pNode.getSize();
             var srcoll = pNode.getScroll();
             var srcoll = pNode.getScroll();
             var p = (pNode == window) ? {"x":0, "y": 0} : this.getPosition(pNode);
             var p = (pNode == window) ? {"x":0, "y": 0} : this.getPosition(pNode);
             var nodeSize = this.getSize();
             var nodeSize = this.getSize();
-            return (p.x-srcoll.x>=0 && p.y-srcoll.y>=0) && (p.x+nodeSize.x<size.x+srcoll.x && p.y+nodeSize.y<size.y+srcoll.y)
+            //return (p.x-srcoll.x>=0 && p.y-srcoll.y>=0) && (p.x+nodeSize.x<size.x+srcoll.x && p.y+nodeSize.y<size.y+srcoll.y);
+            return (p.x-srcoll.x>=0 && p.y>=0) && (p.x+nodeSize.x<size.x+srcoll.x && p.y+nodeSize.y<size.y)
         },
         },
         "appendHTML": function(html, where){
         "appendHTML": function(html, where){
             if (this.insertAdjacentHTML){
             if (this.insertAdjacentHTML){
@@ -417,13 +420,39 @@
                 "onClick": click
                 "onClick": click
             });
             });
         },
         },
+        "scrollIn": function(where){
+            var wh = (where) ? where.toString().toLowerCase() : "center";
+
+            if (Browser.name=="ie" || Browser.name=="safari"){
+                var scrollNode = this.getParentSrcollNode();
+                var scrollFx = new Fx.Scroll(scrollNode);
+                var scroll = scrollNode.getScroll();
+                var size = scrollNode.getSize();
+                var thisSize = this.getComputedSize();
+                var p = this.getPosition(scrollNode);
+
+                if (wh=="start"){
+                    var top = 0;
+                    scrollFx.start(scroll.x, p.y-top+scroll.y);
+                }else if (wh=="end"){
+                    var bottom = size.y-thisSize.totalHeight;
+                    scrollFx.start(scroll.x, p.y-bottom+scroll.y);
+                }else{
+                    var center = size.y/2-thisSize.totalHeight/2;
+                    scrollFx.start(scroll.x, p.y-center+scroll.y);
+                }
+            }else{
+                if (wh!=="start" && wh!=="end") wh = "center"
+                this.scrollIntoView({"behavior": "smooth", "block": wh, "inline": "nearest"});
+            }
+        },
         scrollToNode: function(el, where){
         scrollToNode: function(el, where){
             var scrollSize = this.getScrollSize();
             var scrollSize = this.getScrollSize();
             if (!scrollSize.y) return true;
             if (!scrollSize.y) return true;
             var wh = (where) ? where.toString().toLowerCase() : "bottom";
             var wh = (where) ? where.toString().toLowerCase() : "bottom";
             var node = $(el);
             var node = $(el);
-            var size = el.getComputedSize();
-            var p = el.getPosition(this);
+            var size = node.getComputedSize();
+            var p = node.getPosition(this);
             var thisSize = this.getComputedSize();
             var thisSize = this.getComputedSize();
             var scroll = this.getScroll();
             var scroll = this.getScroll();
             if (wh==="top"){
             if (wh==="top"){

+ 1 - 0
o2web/source/o2_core/o2/xDesktop/WebSocket.js

@@ -56,6 +56,7 @@ MWF.xDesktop.WebSocket = new Class({
             }catch(e){
             }catch(e){
                 //WebSocket.close();
                 //WebSocket.close();
                 //this.webSocket = new WebSocket(this.ws);
                 //this.webSocket = new WebSocket(this.ws);
+                this.errorCount++;
                 console.log("Unable to connect to the websocket server, will retry in "+(this.checkingTimeout/1000)+" seconds");
                 console.log("Unable to connect to the websocket server, will retry in "+(this.checkingTimeout/1000)+" seconds");
                 this.checkRetry();
                 this.checkRetry();
                 // if (this.webSocket){
                 // if (this.webSocket){

+ 1 - 1
o2web/source/o2_lib/diff-match-patch/diff_match_patch_uncompressed.js

@@ -1901,7 +1901,7 @@ diff_match_patch.prototype.patch_apply = function(patches, text) {
               text = text.substring(0, start_loc + index2) + mod[1] +
               text = text.substring(0, start_loc + index2) + mod[1] +
                      text.substring(start_loc + index2);
                      text.substring(start_loc + index2);
             } else if (mod[0] === DIFF_DELETE) {  // Deletion
             } else if (mod[0] === DIFF_DELETE) {  // Deletion
-              text = text.substring(0, start_loc + index2) +
+              text = text.substring(0, start_loc + index2) + mod[1] +
                      text.substring(start_loc + this.diff_xIndex(diffs,
                      text.substring(start_loc + this.diff_xIndex(diffs,
                          index1 + mod[1].length));
                          index1 + mod[1].length));
             }
             }

+ 19 - 0
o2web/source/x_component_process_Xform/$Form/default/doc.wcss

@@ -138,6 +138,25 @@
         "line-height": "20px",
         "line-height": "20px",
         "font-size": "12px",
         "font-size": "12px",
         "overflow": "hidden"
         "overflow": "hidden"
+    },
+    "historyInforNode": {
+        "width": "300px",
+        "padding": "10px",
+        "overflow": "hidden",
+        "border": "1px solid #CCCCCC",
+        "border-radius": "5px",
+        "box-shadow": "2px 2px 5px #CCCCCC",
+        "position": "absolute",
+        "opacity": 1
+    },
+    "historyListAreaNode": {
+        "width": "260px",
+        "float": "right",
+        "height": "500px",
+        "background-color": "#f3f3f3",
+        "border-left": "1px solid #cccccc"
+    },
+    "historyListTitleAreaNode":{
     }
     }
     
     
 }
 }

BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/exit.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/next.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/next_gray.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/pause.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/pause_gray.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/play.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/play_gray.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/prev.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/prev_gray.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/stop.png


BIN
o2web/source/x_component_process_Xform/$Form/default/documenteditoricon/stop_gray.png


+ 71 - 153
o2web/source/x_component_process_Xform/Documenteditor.js

@@ -3,6 +3,18 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
     Extends: MWF.APP$Module,
     Extends: MWF.APP$Module,
     options: {
     options: {
         "moduleEvents": ["load", "queryLoad", "beforeLoad", "postLoad", "afterLoad", "loadPage"],
         "moduleEvents": ["load", "queryLoad", "beforeLoad", "postLoad", "afterLoad", "loadPage"],
+        "historyColors": [
+            "#d62728",
+            "#1f77b4",
+            "#ff7f0e",
+            "#2ca02c",
+            "#8c564b",
+            "#9467bd",
+            "#17becf",
+            "#e377c2",
+            "#bcbd22",
+            "#ff9896"
+        ],
         "docPageHeight": 850.4,
         "docPageHeight": 850.4,
         "docPageFullWidth": 794,
         "docPageFullWidth": 794,
         "pageShow": "single"
         "pageShow": "single"
@@ -94,7 +106,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
         }
         }
     },
     },
     _createPage: function(callback){
     _createPage: function(callback){
-        debugger;
         var pageContentNode = this._createNewPage().getFirst();
         var pageContentNode = this._createNewPage().getFirst();
 
 
         var control = this.getShowControl();
         var control = this.getShowControl();
@@ -443,7 +454,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
     },
     },
 
 
     reSetShow: function(control){
     reSetShow: function(control){
-        debugger;
         if (!control) control = this.getShowControl();
         if (!control) control = this.getShowControl();
         var m = function(s){ return (control[s]) ? "show" : "hide"; }
         var m = function(s){ return (control[s]) ? "show" : "hide"; }
 
 
@@ -481,7 +491,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
         if (this.layout_issuanceDate) this.layout_issuanceDate[m("issuanceDate")]();
         if (this.layout_issuanceDate) this.layout_issuanceDate[m("issuanceDate")]();
         if (this.layout_annotation) this.layout_annotation[m("annotation")]();
         if (this.layout_annotation) this.layout_annotation[m("annotation")]();
 
 
-        debugger;
         if ((!control.copyto || !this.layout_copytoContent) && (!control.copyto2 || !this.layout_copyto2Content)  && (!control.editionUnit || !this.layout_edition_issuance_unit) && (!control.editionDate || !this.layout_edition_issuance_date)){
         if ((!control.copyto || !this.layout_copytoContent) && (!control.copyto2 || !this.layout_copyto2Content)  && (!control.editionUnit || !this.layout_edition_issuance_unit) && (!control.editionDate || !this.layout_edition_issuance_date)){
             if (this.layout_editionArea) this.layout_editionArea.hide();
             if (this.layout_editionArea) this.layout_editionArea.hide();
         }else{
         }else{
@@ -509,7 +518,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
                 // });
                 // });
             }
             }
             if ((!control.editionUnit || !this.layout_edition_issuance_unit) && (!control.editionDate || !this.layout_edition_issuance_date)){
             if ((!control.editionUnit || !this.layout_edition_issuance_unit) && (!control.editionDate || !this.layout_edition_issuance_date)){
-                debugger
                 if (this.layout_editionArea && (this.layout_edition_issuance_date || this.layout_edition_issuance_unit)){
                 if (this.layout_editionArea && (this.layout_edition_issuance_date || this.layout_edition_issuance_unit)){
                     var trs = this.layout_editionArea.getElement("table").rows;
                     var trs = this.layout_editionArea.getElement("table").rows;
                     trs.item(trs.length-1).destroy();
                     trs.item(trs.length-1).destroy();
@@ -638,15 +646,15 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
                 this._doublePage();
                 this._doublePage();
             }
             }
 
 
-            // this.form.addEvent("beforeProcess", function(){
-            //     this.resetData();
-            //     if (this.checkSaveNewEdition()) this.saveNewDataEdition();
-            //     this.notSaveResetData = true;
-            // }.bind(this));
-            this.form.addEvent("beforeSave", function(){
+            this.form.addEvent("beforeProcess", function(){
                 this.resetData();
                 this.resetData();
                 if (this.checkSaveNewEdition()) this.saveNewDataEdition();
                 if (this.checkSaveNewEdition()) this.saveNewDataEdition();
-                //if (!this.notSaveResetData) this.resetData();
+                this.notSaveResetData = true;
+            }.bind(this));
+            this.form.addEvent("beforeSave", function(){
+                // this.resetData();
+                // if (this.checkSaveNewEdition()) this.saveNewDataEdition();
+                if (!this.notSaveResetData) this.resetData();
             }.bind(this));
             }.bind(this));
 
 
             if (this.json.toWord=="y"){
             if (this.json.toWord=="y"){
@@ -656,7 +664,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
             }
             }
             if (!layout.mobile) this.loadSideToolbar();
             if (!layout.mobile) this.loadSideToolbar();
 
 
-            debugger;
             var id = this.form.businessData.data["$work"].job;
             var id = this.form.businessData.data["$work"].job;
             o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.listWithJobCategory(id, this.json.id, function(json){
             o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.listWithJobCategory(id, this.json.id, function(json){
                 this.historyDocumentList = json.data;
                 this.historyDocumentList = json.data;
@@ -681,7 +688,7 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
         //     return true;
         //     return true;
         // }
         // }
         debugger;
         debugger;
-        if (this.allowEdit) if (!this.prevHistoryData || (this.prevHistoryData != this.data.filetext)) return true;
+        if (this.allowEdit && this.data.filetext && (this.data.filetext != this.json.defaultValue.filetext)) if (!this.prevHistoryData || (this.prevHistoryData != this.data.filetext)) return true;
         return false;
         return false;
     },
     },
     saveNewDataEdition: function(callback){
     saveNewDataEdition: function(callback){
@@ -703,15 +710,38 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
             var editionData = {"category": this.json.id, "data": data };
             var editionData = {"category": this.json.id, "data": data };
 
 
             o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.create(this.form.businessData.work.id, editionData, function(json){
             o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.create(this.form.businessData.work.id, editionData, function(json){
+                this.prevHistoryData = this.data.filetext
                 if (callback) callback();
                 if (callback) callback();
-            });
+            }.bind(this));
         }
         }
 
 
         //
         //
         // if (!this.data.editions) this.data.editions = [];
         // if (!this.data.editions) this.data.editions = [];
         // this.data.editions.push(editionData);
         // this.data.editions.push(editionData);
     },
     },
-
+    resizeToolbar: function(){
+        if (this.toolbarNode){
+            var p = this.toolNode.getPosition(this.form.app.content);
+            var size = this.toolNode.getSize();
+            var pl = this.toolbarNode.getStyle("padding-left").toInt();
+            var pr = this.toolbarNode.getStyle("padding-right").toInt();
+            var x = size.x-pl-pr;
+
+            if (p.y<0){
+                this.toolbarNode.inject(this.form.node);
+                this.toolbarNode.setStyles({
+                    "position": "absolute",
+                    "width": ""+x+"px",
+                    "z-index": 20000,
+                    "top": "0px",
+                    "left": ""+p.x+"px"
+                });
+            }else{
+                this.toolbarNode.inject(this.toolNode);
+                this.toolbarNode.setStyles({"position": "static"});
+            }
+        }
+    },
     resizeSidebar: function(){
     resizeSidebar: function(){
         if (this.sidebarNode){
         if (this.sidebarNode){
             var fileTextNode = this.contentNode.getElement("div.doc_layout_filetext");
             var fileTextNode = this.contentNode.getElement("div.doc_layout_filetext");
@@ -786,7 +816,7 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
         offset = 0;
         offset = 0;
         if (this.pages.length){
         if (this.pages.length){
             var pageSize = this.pages[0].getSize();
             var pageSize = this.pages[0].getSize();
-            var contentSize = this.node.getSize();
+            var contentSize = this.contentNode.getSize();
             var contentWidth = (offset) ? contentSize.x-20-offset : contentSize.x-20;
             var contentWidth = (offset) ? contentSize.x-20-offset : contentSize.x-20;
             if (contentWidth<pageSize.x){
             if (contentWidth<pageSize.x){
                 this.isScale = true;
                 this.isScale = true;
@@ -801,6 +831,7 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
         if (scale) this.scale = scale;
         if (scale) this.scale = scale;
 
 
         var w = this.node.getSize().x;
         var w = this.node.getSize().x;
+        if (this.history && this.history.historyListAreaNode) w = w-this.history.historyListAreaNode.getComputedSize().totalWidth-2;
         w = w/this.scale;
         w = w/this.scale;
         this.contentNode.setStyles({
         this.contentNode.setStyles({
             "transform":"scale("+this.scale+")",
             "transform":"scale("+this.scale+")",
@@ -848,147 +879,33 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
         }.bind(this), "$doc.doc");
         }.bind(this), "$doc.doc");
     },
     },
     _historyDoc: function(){
     _historyDoc: function(){
-
-        // this.historyAreaActionNode = new Element("div", {"styles": this.css.historyAreaActionNode}).inject(this.historyAreaNode);
-        // this.historyAreaTitleNode = new Element("div", {"styles": this.css.historyAreaTitleNode, "text": MWF.xApplication.process.Xform.LP.documentEditor.historyList}).inject(this.historyAreaNode);
-        // this.historyAreaContentNode = new Element("div", {"styles": this.css.historyAreaContentNode}).inject(this.historyAreaNode);
-        //
-        // var id = this.form.businessData.data["$work"].job;
-        // o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.listWithJob(id, function(json){
-        //     json.data.each(function(d){
-        //         var title = o2.name.cn(d.person) + "(" + d.activityName + ")";
-        //         var time = d.createTime;
-        //         var node = new Element("div", {"styles": this.css.historyItemNode}).inject(this.historyAreaContentNode);
-        //         var titleNode = new Element("div", {"styles": this.css.historyItemTitleNode, "text": title}).inject(node);
-        //         var timeNode = new Element("div", {"styles": this.css.historyItemTimeNode, "text": time}).inject(node);
-        //     }.bind(this));
-        // }.bind(this));
-        //
-
-        //this.contentNode.hide();
-
-        //this.historyAreaNode = new Element("div", {"styles": this.css.doc_content}).inject(this.contentNode, "after");
-        //var size = this.node.getSize();
-        //this.historyAreaNode.setStyle("height", ""+size.y+"px");
-
-        debugger;
-        //if (this.layout_filetext) currentData = this.layout_filetext.get("text");
-        this.resetData();
-        var currentData = {
-            "data": this.data.filetext,
-            "person": layout.session.user.distinguishedName,
-            "activityName": this.form.businessData.activity.name,
-            "createTime" : (new Date()).format("db")
-        }
-
-        this.getHistroyDocumentList(function(){
-            if (this.historyDocumentList && this.historyDocumentList.length){
-                this.getHistroyDocumentData(this.historyDocumentList[0].id, function(historyData){
-                    this.diffHistroy(historyData.data, currentData.data, function(diff_ds){
-                        this.resetData(diff_ds);
-
-                        if (this.layout_filetext){
-                            var insList = this.layout_filetext.getElements("ins");
-                            var delList = this.layout_filetext.getElements("del");
-
-                            var insTitle = o2.name.cn(currentData.person)+" 添加的内容\n"+currentData.createTime;
-                            insList.set("title", insTitle);
-                            var delTitle = o2.name.cn(currentData.person)+" 删除的内容\n"+currentData.createTime
-                            delList.set("title", delTitle);
-                            // insList.addEvents({
-                            //     "mouseover": function(){alert()}
-                            // })
-                        }
-
-                    }.bind(this));
-                }.bind(this))
-            }
+        this.getHistory(function(){
+            //this.history.play();
         }.bind(this));
         }.bind(this));
     },
     },
-    diffHistroy: function(earlyData, laterData, callback){
-        o2.load("/o2_lib/diff-match-patch/diff_match_patch_uncompressed.js", function(){
-            diff_match_patch.prototype.diff_prettyHtml = function(diffs) {
-                var html = [];
-                var pattern_amp = /&/g;
-                var pattern_lt = /</g;
-                var pattern_gt = />/g;
-                var pattern_para = /\n/g;
-                for (var x = 0; x < diffs.length; x++) {
-                    var op = diffs[x][0];    // Operation (insert, delete, equal)
-                    var data = diffs[x][1];  // Text of change.
-                    // var text = data.replace(pattern_amp, '&amp;').replace(pattern_lt, '&lt;')
-                    //     .replace(pattern_gt, '&gt;').replace(pattern_para, '&para;<br>');
-                    var text = data;
-                    switch (op) {
-                        case DIFF_INSERT:
-                            html[x] = '<ins style="background:#e6ffe6; color:green">' + text + '</ins>';
-                            break;
-                        case DIFF_DELETE:
-                            html[x] = '<del style="background:#ffe6e6; color:red">' + text + '</del>';
-                            break;
-                        case DIFF_EQUAL:
-                            html[x] = '<span>' + text + '</span>';
-                            break;
-                    }
-                }
-                return html.join('');
-            };
-
-            var dmp = new diff_match_patch();
-            dmp.Diff_Timeout = parseFloat(10);
-            dmp.Diff_EditCost = parseFloat(4);
-            // var historyDataText = this.htmlToText(historyData);
-            // var currentDataText = this.htmlToText(currentData);
-            // var historyDataText = (historyData);
-            // var currentDataText = (currentData);
-            var diff_d = dmp.diff_main(earlyData, laterData);
-            dmp.diff_cleanupSemantic(diff_d);
-            var patch_list = dmp.patch_make(earlyData, laterData, diff_d);
-
-            var data = earlyData;
-            if (patch_list.length){
-                patch_list.each(function(patch){
-                    patch.start1;
-                    patch.start2;
-                    patch.length1;
-                    patch.length2;
-                    patch.diffs;
-
-                    var left = data.substring(0,patch.start1);
-                    var middle = data.substring(patch.start1, patch.length1);
-                    var right = data.substring(patch.start1+patch.length1, data.length);
-
+    getHistory: function(callback){
+        if (this.history){
+            this.history.active(function(){
+                if (callback) callback();
+            });
+        }else{
+            MWF.xDesktop.requireApp("process.Xform", "widget.DocumentHistory", function(){
+                this.history = new MWF.xApplication.process.Xform.widget.DocumentHistory(this);
+                this.history.load(function(){
+                    if (callback) callback();
+                });
+            }.bind(this));
+        }
+    },
 
 
-                }.bind(this));
-            }
 
 
-            //var diff_ds = dmp.diff_prettyHtml(diff_d);
-            if (callback) callback(diff_ds);
-        }.bind(this));
-    },
     htmlToText: function(html){
     htmlToText: function(html){
         var tmpdiv = new Element("div", {"html": html});
         var tmpdiv = new Element("div", {"html": html});
         var text = tmpdiv.get("text");
         var text = tmpdiv.get("text");
         tmpdiv.destroy();
         tmpdiv.destroy();
         return text;
         return text;
     },
     },
-    getHistroyDocumentData: function(id, callback){
-        o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.get(id, function(json){
-            if (callback) callback(json.data);
-        }.bind(this));
-    },
-    getHistroyDocumentList: function(callback){
-        if (!this.historyDocumentList){
-            //var id = this.form.businessData.data["$work"].job;
-            var id = this.form.businessData.work.job;
-            o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.listWithJobCategory(id, this.json.id, function(json){
-                this.historyDocumentList = json.data;
-                if (callback) callback();
-            }.bind(this));
-        }else{
-            if (callback) callback();
-        }
-    },
+
 
 
     _readFiletext: function(){
     _readFiletext: function(){
         //this._returnScale();
         //this._returnScale();
@@ -1039,7 +956,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
     _createEditor: function(inline){
     _createEditor: function(inline){
         if (this.allowEdit){
         if (this.allowEdit){
             this.loadCkeditorFiletext(function(e){
             this.loadCkeditorFiletext(function(e){
-                debugger;
                 e.editor.focus();
                 e.editor.focus();
                 e.editor.getSelection().scrollIntoView();
                 e.editor.getSelection().scrollIntoView();
 
 
@@ -1198,6 +1114,13 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
             this.toolbar.load();
             this.toolbar.load();
         }.bind(this));
         }.bind(this));
 
 
+        this.scrollNode = this.toolbarNode.getParentSrcollNode();
+        if (this.scrollNode){
+            this.scrollNode.addEvent("scroll", function(){
+                this.resizeToolbar();
+            }.bind(this));
+        }
+
         this.doublePageAction = new Element("div", {"styles": this.css.doc_toolbar_doublePage, "text": MWF.xApplication.process.Xform.LP.doublePage}).inject(this.toolbarNode);
         this.doublePageAction = new Element("div", {"styles": this.css.doc_toolbar_doublePage, "text": MWF.xApplication.process.Xform.LP.doublePage}).inject(this.toolbarNode);
         this.doublePageAction.addEvent("click", function(){
         this.doublePageAction.addEvent("click", function(){
             if (this.options.pageShow!=="double"){
             if (this.options.pageShow!=="double"){
@@ -1284,7 +1207,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
         });
         });
     },
     },
     createWaitSplitPage: function(){
     createWaitSplitPage: function(){
-        debugger;
         this.node.mask({
         this.node.mask({
             "style": {
             "style": {
                 "background-color": "#cccccc",
                 "background-color": "#cccccc",
@@ -1761,7 +1683,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
                             this.data[name] = tmpStrs.join(",");
                             this.data[name] = tmpStrs.join(",");
                             break;
                             break;
                         case "mainSend":
                         case "mainSend":
-                            debugger;
                             this.data[name] = strs.join(",") + ":";
                             this.data[name] = strs.join(",") + ":";
                             break;
                             break;
                         default:
                         default:
@@ -1789,8 +1710,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
                 }
                 }
                 break;
                 break;
             case "script":
             case "script":
-                debugger;
-
                 if (this.json[scriptItem] && this.json[scriptItem].code){
                 if (this.json[scriptItem] && this.json[scriptItem].code){
                     var v = this.form.Macro.exec(this.json[scriptItem].code, this);
                     var v = this.form.Macro.exec(this.json[scriptItem].code, this);
                     this.data[name] = v;
                     this.data[name] = v;
@@ -1924,7 +1843,6 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
     },
     },
     setData: function(data, diffFiletext){
     setData: function(data, diffFiletext){
         if (data){
         if (data){
-            debugger;
             this.data = data;
             this.data = data;
             // this.data["$json"] = this.json;
             // this.data["$json"] = this.json;
             this._setBusinessData(data);
             this._setBusinessData(data);

+ 16 - 1
o2web/source/x_component_process_Xform/lp/zh-cn.js

@@ -156,7 +156,7 @@ MWF.xApplication.process.Xform.LP = {
     "editdoc": "编辑正文",
     "editdoc": "编辑正文",
     "editdocCompleted": "编辑完成",
     "editdocCompleted": "编辑完成",
     "printdoc": "打印正文",
     "printdoc": "打印正文",
-    "history": "正文痕迹",
+    "history": "正文痕迹审查",
 
 
     "subformNestedError" : "该表单存在相互嵌套的子表单,请联系管理员!",
     "subformNestedError" : "该表单存在相互嵌套的子表单,请联系管理员!",
     "subpageNestedError" : "该页面存在相互嵌套的子页面,请联系管理员!",
     "subpageNestedError" : "该页面存在相互嵌套的子页面,请联系管理员!",
@@ -197,6 +197,21 @@ MWF.xApplication.process.Xform.LP = {
         "editionUnit":"[印发机关]",
         "editionUnit":"[印发机关]",
         "editionDate":"[印发日期]",
         "editionDate":"[印发日期]",
         "historyList": "历史版本文档"
         "historyList": "历史版本文档"
+    },
+    "documentHistory": {
+        "diffContent": "<div>{time}</div>{name} 在 ”{activity}“ 时修改的内容",
+        "insertContent": "<div>{time}</div>{name} 在 ”{activity}“ 时插入的内容:",
+        "deleteContent": "<div>{time}</div>{name} 在 ”{activity}“ 时删除的内容:",
+        "insert": "插入了",
+        "delete": "删除了",
+        "play": "修改记录回放",
+        "pause": "暂停回放",
+        "stop": "停止修改记录回放",
+        "next": "下一个修改记录",
+        "prev": "上一个修改记录",
+        "exit": "退出痕迹审查",
+        "diff_patch_count": "共有{history}个历史版本,{diff}处修订。",
+        "original": "原始版本"
     }
     }
 
 
 };
 };

+ 725 - 0
o2web/source/x_component_process_Xform/widget/DocumentHistory.js

@@ -0,0 +1,725 @@
+MWF.xApplication.process.Xform.widget = MWF.xApplication.process.Xform.widget || {};
+MWF.xApplication.process.Xform.widget.DocumentHistory = new Class({
+    Implements: [Options, Events],
+    options: {
+        "speed": 1,
+        "fxTime": 500,
+        "inforTime": 2000
+    },
+    initialize: function(documentEditor, options){
+        this.setOptions(options);
+        this.documentEditor = documentEditor;
+        this.css = this.documentEditor.css;
+    },
+    load: function(callback){
+        this.getHistroyDocumentList(function(){
+            if (this.historyDocumentList && this.historyDocumentList.length){
+                this.getHistoryDataList(function(){
+                    this.createHistoryToolbar();
+                    this.createHistoryListNode();
+
+                    this.documentEditor.options.pageShow = "single";
+                    this.documentEditor.resetData();
+
+                    this.beginDiffHistory(function(){
+                        this.loadHistoryToolbar();
+                        this.loadHistoryList();
+
+                        if (callback) callback();
+                    }.bind(this));
+                }.bind(this));
+            }
+        }.bind(this));
+    },
+    createHistoryToolbar: function(){
+        this.documentEditor.documentToolbarNode = this.documentEditor.toolbarNode;
+        this.toolbarNode = this.documentEditor.toolbarNode.clone(true);
+        this.toolbarNode.inject(this.documentEditor.toolbarNode, "after");
+        this.documentEditor.toolbarNode = this.toolbarNode;
+        this.documentEditor.documentToolbarNode.hide();
+        this.toolbarNode.empty();
+        if (this.documentEditor.sidebarNode) this.documentEditor.sidebarNode.hide();
+    },
+
+    loadHistoryToolbar: function(){
+        var html = "<span MWFnodetype=\"MWFToolBarButton\" MWFButtonImage=\"/x_component_process_Xform/$Form/default/documenteditoricon/play.png\" title=\""+MWF.xApplication.process.Xform.LP.documentHistory.play+"\" MWFButtonAction=\"play\"></span>";
+        html += "<span MWFnodetype=\"MWFToolBarButton\" MWFButtonImage=\"/x_component_process_Xform/$Form/default/documenteditoricon/pause.png\" title=\""+MWF.xApplication.process.Xform.LP.documentHistory.pause+"\" MWFButtonAction=\"pause\"></span>";
+        html += "<span MWFnodetype=\"MWFToolBarButton\" MWFButtonImage=\"/x_component_process_Xform/$Form/default/documenteditoricon/stop.png\" title=\""+MWF.xApplication.process.Xform.LP.documentHistory.stop+"\" MWFButtonAction=\"stopPlay\"></span>";
+        html += "<span MWFnodetype=\"MWFToolBarSeparator\"></span>";
+        html += "<span MWFnodetype=\"MWFToolBarButton\" MWFButtonImage=\"/x_component_process_Xform/$Form/default/documenteditoricon/prev.png\" title=\""+MWF.xApplication.process.Xform.LP.documentHistory.prev+"\" MWFButtonAction=\"prev\"></span>";
+        html += "<span MWFnodetype=\"MWFToolBarButton\" MWFButtonImage=\"/x_component_process_Xform/$Form/default/documenteditoricon/next.png\" title=\""+MWF.xApplication.process.Xform.LP.documentHistory.next+"\" MWFButtonAction=\"next\"></span>";
+        html += "<span MWFnodetype=\"MWFToolBarSeparator\"></span>";
+        html += "<span MWFnodetype=\"MWFToolBarButton\" MWFButtonImage=\"/x_component_process_Xform/$Form/default/documenteditoricon/exit.png\" title=\""+MWF.xApplication.process.Xform.LP.documentHistory.exit+"\" MWFButtonAction=\"exit\" MWFButtonText=\""+MWF.xApplication.process.Xform.LP.documentHistory.exit+"\"></span>";
+        html += "<span MWFnodetype=\"MWFToolBarSeparator\"></span>";
+
+        var text = MWF.xApplication.process.Xform.LP.documentHistory.diff_patch_count;
+        text = text.replace(/{history}/, this.historyDataList.length).replace(/{diff}/, this.diffCount);
+
+        html += "<span style='float: left; line-height: 24px; color: #666666; margin-left: 10px'>"+text+"</span>";
+
+        this.toolbarNode.set("html", html);
+
+        MWF.require("MWF.widget.Toolbar", function() {
+            this.toolbar = new MWF.widget.Toolbar(this.toolbarNode, {"style": "documentEdit"}, this);
+            this.toolbar.load();
+            this.checkToolbar();
+        }.bind(this));
+    },
+    checkToolbar: function(){
+        if (this.toolbar){
+            if (this.playing){
+                if (this.stop){
+                    this.toolbar.childrenButton[0].enable();
+                    this.toolbar.childrenButton[1].disable();
+
+                    if (this.patchIndex==0 && this.diffIndex==0){
+                        this.toolbar.childrenButton[3].disable();
+                        if (this.diffPatch.length) this.toolbar.childrenButton[4].enable();
+                    }else{
+                        if (this.patchIndex<this.diffPatch.length-1){
+                            this.toolbar.childrenButton[3].enable();
+                            this.toolbar.childrenButton[4].enable();
+                        }else if (this.patchIndex<this.diffPatch.length && this.diffIndex < this.diffPatch[this.patchIndex].patch.diffs.length){
+                            this.toolbar.childrenButton[3].enable();
+                            this.toolbar.childrenButton[4].enable();
+                        }else{
+                            if (this.diffPatch.length) this.toolbar.childrenButton[3].enable();
+                            this.toolbar.childrenButton[4].disable();
+                        }
+                    }
+                }else{
+                    this.toolbar.childrenButton[0].disable();
+                    this.toolbar.childrenButton[1].enable();
+
+                    this.toolbar.childrenButton[3].disable();
+                    this.toolbar.childrenButton[4].disable();
+                }
+                this.toolbar.childrenButton[2].enable();
+
+            }else{
+                this.toolbar.childrenButton[0].enable();
+                this.toolbar.childrenButton[1].disable();
+                this.toolbar.childrenButton[2].disable();
+
+                if (this.patchIndex==0 && this.diffIndex==0){
+                    this.toolbar.childrenButton[3].disable();
+                    if (this.diffPatch.length) this.toolbar.childrenButton[4].enable();
+                }else{
+                    if (this.patchIndex<this.diffPatch.length-1){
+                        this.toolbar.childrenButton[3].enable();
+                        this.toolbar.childrenButton[4].enable();
+                    }else if (this.patchIndex<this.diffPatch.length && this.diffIndex < this.diffPatch[this.patchIndex].patch.diffs.length){
+                        this.toolbar.childrenButton[3].enable();
+                        this.toolbar.childrenButton[4].enable();
+                    }else{
+                        if (this.diffPatch.length) this.toolbar.childrenButton[3].enable();
+                        this.toolbar.childrenButton[4].disable();
+                    }
+                }
+            }
+        }
+    },
+    createHistoryListNode: function(){
+        this.historyListAreaNode = new Element("div", {"styles": this.css.historyListAreaNode}).inject(this.documentEditor.contentNode, "before");
+        this.documentEditor.contentNode.setStyle("width", "auto");
+        this.documentEditor.zoom(1);
+        this.documentEditor._checkScale();
+
+        var size = this.documentEditor.node.getSize();
+        var toolbarSize = this.documentEditor.toolbarNode.getSize();
+        var h = size.y-toolbarSize.y;
+        this.historyListAreaNode.setStyle("height", ""+h+"px");
+
+        this.historyListTitleAreaNode = new Element("div", {"styles": this.css.historyListTitleAreaNode}).inject(this.historyListAreaNode);
+        this.historyListContentAreaNode = new Element("div", {"styles": this.css.historyListContentAreaNode}).inject(this.historyListAreaNode);
+    },
+    loadHistoryList: function(){
+        var original = this.historyDataList[0];
+        this.diffPatch.each();
+    },
+    createHistoryListItem: function(){
+
+    },
+
+
+    getHistoryDataList: function(callback){
+        if (this.documentEditor.historyDataList){
+            this.getHistoryDataListFinish(this.documentEditor.historyDataList);
+            if (callback) callback();
+        }else{
+            var historyDataList = [];
+            var getDataCount = 0;
+            var idx = 0;
+
+            var checkBeginDiffHistory = function(){
+                if (getDataCount>=this.historyDocumentList.length){
+                    this.getHistoryDataListFinish(historyDataList);
+                    if (callback) callback();
+                }
+            }.bind(this);
+
+            for (var i=this.historyDocumentList.length-1; i>=0; i--){
+                historyDataList.push(null);
+                this.getHistroyDocumentData(this.historyDocumentList[i].id, function(){
+                    getDataCount++;
+                    checkBeginDiffHistory();
+                }.bind(this), idx, historyDataList);
+                idx++;
+            }
+        }
+    },
+    getHistoryDataListFinish: function(historyDataList){
+        this.documentEditor.historyDataList = historyDataList;
+        this.historyDataList = historyDataList;
+        var currentData = {
+            "data": this.documentEditor.data.filetext,
+            "person": layout.session.user.distinguishedName,
+            "activityName": this.documentEditor.form.businessData.activity.name,
+            "createTime" : (new Date()).format("db")
+        }
+        this.historyDataList.push(currentData);
+    },
+    getHistroyDocumentData: function(id, callback, i, historyDataList){
+        o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.get(id, function(json){
+            if (historyDataList) historyDataList[i] = json.data;
+            if (callback) callback(json.data);
+        }.bind(this));
+    },
+    getHistroyDocumentList: function(callback){
+        if (!this.documentEditor.historyDocumentList){
+            var id = this.documentEditor.form.businessData.work.job;
+            o2.Actions.load("x_processplatform_assemble_surface").DocumentVersionAction.listWithJobCategory(id, this.json.id, function(json){
+                this.historyDocumentList = json.data;
+                this.documentEditor.historyDocumentList = json.data;
+                if (callback) callback();
+            }.bind(this));
+        }else{
+            this.historyDocumentList = this.documentEditor.historyDocumentList;
+            if (callback) callback();
+        }
+    },
+
+    beginDiffHistory: function(callback){
+        o2.load("/o2_lib/diff-match-patch/diff_match_patch_uncompressed.js", function(){
+            this.initAnimation();
+            if (callback) callback();
+        }.bind(this));
+    },
+    initAnimation: function(){
+        this.diffPatch =  this.diffHistroy();
+        this.diffCount = 0;
+        this.diffPatch.each(function(patch){
+            patch.patch.diffs.each(function(diff){
+                if (diff[0]!=0) this.diffCount++;
+            }.bind(this));
+        }.bind(this));
+
+        // this.initData();
+        // this.initAnimationStatus();
+    },
+    initData: function(){
+        this.currentHistoryData = this.historyDataList[0].data;
+        this.documentEditor.layout_filetext.set("html", this.currentHistoryData);
+    },
+    initAnimationStatus: function(){
+        this.patchIndex = 0;
+        this.diffIndex = 0;
+        this.currentDiffs = null;
+        this.stop = false;
+        this.step = false;
+        this.playing = false;
+        this.reverse = false;
+        this.options.fxTime = 500;
+        this.options.inforTime = 2000;
+
+        this.checkToolbar();
+    },
+    doAnimationAuto: function(){
+        this.playing = true;
+        this.checkToolbar();
+        this.doPatchAnimation(function(){
+            this.patchIndex = 0;
+            this.diffIndex = 0;
+            this.playing = false;
+            this.documentEditor.resetData();
+            this.checkToolbar();
+        }.bind(this));
+    },
+    do: function(){
+        if (this.nextPlayPrefixFunction){
+            this.nextPlayPrefixFunction();
+            this.nextPlayPrefixFunction = null;
+        }else{
+            this.doAnimationAuto();
+        }
+    },
+    play: function(){
+        this.reverse = false;
+        this.stop = false;
+    //    this.checkToolbar();
+        this.options.fxTime = 500;
+        this.options.inforTime = 2000;
+
+        this.toolbar.childrenButton[0].disable();
+        this.toolbar.childrenButton[3].disable();
+        this.toolbar.childrenButton[4].disable();
+
+        if (!this.playing){
+            this.initData();
+            this.initAnimationStatus();
+        }
+        this.do();
+    },
+    stopPlay: function(){
+        if (this.playing){
+            this.stop = true;
+            this.playing = false;
+
+            if (this.nextPlayPrefixFunction){
+                this.nextPlayPrefixFunction();
+                this.nextPlayPrefixFunction = null;
+            }
+
+            this.patchIndex = 0;
+            this.diffIndex = 0;
+            this.toolbar.childrenButton[1].disable();
+            this.toolbar.childrenButton[2].disable();
+        }
+    },
+    pause: function(){
+        if (this.playing){
+            this.stop = true;
+            this.toolbar.childrenButton[1].disable();
+            this.toolbar.childrenButton[2].disable();
+        }
+    },
+    next: function(){
+        this.reverse = false;
+        this.options.fxTime = 0;
+        this.options.inforTime = 0;
+        this.stop = true;
+
+        this.toolbar.childrenButton[3].disable();
+        this.toolbar.childrenButton[4].disable();
+
+        if (!this.playing){
+            this.initData();
+            this.initAnimationStatus();
+        }
+        this.do();
+    },
+    prev: function(){
+        this.reverse = true;
+        this.options.fxTime = 0;
+        this.options.inforTime = 0;
+        this.stop = true;
+
+        this.toolbar.childrenButton[3].disable();
+        this.toolbar.childrenButton[4].disable();
+
+        if (!this.playing) this.initData();
+        this.do();
+    },
+    exit: function(){
+        this.initAnimationStatus();
+        this.options.fxTime = 0;
+        this.options.inforTime = 0;
+        if (this.nextPlayPrefixFunction){
+            this.nextPlayPrefixFunction(function(){
+                this.documentEditor.toolbarNode = this.documentEditor.documentToolbarNode;
+                this.documentEditor.toolbarNode.show();
+                if (this.documentEditor.sidebarNode) this.documentEditor.sidebarNode.show();
+                this.documentEditor.resizeToolbar();
+            }.bind(this));
+            this.nextPlayPrefixFunction = null;
+        }else{
+            this.documentEditor.toolbarNode = this.documentEditor.documentToolbarNode;
+            this.documentEditor.toolbarNode.show();
+            if (this.documentEditor.sidebarNode) this.documentEditor.sidebarNode.show();
+            this.documentEditor.resizeToolbar();
+        }
+
+        this.historyListAreaNode.destroy();
+        this.historyListAreaNode = null;
+        this.documentEditor.zoom(1);
+        this.documentEditor._checkScale();
+
+        this.documentEditor.resetData();
+        this.toolbarNode.hide();
+    },
+    active: function(callback){
+        this.getHistroyDocumentList(function(){
+            if (this.historyDocumentList && this.historyDocumentList.length){
+                this.getHistoryDataList(function(){
+                    this.documentEditor.options.pageShow = "single";
+                    this.documentEditor.resetData();
+
+                    this.beginDiffHistory(function(){
+                        this.documentEditor.resetData();
+                        this.toolbarNode.show();
+                        this.documentEditor.documentToolbarNode = this.documentEditor.toolbarNode;
+                        this.documentEditor.documentToolbarNode.hide();
+                        if (this.documentEditor.sidebarNode) this.documentEditor.sidebarNode.hide();
+                        this.documentEditor.toolbarNode = this.toolbarNode;
+                        this.documentEditor.resizeToolbar();
+
+                        var text = MWF.xApplication.process.Xform.LP.documentHistory.diff_patch_count;
+                        text = text.replace(/{history}/, this.historyDataList.length).replace(/{diff}/, this.diffCount);
+                        this.toolbarNode.getLast().set("html", text);
+
+                        if (callback) callback();
+                    }.bind(this));
+                }.bind(this));
+            }
+        }.bind(this));
+    },
+
+    doAnimationStep: function(i){
+        this.doPatchAnimationStep(i);
+
+        this.documentEditor.resetData();
+        this.checkToolbar();
+    },
+
+    diffHistroy: function(){
+        var diffPatch =  [];
+        for (var i=1; i<this.historyDataList.length; i++){
+            var earlyDataText = this.historyDataList[i-1].data;
+            var laterData = this.historyDataList[i];
+
+            var dmp = new diff_match_patch();
+            // dmp.Diff_Timeout = parseFloat(10);
+            // dmp.Diff_EditCost = parseFloat(4);
+            var diff_d = dmp.diff_main(earlyDataText, laterData.data);
+            dmp.diff_cleanupSemantic(diff_d);
+            var patch_list = dmp.patch_make(earlyDataText, laterData.data, diff_d);
+
+            patch_list.each(function(patch){
+                diffPatch.push({"patch":patch, "obj": laterData});
+            }.bind(this));
+        }
+        return diffPatch;
+    },
+
+    doPatchAnimation: function(callback){
+        var patchObj = this.diffPatch[this.patchIndex];
+        var patch = patchObj.patch;
+        var obj = patchObj.obj;
+        this.currentDiffs = patch.diffs;
+        this.diffIndex = (this.reverse) ? patch.diffs.length-1 : 0;
+
+        // var inforDiv = this.createPatchInforNode(obj);
+        //
+        // var fx = new Fx.Tween(inforDiv, {property: 'opacity'});
+        // fx.start(0,1).chain(function(){
+
+        var start = (this.reverse) ? patch.start1+patch.length2 : patch.start1;
+        this.doDiffsAnimation(obj, start, function(){
+            //inforDiv.destroy();
+            if (this.reverse){
+                this.patchIndex--;
+                if (this.patchIndex>=0){
+                    this.currentHistoryData = this.documentEditor.layout_filetext.get("html");
+                    this.doPatchAnimation(callback);
+                }else{
+                    if (callback) callback();
+                }
+            }else{
+                this.patchIndex++;
+                if (this.patchIndex<this.diffPatch.length){
+                    this.currentHistoryData = this.documentEditor.layout_filetext.get("html");
+                    this.doPatchAnimation(callback);
+                }else{
+                    if (callback) callback();
+                }
+            }
+
+        }.bind(this));
+    },
+    doPatchAnimationStep: function(i){
+        if (this.patchIndex>this.diffPatch.length || this.patchIndex<0){
+            this.initAnimationStatus();
+            this.documentEditor.resetData();
+            this.checkToolbar();
+        }else{
+            var patchObj = this.diffPatch[this.patchIndex];
+            var patch = patchObj.patch;
+            var obj = patchObj.obj;
+            this.currentDiffs = patch.diffs;
+            this.diffIndex = 0;
+
+            this.doDiffsAnimation(obj, patch.start1);
+
+            this.patchIndex = this.patchIndex+i;
+        }
+    },
+
+    createDiifInforNode: function(obj, node, color, insertInfor){
+        var insertInforDiv = new Element("div", { "styles": this.css.historyInforNode }).inject(this.documentEditor.node);
+        insertInforDiv.setStyle("background", color);
+        insertInfor = insertInfor.replace(/{name}/, o2.name.cn(obj.person))
+            .replace(/{activity}/, obj.activityName)
+            .replace(/{time}/, obj.createTime);
+        insertInforDiv.set("html", insertInfor);
+        insertInforDiv.position({
+            "relativeTo": node,
+            "position": 'upperCenter',
+            "edge": 'bottomCenter',
+            "offset": {
+                "x": 0, "y": -10
+            }
+        });
+        return insertInforDiv;
+    },
+    doDiffsAnimation: function(obj, start, callback){
+        var diff = this.currentDiffs[this.diffIndex];
+        var filetextNode = this.documentEditor.layout_filetext;
+        switch (diff[0]) {
+            case DIFF_INSERT:
+                var text = diff[1];
+                if (this.reverse){
+                    start -= text.length;
+                    var left = this.currentHistoryData.substring(0, start);
+                    var middle = this.currentHistoryData.substring(start, start+diff[1].length);
+                    var right = this.currentHistoryData.substring(start+diff[1].length);
+                    filetextNode.set("html", left+"<ins style='color:blue;'></ins>"+right);
+                }else{
+                    var left = this.currentHistoryData.substring(0, start);
+                    var right = this.currentHistoryData.substring(start);
+                    filetextNode.set("html", left+"<ins style='color:blue;'></ins>"+right);
+                }
+
+                var ins = filetextNode.getElement("ins");
+                ins.scrollIn();
+
+                this.doInsetAnimation(ins, diff[1], function(invisible){
+                    var insertInforDiv = null;
+                    if (!invisible){
+                        insertInforDiv = this.createDiifInforNode(obj, ins, "#e2edfb", MWF.xApplication.process.Xform.LP.documentHistory.insertContent);
+                    }
+                    window.setTimeout(function(){
+                        var endFunction = function(cb){
+                            if (insertInforDiv) insertInforDiv.fade("out");
+                            var fx = new Fx.Tween(ins, {property: 'opacity', duration:this.options.speed*this.options.fxTime});
+                            fx.start(1.1).chain(function(){
+                                if (insertInforDiv) insertInforDiv.destroy();
+                                if (this.reverse){
+                                    ins.destroy();
+                                    this.currentHistoryData = filetextNode.get("html");
+                                }else{
+                                    data = filetextNode.get("html");
+                                    this.currentHistoryData = data.replace(/<ins[\s\S]*\/ins>/m, text);
+                                    filetextNode.set("html", this.currentHistoryData);
+                                }
+                                if (this.playing){
+                                    if (this.reverse){
+                                        this.diffIndex--;
+                                        if (this.diffIndex>=0){
+                                            window.setTimeout(function(){this.doDiffsAnimation(obj, start, callback);}.bind(this), this.options.speed*this.options.fxTime);
+                                            //this.doDiffsAnimation(obj, start, callback);
+                                        }else{
+                                            if (callback) callback();
+                                        }
+                                    }else{
+                                        start += text.length;
+                                        this.diffIndex++;
+                                        if (this.diffIndex<this.currentDiffs.length){
+                                            window.setTimeout(function(){this.doDiffsAnimation(obj, start, callback);}.bind(this), this.options.speed*this.options.fxTime);
+                                            //this.doDiffsAnimation(obj, start, callback);
+                                        }else{
+                                            if (callback) callback();
+                                        }
+                                    }
+                                }else{
+                                    this.initAnimationStatus();
+                                    this.documentEditor.resetData();
+                                }
+                                if (cb) cb();
+
+                            }.bind(this));
+                            if (this.nextPlayPrefixFunction) this.nextPlayPrefixFunction = null;
+                        }.bind(this)
+                        if (!this.stop || !this.playing) {
+                            endFunction();
+                        } else{
+                            this.nextPlayPrefixFunction = endFunction;
+                        }
+                        this.checkToolbar();
+                    }.bind(this), (invisible ? 100: this.options.speed*this.options.inforTime));
+                }.bind(this));
+                break;
+            case DIFF_DELETE:
+                var text = diff[1];
+                if (this.reverse){
+                    var left = this.currentHistoryData.substring(0, start);
+                    //var middle = this.currentHistoryData.substring(start, start+diff[1].length);
+                    var right = this.currentHistoryData.substring(start);
+                    filetextNode.set("html", left+"<del style='color: red'>"+text+"</del>"+right);
+                    start -= text.length;
+                }else{
+                    var left = this.currentHistoryData.substring(0, start);
+                    var middle = this.currentHistoryData.substring(start, start+diff[1].length);
+                    var right = this.currentHistoryData.substring(start+diff[1].length);
+                    //start -= .length;
+                    filetextNode.set("html", left+"<del style='color: red'>"+middle+"</del>"+right);
+                }
+
+
+                var del = filetextNode.getElement("del");
+                del.scrollIn();
+
+                this.doDeleteAnimation(del, diff[1], obj, function(deleteInforDiv){
+                    // var deleteInforDiv = null;
+                    // if (!invisible){
+                    //     deleteInforDiv = this.createDiifInforNode(obj, del, "#fbe0e7", MWF.xApplication.process.Xform.LP.documentHistory.deleteContent);
+                    // }
+                    var invisible = !deleteInforDiv;
+                    window.setTimeout(function(){
+                        var endFunction = function(cb){
+                            if (deleteInforDiv) deleteInforDiv.fade("out");
+                            var fx = new Fx.Tween(del, {property: 'opacity', duration:this.options.speed*this.options.fxTime});
+                            fx.start(0.5,0).chain(function(){
+                                if (deleteInforDiv) deleteInforDiv.destroy();
+                                if (this.reverse){
+                                    data = filetextNode.get("html");
+                                    this.currentHistoryData = data.replace(/<del[\s\S]*\/del>/m, text);
+                                    filetextNode.set("html", this.currentHistoryData);
+                                }else{
+                                    del.destroy();
+                                    this.currentHistoryData = filetextNode.get("html");
+                                }
+
+                                if (this.playing){
+                                    if (this.reverse){
+                                        this.diffIndex--;
+                                        if (this.diffIndex>=0){
+                                            window.setTimeout(function(){this.doDiffsAnimation(obj, start, callback);}.bind(this), this.options.speed*this.options.fxTime);
+                                        }else{
+                                            if (callback) callback();
+                                        }
+                                    }else{
+                                        this.diffIndex++;
+                                        if (this.diffIndex<this.currentDiffs.length){
+                                            window.setTimeout(function(){this.doDiffsAnimation(obj, start, callback);}.bind(this), this.options.speed*this.options.fxTime);
+                                        }else{
+                                            if (callback) callback();
+                                        }
+                                    }
+
+                                }else{
+                                    this.initAnimationStatus();
+                                    this.documentEditor.resetData();
+                                }
+                                if (cb) cb();
+
+                            }.bind(this));
+                            if (this.nextPlayPrefixFunction) this.nextPlayPrefixFunction = null;
+                        }.bind(this)
+                        if (!this.stop || !this.playing) {
+                            endFunction();
+                        } else{
+                            this.nextPlayPrefixFunction = endFunction;
+                        }
+                        this.checkToolbar();
+                    }.bind(this), (invisible ? 100: this.options.speed*this.options.inforTime));
+                }.bind(this));
+                break;
+            case DIFF_EQUAL:
+                if (this.reverse){
+                    start -= diff[1].length;
+                    this.diffIndex--;
+                    if (this.diffIndex>=0){
+                        this.doDiffsAnimation(obj, start, callback);
+                    }else{
+                        if (callback) callback();
+                    }
+                }else{
+                    start += diff[1].length;
+                    this.diffIndex++;
+                    if (this.diffIndex<this.currentDiffs.length){
+                        this.doDiffsAnimation(obj, start, callback);
+                    }else{
+                        if (callback) callback();
+                    }
+                }
+
+                break;
+        }
+    },
+
+    doInsetAnimation: function(node, str, callback){
+        var tmp = new Element("div", {"html": str});
+        if (!tmp.get("text").trim()){
+            if (callback) callback(true);
+        }else{
+            var nodes = tmp.childNodes;
+            this.doInsetNodeAnimation(node, nodes, 0, callback);
+        }
+    },
+    doInsetNodeAnimation: function(ins, nodes, idx, callback){
+        var node = nodes[idx];
+        if (node.nodeType == Node.TEXT_NODE){
+            this.doCharAnimation(ins, node.nodeValue, 0, function(){
+                idx++;
+                if (idx<nodes.length){
+                    this.doInsetNodeAnimation(ins, nodes, idx, callback);
+                }else{
+                    if (callback) callback();
+                }
+            }.bind(this));
+        }else{
+            var duration = this.options.speed*this.options.fxTime/nodes.length
+            var span = new Element("span", {"styles": {"opacity": 0}}).inject(ins);
+            span.appendChild(node);
+            var fx = new Fx.Tween(span, {property: 'opacity', duration:duration});
+            fx.start(0,1).chain(function(){
+                idx++;
+                if (idx<nodes.length){
+                    this.doInsetNodeAnimation(ins, nodes, idx, callback);
+                }else{
+                    if (callback) callback();
+                }
+            }.bind(this));
+        }
+    },
+
+    doCharAnimation: function(node, str, idx, callback){
+        var duration = this.options.speed*this.options.fxTime/str.length;
+        var char = str.charAt(idx);
+        var span = new Element("span", {"styles": {"opacity": 0}, "html": char}).inject(node);
+        var fx = new Fx.Tween(span, {property: 'opacity', duration:duration});
+        fx.start(0,1).chain(function(){
+            idx++;
+            if (idx<str.length){
+                this.doCharAnimation(node, str, idx, callback);
+            }else{
+                if (callback) callback();
+            }
+        }.bind(this));
+    },
+
+    doDeleteAnimation: function(node, str, obj, callback){
+        var tmp = new Element("div", {"html": str});
+        if (!tmp.get("text").trim()){
+            if (callback) callback(null);
+        }else{
+            deleteInforDiv = this.createDiifInforNode(obj, node, "#fbe0e7", MWF.xApplication.process.Xform.LP.documentHistory.deleteContent);
+            var fx = new Fx.Tween(node, {property: 'opacity', duration:this.options.speed*this.options.fxTime});
+            fx.start(1,0.5).chain(function(){
+                if (callback) callback(deleteInforDiv);
+            }.bind(this));
+        }
+    }
+});
+
+MWF.xApplication.process.Xform.widget.DocumentHistory.Item = new Class({
+    initialize: function(history, patch){
+        this.history = history;
+        this.documentEditor = this.history.documentEditor;
+        this.css = this.history.css;
+        this.load();
+    },
+    load: function(){
+
+    }
+})