Subversion Repositories Applications.papyrus

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1075 ddelon 1
/*
2
 * FCKeditor - The text editor for internet
3
 * Copyright (C) 2003-2006 Frederico Caldeira Knabben
4
 *
5
 * Licensed under the terms of the GNU Lesser General Public License:
6
 * 		http://www.opensource.org/licenses/lgpl-license.php
7
 *
8
 * For further information visit:
9
 * 		http://www.fckeditor.net/
10
 *
11
 * "Support Open Source software. What about a donation today?"
12
 *
13
 * File Name: fcktablehandler.js
14
 * 	Manage table operations.
15
 *
16
 * File Authors:
17
 * 		Frederico Caldeira Knabben (fredck@fckeditor.net)
18
 */
19
 
20
var FCKTableHandler = new Object() ;
21
 
22
FCKTableHandler.InsertRow = function()
23
{
24
	// Get the row where the selection is placed in.
25
	var oRow = FCKSelection.MoveToAncestorNode("TR") ;
26
	if ( !oRow ) return ;
27
 
28
	// Create a clone of the row.
29
	var oNewRow = oRow.cloneNode( true ) ;
30
 
31
	// Insert the new row (copy) before of it.
32
	oRow.parentNode.insertBefore( oNewRow, oRow ) ;
33
 
34
	// Clean the row (it seems that the new row has been added after it).
35
	FCKTableHandler.ClearRow( oRow ) ;
36
}
37
 
38
FCKTableHandler.DeleteRows = function( row )
39
{
40
	// If no row has been passed as a parameer,
41
	// then get the row where the selection is placed in.
42
	if ( !row )
43
		row = FCKSelection.MoveToAncestorNode("TR") ;
44
	if ( !row ) return ;
45
 
46
	// Get the row's table.
47
	var oTable = FCKTools.GetElementAscensor( row, 'TABLE' ) ;
48
 
49
	// If just one row is available then delete the entire table.
50
	if ( oTable.rows.length == 1 )
51
	{
52
		FCKTableHandler.DeleteTable( oTable ) ;
53
		return ;
54
	}
55
 
56
	// Delete the row.
57
	row.parentNode.removeChild( row ) ;
58
}
59
 
60
FCKTableHandler.DeleteTable = function( table )
61
{
62
	// If no table has been passed as a parameer,
63
	// then get the table where the selection is placed in.
64
	if ( !table )
65
	{
66
		var table = FCKSelection.GetSelectedElement() ;
67
		if ( !table || table.tagName != 'TABLE' )
68
			table = FCKSelection.MoveToAncestorNode("TABLE") ;
69
	}
70
	if ( !table ) return ;
71
 
72
	// Delete the table.
73
	FCKSelection.SelectNode( table ) ;
74
	FCKSelection.Collapse();
75
	table.parentNode.removeChild( table ) ;
76
}
77
 
78
FCKTableHandler.InsertColumn = function()
79
{
80
	// Get the cell where the selection is placed in.
81
	var oCell = FCKSelection.MoveToAncestorNode("TD") ;
82
	if ( !oCell )
83
	    oCell =  FCKSelection.MoveToAncestorNode("TH") ;
84
 
85
	if ( !oCell ) return ;
86
 
87
	// Get the cell's table.
88
	var oTable = FCKTools.GetElementAscensor( oCell, 'TABLE' ) ;
89
 
90
	// Get the index of the column to be created (based on the cell).
91
	var iIndex = oCell.cellIndex + 1 ;
92
 
93
	// Loop throw all rows available in the table.
94
	for ( var i = 0 ; i < oTable.rows.length ; i++ )
95
	{
96
		// Get the row.
97
		var oRow = oTable.rows[i] ;
98
 
99
		// If the row doens't have enought cells, ignore it.
100
		if ( oRow.cells.length < iIndex )
101
			continue ;
102
 
103
		oCell = oRow.cells[iIndex-1].cloneNode(false) ;
104
 
105
		if ( FCKBrowserInfo.IsGecko )
106
			oCell.innerHTML = GECKO_BOGUS ;
107
 
108
		// Get the cell that is placed in the new cell place.
109
		var oBaseCell = oRow.cells[iIndex] ;
110
 
111
		// If the cell is available (we are not in the last cell of the row).
112
		if ( oBaseCell )
113
			oRow.insertBefore( oCell, oBaseCell ) ;	// Insert the new cell just before of it.
114
		else
115
			oRow.appendChild( oCell ) ;				// Append the cell at the end of the row.
116
	}
117
}
118
 
