Project

General

Profile

1
var FCKDragTableHandler =
2
{
3
	"_DragState" : 0,
4
	"_LeftCell" : null,
5
	"_RightCell" : null,
6
	"_MouseMoveMode" : 0,	// 0 - find candidate cells for resizing, 1 - drag to resize
7
	"_ResizeBar" : null,
8
	"_OriginalX" : null,
9
	"_MinimumX" : null,
10
	"_MaximumX" : null,
11
	"_LastX" : null,
12
	"_TableMap" : null,
13
	"_doc" : document,
14
	"_IsInsideNode" : function( w, domNode, pos )
15
	{
16
		var myCoords = FCKTools.GetWindowPosition( w, domNode ) ;
17
		var xMin = myCoords.x ;
18
		var yMin = myCoords.y ;
19
		var xMax = parseInt( xMin, 10 ) + parseInt( domNode.offsetWidth, 10 ) ;
20
		var yMax = parseInt( yMin, 10 ) + parseInt( domNode.offsetHeight, 10 ) ;
21
		if ( pos.x >= xMin && pos.x <= xMax && pos.y >= yMin && pos.y <= yMax )
22
			return true;
23
		return false;
24
	},
25
	"_GetBorderCells" : function( w, tableNode, tableMap, mouse )
26
	{
27
		// Enumerate all the cells in the table.
28
		var cells = [] ;
29
		for ( var i = 0 ; i < tableNode.rows.length ; i++ )
30
		{
31
			var r = tableNode.rows[i] ;
32
			for ( var j = 0 ; j < r.cells.length ; j++ )
33
				cells.push( r.cells[j] ) ;
34
		}
35

    
36
		if ( cells.length < 1 )
37
			return null ;
38

    
39
		// Get the cells whose right or left border is nearest to the mouse cursor's x coordinate.
40
		var minRxDist = null ;
41
		var lxDist = null ;
42
		var minYDist = null ;
43
		var rbCell = null ;
44
		var lbCell = null ;
45
		for ( var i = 0 ; i < cells.length ; i++ )
46
		{
47
			var pos = FCKTools.GetWindowPosition( w, cells[i] ) ;
48
			var rightX = pos.x + parseInt( cells[i].clientWidth, 10 ) ;
49
			var rxDist = mouse.x - rightX ;
50
			var yDist = mouse.y - ( pos.y + ( cells[i].clientHeight / 2 ) ) ;
51
			if ( minRxDist == null ||
52
					( Math.abs( rxDist ) <= Math.abs( minRxDist ) &&
53
					  ( minYDist == null || Math.abs( yDist ) <= Math.abs( minYDist ) ) ) )
54
			{
55
				minRxDist = rxDist ;
56
				minYDist = yDist ;
57
				rbCell = cells[i] ;
58
			}
59
		}
60
		/*
61
		var rowNode = FCKTools.GetElementAscensor( rbCell, "tr" ) ;
62
		var cellIndex = rbCell.cellIndex + 1 ;
63
		if ( cellIndex >= rowNode.cells.length )
64
			return null ;
65
		lbCell = rowNode.cells.item( cellIndex ) ;
66
		*/
67
		var rowIdx = rbCell.parentNode.rowIndex ;
68
		var colIdx = FCKTableHandler._GetCellIndexSpan( tableMap, rowIdx, rbCell ) ;
69
		var colSpan = isNaN( rbCell.colSpan ) ? 1 : rbCell.colSpan ;
70
		lbCell = tableMap[rowIdx][colIdx + colSpan] ;
71

    
72
		if ( ! lbCell )
73
			return null ;
74

    
75
		// Abort if too far from the border.
76
		lxDist = mouse.x - FCKTools.GetWindowPosition( w, lbCell ).x ;
77
		if ( lxDist < 0 && minRxDist < 0 && minRxDist < -2 )
78
			return null ;
79
		if ( lxDist > 0 && minRxDist > 0 && lxDist > 3 )
80
			return null ;
81

    
82
		return { "leftCell" : rbCell, "rightCell" : lbCell } ;
83
	},
84
	"_GetResizeBarPosition" : function()
85
	{
86
		var row = FCKTools.GetElementAscensor( this._RightCell, "tr" ) ;
87
		return FCKTableHandler._GetCellIndexSpan( this._TableMap, row.rowIndex, this._RightCell ) ;
88
	},
89
	"_ResizeBarMouseDownListener" : function( evt )
90
	{
91
		if ( FCKDragTableHandler._LeftCell )
92
			FCKDragTableHandler._MouseMoveMode = 1 ;
93
		if ( FCKBrowserInfo.IsIE )
94
			FCKDragTableHandler._ResizeBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 50 ;
95
		else
96
			FCKDragTableHandler._ResizeBar.style.opacity = 0.5 ;
97
		FCKDragTableHandler._OriginalX = evt.clientX ;
98

    
99
		// Calculate maximum and minimum x-coordinate delta.
100
		var borderIndex = FCKDragTableHandler._GetResizeBarPosition() ;
101
		var offset = FCKDragTableHandler._GetIframeOffset();
102
		var table = FCKTools.GetElementAscensor( FCKDragTableHandler._LeftCell, "table" );
103
		var minX = null ;
104
		var maxX = null ;
105
		for ( var r = 0 ; r < FCKDragTableHandler._TableMap.length ; r++ )
106
		{
107
			var leftCell = FCKDragTableHandler._TableMap[r][borderIndex - 1] ;
108
			var rightCell = FCKDragTableHandler._TableMap[r][borderIndex] ;
109
			var leftPosition = FCKTools.GetWindowPosition( FCK.EditorWindow, leftCell ) ;
110
			var rightPosition = FCKTools.GetWindowPosition( FCK.EditorWindow, rightCell ) ;
111
			var leftPadding = FCKDragTableHandler._GetCellPadding( table, leftCell ) ;
112
			var rightPadding = FCKDragTableHandler._GetCellPadding( table, rightCell ) ;
113
			if ( minX == null || leftPosition.x + leftPadding > minX )
114
				minX = leftPosition.x + leftPadding ;
115
			if ( maxX == null || rightPosition.x + rightCell.clientWidth - rightPadding < maxX )
116
				maxX = rightPosition.x + rightCell.clientWidth - rightPadding ;
117
		}
118

    
119
		FCKDragTableHandler._MinimumX = minX + offset.x ;
120
		FCKDragTableHandler._MaximumX = maxX + offset.x ;
121
		FCKDragTableHandler._LastX = null ;
122

    
123
		if (evt.preventDefault)
124
			evt.preventDefault();
125
		else
126
			evt.returnValue = false;
127
	},
128
	"_ResizeBarMouseUpListener" : function( evt )
129
	{
130
		FCKDragTableHandler._MouseMoveMode = 0 ;
131
		FCKDragTableHandler._HideResizeBar() ;
132

    
133
		if ( FCKDragTableHandler._LastX == null )
134
			return ;
135

    
136
		// Calculate the delta value.
137
		var deltaX = FCKDragTableHandler._LastX - FCKDragTableHandler._OriginalX ;
138

    
139
		// Then, build an array of current column width values.
140
		// This algorithm can be very slow if the cells have insane colSpan values. (e.g. colSpan=1000).
141
		var table = FCKTools.GetElementAscensor( FCKDragTableHandler._LeftCell, "table" ) ;
142
		var colArray = [] ;
143
		var tableMap = FCKDragTableHandler._TableMap ;
144
		for ( var i = 0 ; i < tableMap.length ; i++ )
145
		{
146
			for ( var j = 0 ; j < tableMap[i].length ; j++ )
147
			{
148
				var cell = tableMap[i][j] ;
149
				var width = FCKDragTableHandler._GetCellWidth( table, cell ) ;
150
				var colSpan = isNaN( cell.colSpan) ? 1 : cell.colSpan ;
151
				if ( colArray.length <= j )
152
					colArray.push( { width : width / colSpan, colSpan : colSpan } ) ;
153
				else
154
				{
155
					var guessItem = colArray[j] ;
156
					if ( guessItem.colSpan > colSpan )
157
					{
158
						guessItem.width = width / colSpan ;
159
						guessItem.colSpan = colSpan ;
160
					}
161
				}
162
			}
163
		}
164

    
165
		// Find out the equivalent column index of the two cells selected for resizing.
166
		colIndex = FCKDragTableHandler._GetResizeBarPosition() ;
167

    
168
		// Note that colIndex must be at least 1 here, so it's safe to subtract 1 from it.
169
		colIndex-- ;
170

    
171
		// Modify the widths in the colArray according to the mouse coordinate delta value.
172
		colArray[colIndex].width += deltaX ;
173
		colArray[colIndex + 1].width -= deltaX ;
174

    
175
		// Clear all cell widths, delete all <col> elements from the table.
176
		for ( var r = 0 ; r < table.rows.length ; r++ )
177
		{
178
			var row = table.rows.item( r ) ;
179
			for ( var c = 0 ; c < row.cells.length ; c++ )
180
			{
181
				var cell = row.cells.item( c ) ;
182
				cell.width = "" ;
183
				cell.style.width = "" ;
184
			}
185
		}
186
		var colElements = table.getElementsByTagName( "col" ) ;
187
		for ( var i = colElements.length - 1 ; i >= 0 ; i-- )
188
			colElements[i].parentNode.removeChild( colElements[i] ) ;
189

    
190
		// Set new cell widths.
191
		var processedCells = [] ;
192
		for ( var i = 0 ; i < tableMap.length ; i++ )
193
		{
194
			for ( var j = 0 ; j < tableMap[i].length ; j++ )
195
			{
196
				var cell = tableMap[i][j] ;
197
				if ( cell._Processed )
198
					continue ;
199
				if ( tableMap[i][j-1] != cell )
200
					cell.width = colArray[j].width ;
201
				else
202
					cell.width = parseInt( cell.width, 10 ) + parseInt( colArray[j].width, 10 ) ;
203
				if ( tableMap[i][j+1] != cell )
204
				{
205
					processedCells.push( cell ) ;
206
					cell._Processed = true ;
207
				}
208
			}
209
		}
210
		for ( var i = 0 ; i < processedCells.length ; i++ )
211
		{
212
			if ( FCKBrowserInfo.IsIE )
213
				processedCells[i].removeAttribute( '_Processed' ) ;
214
			else
215
				delete processedCells[i]._Processed ;
216
		}
217

    
218
		FCKDragTableHandler._LastX = null ;
219
	},
220
	"_ResizeBarMouseMoveListener" : function( evt )
221
	{
222
		if ( FCKDragTableHandler._MouseMoveMode == 0 )
223
			return FCKDragTableHandler._MouseFindHandler( FCK, evt ) ;
224
		else
225
			return FCKDragTableHandler._MouseDragHandler( FCK, evt ) ;
226
	},
227
	// Calculate the padding of a table cell.
228
	// It returns the value of paddingLeft + paddingRight of a table cell.
229
	// This function is used, in part, to calculate the width parameter that should be used for setting cell widths.
230
	// The equation in question is clientWidth = paddingLeft + paddingRight + width.
231
	// So that width = clientWidth - paddingLeft - paddingRight.
232
	// The return value of this function must be pixel accurate acorss all supported browsers, so be careful if you need to modify it.
233
	"_GetCellPadding" : function( table, cell )
234
	{
235
		var attrGuess = parseInt( table.cellPadding, 10 ) * 2 ;
236
		var cssGuess = null ;
237
		if ( typeof( window.getComputedStyle ) == "function" )
238
		{
239
			var styleObj = window.getComputedStyle( cell, null ) ;
240
			cssGuess = parseInt( styleObj.getPropertyValue( "padding-left" ), 10 ) +
241
				parseInt( styleObj.getPropertyValue( "padding-right" ), 10 ) ;
242
		}
243
		else
244
			cssGuess = parseInt( cell.currentStyle.paddingLeft, 10 ) + parseInt (cell.currentStyle.paddingRight, 10 ) ;
245

    
246
		var cssRuntime = cell.style.padding ;
247
		if ( isFinite( cssRuntime ) )
248
			cssGuess = parseInt( cssRuntime, 10 ) * 2 ;
249
		else
250
		{
251
			cssRuntime = cell.style.paddingLeft ;
252
			if ( isFinite( cssRuntime ) )
253
				cssGuess = parseInt( cssRuntime, 10 ) ;
254
			cssRuntime = cell.style.paddingRight ;
255
			if ( isFinite( cssRuntime ) )
256
				cssGuess += parseInt( cssRuntime, 10 ) ;
257
		}
258

    
259
		attrGuess = parseInt( attrGuess, 10 ) ;
260
		cssGuess = parseInt( cssGuess, 10 ) ;
261
		if ( isNaN( attrGuess ) )
262
			attrGuess = 0 ;
263
		if ( isNaN( cssGuess ) )
264
			cssGuess = 0 ;
265
		return Math.max( attrGuess, cssGuess ) ;
266
	},
267
	// Calculate the real width of the table cell.
268
	// The real width of the table cell is the pixel width that you can set to the width attribute of the table cell and after
269
	// that, the table cell should be of exactly the same width as before.
270
	// The real width of a table cell can be calculated as:
271
	// width = clientWidth - paddingLeft - paddingRight.
272
	"_GetCellWidth" : function( table, cell )
273
	{
274
		var clientWidth = cell.clientWidth ;
275
		if ( isNaN( clientWidth ) )
276
			clientWidth = 0 ;
277
		return clientWidth - this._GetCellPadding( table, cell ) ;
278
	},
279
	"MouseMoveListener" : function( FCK, evt )
280
	{
281
		if ( FCKDragTableHandler._MouseMoveMode == 0 )
282
			return FCKDragTableHandler._MouseFindHandler( FCK, evt ) ;
283
		else
284
			return FCKDragTableHandler._MouseDragHandler( FCK, evt ) ;
285
	},
286
	"_MouseFindHandler" : function( FCK, evt )
287
	{
288
		if ( FCK.MouseDownFlag )
289
			return ;
290
		var node = evt.srcElement || evt.target ;
291
		try
292
		{
293
			if ( ! node || node.nodeType != 1 )
294
			{
295
				this._HideResizeBar() ;
296
				return ;
297
			}
298
		}
299
		catch ( e )
300
		{
301
			this._HideResizeBar() ;
302
			return ;
303
		}
304

    
305
		// Since this function might be called from the editing area iframe or the outer fckeditor iframe,
306
		// the mouse point coordinates from evt.clientX/Y can have different reference points.
307
		// We need to resolve the mouse pointer position relative to the editing area iframe.
308
		var mouseX = evt.clientX ;
309
		var mouseY = evt.clientY ;
310
		if ( FCKTools.GetElementDocument( node ) == document )
311
		{
312
			var offset = this._GetIframeOffset() ;
313
			mouseX -= offset.x ;
314
			mouseY -= offset.y ;
315
		}
316

    
317

    
318
		if ( this._ResizeBar && this._LeftCell )
319
		{
320
			var leftPos = FCKTools.GetWindowPosition( FCK.EditorWindow, this._LeftCell ) ;
321
			var rightPos = FCKTools.GetWindowPosition( FCK.EditorWindow, this._RightCell ) ;
322
			var rxDist = mouseX - ( leftPos.x + this._LeftCell.clientWidth ) ;
323
			var lxDist = mouseX - rightPos.x ;
324
			var inRangeFlag = false ;
325
			if ( lxDist >= 0 && rxDist <= 0 )
326
				inRangeFlag = true ;
327
			else if ( rxDist > 0 && lxDist <= 3 )
328
				inRangeFlag = true ;
329
			else if ( lxDist < 0 && rxDist >= -2 )
330
				inRangeFlag = true ;
331
			if ( inRangeFlag )
332
			{
333
				this._ShowResizeBar( FCK.EditorWindow,
334
					FCKTools.GetElementAscensor( this._LeftCell, "table" ),
335
					{ "x" : mouseX, "y" : mouseY } ) ;
336
				return ;
337
			}
338
		}
339

    
340
		var tagName = node.tagName.toLowerCase() ;
341
		if ( tagName != "table" && tagName != "td" && tagName != "th" )
342
		{
343
			if ( this._LeftCell )
344
				this._LeftCell = this._RightCell = this._TableMap = null ;
345
			this._HideResizeBar() ;
346
			return ;
347
		}
348
		node = FCKTools.GetElementAscensor( node, "table" ) ;
349
		var tableMap = FCKTableHandler._CreateTableMap( node ) ;
350
		var cellTuple = this._GetBorderCells( FCK.EditorWindow, node, tableMap, { "x" : mouseX, "y" : mouseY } ) ;
351

    
352
		if ( cellTuple == null )
353
		{
354
			if ( this._LeftCell )
355
				this._LeftCell = this._RightCell = this._TableMap = null ;
356
			this._HideResizeBar() ;
357
		}
358
		else
359
		{
360
			this._LeftCell = cellTuple["leftCell"] ;
361
			this._RightCell = cellTuple["rightCell"] ;
362
			this._TableMap = tableMap ;
363
			this._ShowResizeBar( FCK.EditorWindow,
364
					FCKTools.GetElementAscensor( this._LeftCell, "table" ),
365
					{ "x" : mouseX, "y" : mouseY } ) ;
366
		}
367
	},
368
	"_MouseDragHandler" : function( FCK, evt )
369
	{
370
		var mouse = { "x" : evt.clientX, "y" : evt.clientY } ;
371

    
372
		// Convert mouse coordinates in reference to the outer iframe.
373
		var node = evt.srcElement || evt.target ;
374
		if ( FCKTools.GetElementDocument( node ) == FCK.EditorDocument )
375
		{
376
			var offset = this._GetIframeOffset() ;
377
			mouse.x += offset.x ;
378
			mouse.y += offset.y ;
379
		}
380

    
381
		// Calculate the mouse position delta and see if we've gone out of range.
382
		if ( mouse.x >= this._MaximumX - 5 )
383
			mouse.x = this._MaximumX - 5 ;
384
		if ( mouse.x <= this._MinimumX + 5 )
385
			mouse.x = this._MinimumX + 5 ;
386

    
387
		var docX = mouse.x + FCKTools.GetScrollPosition( window ).X ;
388
		this._ResizeBar.style.left = ( docX - this._ResizeBar.offsetWidth / 2 ) + "px" ;
389
		this._LastX = mouse.x ;
390
	},
391
	"_ShowResizeBar" : function( w, table, mouse )
392
	{
393
		if ( this._ResizeBar == null )
394
		{
395
			this._ResizeBar = this._doc.createElement( "div" ) ;
396
			var paddingBar = this._ResizeBar ;
397
			var paddingStyles = { 'position' : 'absolute', 'cursor' : 'e-resize' } ;
398
			if ( FCKBrowserInfo.IsIE )
399
				paddingStyles.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=10,enabled=true)" ;
400
			else
401
				paddingStyles.opacity = 0.10 ;
402
			FCKDomTools.SetElementStyles( paddingBar, paddingStyles ) ;
403
			this._avoidStyles( paddingBar );
404
			paddingBar.setAttribute('_fcktemp', true);
405
			this._doc.body.appendChild( paddingBar ) ;
406
			FCKTools.AddEventListener( paddingBar, "mousemove", this._ResizeBarMouseMoveListener ) ;
407
			FCKTools.AddEventListener( paddingBar, "mousedown", this._ResizeBarMouseDownListener ) ;
408
			FCKTools.AddEventListener( document, "mouseup", this._ResizeBarMouseUpListener ) ;
409
			FCKTools.AddEventListener( FCK.EditorDocument, "mouseup", this._ResizeBarMouseUpListener ) ;
410

    
411
			// IE doesn't let the tranparent part of the padding block to receive mouse events unless there's something inside.
412
			// So we need to create a spacer image to fill the block up.
413
			var filler = this._doc.createElement( "img" ) ;
414
			filler.setAttribute('_fcktemp', true);
415
			filler.border = 0 ;
416
			filler.src = FCKConfig.BasePath + "images/spacer.gif" ;
417
			filler.style.position = "absolute" ;
418
			paddingBar.appendChild( filler ) ;
419

    
420
			// Disable drag and drop, and selection for the filler image.
421
			var disabledListener = function( evt )
422
			{
423
				if ( evt.preventDefault )
424
					evt.preventDefault() ;
425
				else
426
					evt.returnValue = false ;
427
			}
428
			FCKTools.AddEventListener( filler, "dragstart", disabledListener ) ;
429
			FCKTools.AddEventListener( filler, "selectstart", disabledListener ) ;
430
		}
431

    
432
		var paddingBar = this._ResizeBar ;
433
		var offset = this._GetIframeOffset() ;
434
		var tablePos = this._GetTablePosition( w, table ) ;
435
		var barHeight = table.offsetHeight ;
436
		var barTop = offset.y + tablePos.y ;
437
		// Do not let the resize bar intrude into the toolbar area.
438
		if ( tablePos.y < 0 )
439
		{
440
			barHeight += tablePos.y ;
441
			barTop -= tablePos.y ;
442
		}
443
		var bw = parseInt( table.border, 10 ) ;
444
		if ( isNaN( bw ) )
445
			bw = 0 ;
446
		var cs = parseInt( table.cellSpacing, 10 ) ;
447
		if ( isNaN( cs ) )
448
			cs = 0 ;
449
		var barWidth = Math.max( bw+100, cs+100 ) ;
450
		var paddingStyles =
451
		{
452
			'top'		: barTop + 'px',
453
			'height'	: barHeight + 'px',
454
			'width'		: barWidth + 'px',
455
			'left'		: ( offset.x + mouse.x + FCKTools.GetScrollPosition( w ).X - barWidth / 2 ) + 'px'
456
		} ;
457
		if ( FCKBrowserInfo.IsIE )
458
			paddingBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 10 ;
459
		else
460
			paddingStyles.opacity = 0.1 ;
461

    
462
		FCKDomTools.SetElementStyles( paddingBar, paddingStyles ) ;
463
		var filler = paddingBar.getElementsByTagName( "img" )[0] ;
464

    
465
		FCKDomTools.SetElementStyles( filler,
466
			{
467
				width	: paddingBar.offsetWidth + 'px',
468
				height	: barHeight + 'px'
469
			} ) ;
470

    
471
		barWidth = Math.max( bw, cs, 3 ) ;
472
		var visibleBar = null ;
473
		if ( paddingBar.getElementsByTagName( "div" ).length < 1 )
474
		{
475
			visibleBar = this._doc.createElement( "div" ) ;
476
			this._avoidStyles( visibleBar );
477
			visibleBar.setAttribute('_fcktemp', true);
478
			paddingBar.appendChild( visibleBar ) ;
479
		}
480
		else
481
			visibleBar = paddingBar.getElementsByTagName( "div" )[0] ;
482

    
483
		FCKDomTools.SetElementStyles( visibleBar,
484
			{
485
				position		: 'absolute',
486
				backgroundColor	: 'blue',
487
				width			: barWidth + 'px',
488
				height			: barHeight + 'px',
489
				left			: '50px',
490
				top				: '0px'
491
			} ) ;
492
	},
