import torrus 1.0.9
[freeside.git] / rt / share / html / NoAuth / RichText / FCKeditor / editor / _source / internals / fckundo.js
1 /*\r
2  * FCKeditor - The text editor for Internet - http://www.fckeditor.net\r
3  * Copyright (C) 2003-2009 Frederico Caldeira Knabben\r
4  *\r
5  * == BEGIN LICENSE ==\r
6  *\r
7  * Licensed under the terms of any of the following licenses at your\r
8  * choice:\r
9  *\r
10  *  - GNU General Public License Version 2 or later (the "GPL")\r
11  *    http://www.gnu.org/licenses/gpl.html\r
12  *\r
13  *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")\r
14  *    http://www.gnu.org/licenses/lgpl.html\r
15  *\r
16  *  - Mozilla Public License Version 1.1 or later (the "MPL")\r
17  *    http://www.mozilla.org/MPL/MPL-1.1.html\r
18  *\r
19  * == END LICENSE ==\r
20  */\r
21 \r
22 var FCKUndo = new Object() ;\r
23 \r
24 FCKUndo.SavedData = new Array() ;\r
25 FCKUndo.CurrentIndex = -1 ;\r
26 FCKUndo.TypesCount = 0 ;\r
27 FCKUndo.Changed = false ;       // Is the document changed in respect to its initial image?\r
28 FCKUndo.MaxTypes = 25 ;\r
29 FCKUndo.Typing = false ;\r
30 FCKUndo.SaveLocked = false ;\r
31 \r
32 FCKUndo._GetBookmark = function()\r
33 {\r
34         FCKSelection.Restore() ;\r
35 \r
36         var range = new FCKDomRange( FCK.EditorWindow ) ;\r
37         try\r
38         {\r
39                 // There are some tricky cases where this might fail (e.g. having a lone empty table in IE)\r
40                 range.MoveToSelection() ;\r
41         }\r
42         catch ( e )\r
43         {\r
44                 return null ;\r
45         }\r
46         if ( FCKBrowserInfo.IsIE )\r
47         {\r
48                 var bookmark = range.CreateBookmark() ;\r
49                 var dirtyHtml = FCK.EditorDocument.body.innerHTML ;\r
50                 range.MoveToBookmark( bookmark ) ;\r
51                 return [ bookmark, dirtyHtml ] ;\r
52         }\r
53         return range.CreateBookmark2() ;\r
54 }\r
55 \r
56 FCKUndo._SelectBookmark = function( bookmark )\r
57 {\r
58         if ( ! bookmark )\r
59                 return ;\r
60 \r
61         var range = new FCKDomRange( FCK.EditorWindow ) ;\r
62         if ( bookmark instanceof Object )\r
63         {\r
64                 if ( FCKBrowserInfo.IsIE )\r
65                         range.MoveToBookmark( bookmark[0] ) ;\r
66                 else\r
67                         range.MoveToBookmark2( bookmark ) ;\r
68                 try\r
69                 {\r
70                         // this does not always succeed, there are still some tricky cases where it fails\r
71                         // e.g. add a special character at end of document, undo, redo -> error\r
72                         range.Select() ;\r
73                 }\r
74                 catch ( e )\r
75                 {\r
76                         // if select restore fails, put the caret at the end of the document\r
77                         range.MoveToPosition( FCK.EditorDocument.body, 4 ) ;\r
78                         range.Select() ;\r
79                 }\r
80         }\r
81 }\r
82 \r
83 FCKUndo._CompareCursors = function( cursor1, cursor2 )\r
84 {\r
85         for ( var i = 0 ; i < Math.min( cursor1.length, cursor2.length ) ; i++ )\r
86         {\r
87                 if ( cursor1[i] < cursor2[i] )\r
88                         return -1;\r
89                 else if (cursor1[i] > cursor2[i] )\r
90                         return 1;\r
91         }\r
92         if ( cursor1.length < cursor2.length )\r
93                 return -1;\r
94         else if (cursor1.length > cursor2.length )\r
95                 return 1;\r
96         return 0;\r
97 }\r
98 \r
99 FCKUndo._CheckIsBookmarksEqual = function( bookmark1, bookmark2 )\r
100 {\r
101         if ( ! ( bookmark1 && bookmark2 ) )\r
102                 return false ;\r
103         if ( FCKBrowserInfo.IsIE )\r
104         {\r
105                 var startOffset1 = bookmark1[1].search( bookmark1[0].StartId ) ;\r
106                 var startOffset2 = bookmark2[1].search( bookmark2[0].StartId ) ;\r
107                 var endOffset1 = bookmark1[1].search( bookmark1[0].EndId ) ;\r
108                 var endOffset2 = bookmark2[1].search( bookmark2[0].EndId ) ;\r
109                 return startOffset1 == startOffset2 && endOffset1 == endOffset2 ;\r
110         }\r
111         else\r
112         {\r
113                 return this._CompareCursors( bookmark1.Start, bookmark2.Start ) == 0\r
114                         && this._CompareCursors( bookmark1.End, bookmark2.End ) == 0 ;\r
115         }\r
116 }\r
117 \r
118 FCKUndo.SaveUndoStep = function()\r
119 {\r
120         if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || this.SaveLocked )\r
121                 return ;\r
122 \r
123         // Assume the editor content is changed when SaveUndoStep() is called after the first time.\r
124         // This also enables the undo button in toolbar.\r
125         if ( this.SavedData.length )\r
126                 this.Changed = true ;\r
127 \r
128         // Get the HTML content.\r
129         var sHtml = FCK.EditorDocument.body.innerHTML ;\r
130         var bookmark = this._GetBookmark() ;\r
131 \r
132         // Shrink the array to the current level.\r
133         this.SavedData = this.SavedData.slice( 0, this.CurrentIndex + 1 ) ;\r
134 \r
135         // Cancel operation if the new step is identical to the previous one.\r
136         if ( this.CurrentIndex > 0\r
137                         && sHtml == this.SavedData[ this.CurrentIndex ][0]\r
138                         && this._CheckIsBookmarksEqual( bookmark, this.SavedData[ this.CurrentIndex ][1] ) )\r
139                 return ;\r
140         // Save the selection and caret position in the first undo level for the first change.\r
141         else if ( this.CurrentIndex == 0 && this.SavedData.length && sHtml == this.SavedData[0][0] )\r
142         {\r
143                 this.SavedData[0][1] = bookmark ;\r
144                 return ;\r
145         }\r
146 \r
147         // If we reach the Maximum number of undo levels, we must remove the first\r
148         // entry of the list shifting all elements.\r
149         if ( this.CurrentIndex + 1 >= FCKConfig.MaxUndoLevels )\r
150                 this.SavedData.shift() ;\r
151         else\r
152                 this.CurrentIndex++ ;\r
153 \r
154         // Save the new level in front of the actual position.\r
155         this.SavedData[ this.CurrentIndex ] = [ sHtml, bookmark ] ;\r
156 \r
157         FCK.Events.FireEvent( "OnSelectionChange" ) ;\r
158 }\r
159 \r
160 FCKUndo.CheckUndoState = function()\r
161 {\r
162         return ( this.Changed || this.CurrentIndex > 0 ) ;\r
163 }\r
164 \r
165 FCKUndo.CheckRedoState = function()\r
166 {\r
167         return ( this.CurrentIndex < ( this.SavedData.length - 1 ) ) ;\r
168 }\r
169 \r
170 FCKUndo.Undo = function()\r
171 {\r
172         if ( this.CheckUndoState() )\r
173         {\r
174                 // If it is the first step.\r
175                 if ( this.CurrentIndex == ( this.SavedData.length - 1 ) )\r
176                 {\r
177                         // Save the actual state for a possible "Redo" call.\r
178                         this.SaveUndoStep() ;\r
179                 }\r
180 \r
181                 // Go a step back.\r
182                 this._ApplyUndoLevel( --this.CurrentIndex ) ;\r
183 \r
184                 FCK.Events.FireEvent( "OnSelectionChange" ) ;\r
185         }\r
186 }\r
187 \r
188 FCKUndo.Redo = function()\r
189 {\r
190         if ( this.CheckRedoState() )\r
191         {\r
192                 // Go a step forward.\r
193                 this._ApplyUndoLevel( ++this.CurrentIndex ) ;\r
194 \r
195                 FCK.Events.FireEvent( "OnSelectionChange" ) ;\r
196         }\r
197 }\r
198 \r
199 FCKUndo._ApplyUndoLevel = function( level )\r
200 {\r
201         var oData = this.SavedData[ level ] ;\r
202 \r
203         if ( !oData )\r
204                 return ;\r
205 \r
206         // Update the editor contents with that step data.\r
207         if ( FCKBrowserInfo.IsIE )\r
208         {\r
209                 if ( oData[1] && oData[1][1] )\r
210                         FCK.SetInnerHtml( oData[1][1] ) ;\r
211                 else\r
212                         FCK.SetInnerHtml( oData[0] ) ;\r
213         }\r
214         else\r
215                 FCK.EditorDocument.body.innerHTML = oData[0] ;\r
216 \r
217         // Restore the selection\r
218         this._SelectBookmark( oData[1] ) ;\r
219 \r
220         this.TypesCount = 0 ;\r
221         this.Changed = false ;\r
222         this.Typing = false ;\r
223 }\r