119
FCKTableHandler.DeleteColumns = function()
120
{
121
	// Get the cell where the selection is placed in.
122
	var oCell = FCKSelection.MoveToAncestorNode('TD') || FCKSelection.MoveToAncestorNode('TH') ;
123
 
124
	if ( !oCell ) return ;
125
 
126
	// Get the cell's table.
127
	var oTable = FCKTools.GetElementAscensor( oCell, 'TABLE' ) ;
128
 
129
	// Get the cell index.
130
	var iIndex = oCell.cellIndex ;
131
 
132
	// Loop throw all rows (from down to up, because it's possible that some
133
	// rows will be deleted).
134
	for ( var i = oTable.rows.length - 1 ; i >= 0 ; i-- )
135
	{
136
		// Get the row.
137
		var oRow = oTable.rows[i] ;
138
 
139
		// If the cell to be removed is the first one and the row has just one cell.
140
		if ( iIndex == 0 && oRow.cells.length == 1 )
141
		{
142
			// Remove the entire row.
143
			FCKTableHandler.DeleteRows( oRow ) ;
144
			continue ;
145
		}
146
 
147
		// If the cell to be removed exists the delete it.
148
		if ( oRow.cells[iIndex] )
149
			oRow.removeChild( oRow.cells[iIndex] ) ;
150
	}
151
}
152
 
153
FCKTableHandler.InsertCell = function( cell )
154
{
155
	// Get the cell where the selection is placed in.
156
	var oCell = cell ? cell : FCKSelection.MoveToAncestorNode("TD") ;
157
	if ( !oCell ) return ;
158
 
159
	// Create the new cell element to be added.
160
	var oNewCell = FCK.EditorDocument.createElement("TD");
161
	if ( FCKBrowserInfo.IsGecko )
162
		oNewCell.innerHTML = GECKO_BOGUS ;
163
//	oNewCell.innerHTML = "&nbsp;" ;
164
 
165
	// If it is the last cell in the row.
166
	if ( oCell.cellIndex == oCell.parentNode.cells.length - 1 )
167
	{
168
		// Add the new cell at the end of the row.
169
		oCell.parentNode.appendChild( oNewCell ) ;
170
	}
171
	else
172
	{
173
		// Add the new cell before the next cell (after the active one).
174
		oCell.parentNode.insertBefore( oNewCell, oCell.nextSibling ) ;
175
	}
176
 
177
	return oNewCell ;
178
}
179
 
180
FCKTableHandler.DeleteCell = function( cell )
181
{
182
	// If this is the last cell in the row.
183
	if ( cell.parentNode.cells.length == 1 )
184
	{
185
		// Delete the entire row.
186
		FCKTableHandler.DeleteRows( FCKTools.GetElementAscensor( cell, 'TR' ) ) ;
187
		return ;
188
	}
189
 
190
	// Delete the cell from the row.
191
	cell.parentNode.removeChild( cell ) ;
192
}
193
 
194
FCKTableHandler.DeleteCells = function()
195
{
196
	var aCells = FCKTableHandler.GetSelectedCells() ;
197
 
198
	for ( var i = aCells.length - 1 ; i >= 0  ; i-- )
199
	{
200
		FCKTableHandler.DeleteCell( aCells[i] ) ;
201
	}
202
}
203
 
204
FCKTableHandler.MergeCells = function()
205
{
206
	// Get all selected cells.
207
	var aCells = FCKTableHandler.GetSelectedCells() ;
208
 
209
	// At least 2 cells must be selected.
210
	if ( aCells.length < 2 )
211
		return ;
212
 
213
	// The merge can occour only if the selected cells are from the same row.
214
	if ( aCells[0].parentNode != aCells[aCells.length-1].parentNode )
215
		return ;
216
 
217
	// Calculate the new colSpan for the first cell.
218
	var iColSpan = isNaN( aCells[0].colSpan ) ? 1 : aCells[0].colSpan ;
219
 
220
	var sHtml = '' ;
221
	var oCellsContents = FCK.EditorDocument.createDocumentFragment() ;
222
 
223
	for ( var i = aCells.length - 1 ; i >= 0 ; i-- )
224
	{
225
		var eCell = aCells[i] ;
226
 
227
		// Move its contents to the document fragment.
228
		for ( var c = eCell.childNodes.length - 1 ; c >= 0 ; c-- )
229
		{
230
			var eChild = eCell.removeChild( eCell.childNodes[c] ) ;
231
 
232
			if ( ( eChild.hasAttribute && eChild.hasAttribute('_moz_editor_bogus_node') ) || ( eChild.getAttribute && eChild.getAttribute( 'type', 2 ) == '_moz' ) )
233
				continue ;
234
 
235
				oCellsContents.insertBefore( eChild, oCellsContents.firstChild ) ;
236
		}
237
 
238
		if ( i > 0 )
239
		{
240
			// Accumulate the colspan of the cell.
241
			iColSpan += isNaN( eCell.colSpan ) ? 1 : eCell.colSpan ;
242
 
243
			// Delete the cell.
244
			FCKTableHandler.DeleteCell( eCell ) ;
245
		}
246
	}
247
 
248
	// Set the innerHTML of the remaining cell (the first one).
249
	aCells[0].colSpan = iColSpan ;
250
 
251
	if ( FCKBrowserInfo.IsGecko && oCellsContents.childNodes.length == 0 )
252
		aCells[0].innerHTML = GECKO_BOGUS ;
253
	else
254
		aCells[0].appendChild( oCellsContents ) ;
255
}
256
 