493
	"_HideResizeBar" : function()
494
	{
495
		if ( this._ResizeBar )
496
			// IE bug: display : none does not hide the resize bar for some reason.
497
			// so set the position to somewhere invisible.
498
			FCKDomTools.SetElementStyles( this._ResizeBar,
499
				{
500
					top		: '-100000px',
501
					left	: '-100000px'
502
				} ) ;
503
	},
504
	"_GetIframeOffset" : function ()
505
	{
506
		return FCKTools.GetDocumentPosition( window, FCK.EditingArea.IFrame ) ;
507
	},
508
	"_GetTablePosition" : function ( w, table )
509
	{
510
		return FCKTools.GetWindowPosition( w, table ) ;
511
	},
512
	"_avoidStyles" : function( element )
513
	{
514
		FCKDomTools.SetElementStyles( element,
515
			{
516
				padding		: '0',
517
				backgroundImage	: 'none',
518
				border		: '0'
519
			} ) ;
520
	},
521
	"Reset" : function()
522
	{
523
		FCKDragTableHandler._LeftCell = FCKDragTableHandler._RightCell = FCKDragTableHandler._TableMap = null ;
524
	}
525

    
526
};
527

    
528
FCK.Events.AttachEvent( "OnMouseMove", FCKDragTableHandler.MouseMoveListener ) ;
529
FCK.Events.AttachEvent( "OnAfterSetHTML", FCKDragTableHandler.Reset ) ;
    (1-1/1)