257
FCKTableHandler.SplitCell = function()
258
{
259
	// Check that just one cell is selected, otherwise return.
260
	var aCells = FCKTableHandler.GetSelectedCells() ;
261
	if ( aCells.length != 1 )
262
		return ;
263
 
264
	var aMap = this._CreateTableMap( aCells[0].parentNode.parentNode ) ;
265
	var iCellIndex = FCKTableHandler._GetCellIndexSpan( aMap, aCells[0].parentNode.rowIndex , aCells[0] ) ;
266
 
267
	var aCollCells = this._GetCollumnCells( aMap, iCellIndex ) ;
268
 
269
	for ( var i = 0 ; i < aCollCells.length ; i++ )
270
	{
271
		if ( aCollCells[i] == aCells[0] )
272
		{
273
			var oNewCell = this.InsertCell( aCells[0] ) ;
274
			if ( !isNaN( aCells[0].rowSpan ) && aCells[0].rowSpan > 1 )
275
				oNewCell.rowSpan = aCells[0].rowSpan ;
276
		}
277
		else
278
		{
279
			if ( isNaN( aCollCells[i].colSpan ) )
280
				aCollCells[i].colSpan = 2 ;
281
			else
282
				aCollCells[i].colSpan += 1 ;
283
		}
284
	}
285
}
286
 
287
// Get the cell index from a TableMap.
288
FCKTableHandler._GetCellIndexSpan = function( tableMap, rowIndex, cell )
289
{
290
	if ( tableMap.length < rowIndex + 1 )
291
		return null ;
292
 
293
	var oRow = tableMap[ rowIndex ] ;
294
 
295
	for ( var c = 0 ; c < oRow.length ; c++ )
296
	{
297
		if ( oRow[c] == cell )
298
			return c ;
299
	}
300
 
301
	return null ;
302
}
303
 
304
// Get the cells available in a collumn of a TableMap.
305
FCKTableHandler._GetCollumnCells = function( tableMap, collumnIndex )
306
{
307
	var aCollCells = new Array() ;
308
 
309
	for ( var r = 0 ; r < tableMap.length ; r++ )
310
	{
311
		var oCell = tableMap[r][collumnIndex] ;
312
		if ( oCell && ( aCollCells.length == 0 || aCollCells[ aCollCells.length - 1 ] != oCell ) )
313
			aCollCells[ aCollCells.length ] = oCell ;
314
	}
315
 
316
	return aCollCells ;
317
}
318
 
319
// This function is quite hard to explain. It creates a matrix representing all cells in a table.
320
// The difference here is that the "spanned" cells (colSpan and rowSpan) are duplicated on the matrix
321
// cells that are "spanned". For example, a row with 3 cells where the second cell has colSpan=2 and rowSpan=3
322
// will produce a bi-dimensional matrix with the following values (representing the cells):
323
//		Cell1, Cell2, Cell2, Cell 3
324
//		Cell4, Cell2, Cell2, Cell 5
325
FCKTableHandler._CreateTableMap = function( table )
326
{
327
	var aRows = table.rows ;
328
 
329
	// Row and Collumn counters.
330
	var r = -1 ;
331
 
332
	var aMap = new Array() ;
333
 
334
	for ( var i = 0 ; i < aRows.length ; i++ )
335
	{
336
		r++ ;
337
		if ( !aMap[r] )
338
			aMap[r] = new Array() ;
339
 
340
		var c = -1 ;
341
 
342
		for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
343
		{
344
			var oCell = aRows[i].cells[j] ;
345
 
346
			c++ ;
347
			while ( aMap[r][c] )
348
				c++ ;
349
 
350
			var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
351
			var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
352
 
353
			for ( var rs = 0 ; rs < iRowSpan ; rs++ )
354
			{
355
				if ( !aMap[r + rs] )
356
					aMap[r + rs] = new Array() ;
357
 
358
				for ( var cs = 0 ; cs < iColSpan ; cs++ )
359
				{
360
					aMap[r + rs][c + cs] = aRows[i].cells[j] ;
361
				}
362
			}
363
 
364
			c += iColSpan - 1 ;
365
		}
366
	}
367
	return aMap ;
368
}
369
 
370
FCKTableHandler.ClearRow = function( tr )
371
{
372
	// Get the array of row's cells.
373
	var aCells = tr.cells ;
374
 
375
	// Replace the contents of each cell with "nothing".
376
	for ( var i = 0 ; i < aCells.length ; i++ )
377
	{
378
		if ( FCKBrowserInfo.IsGecko )
379
			aCells[i].innerHTML = GECKO_BOGUS ;
380
		else
381
			aCells[i].innerHTML = '' ;
382
	}
383
}