1
var FCKDragTableHandler =
6
"_MouseMoveMode" : 0, // 0 - find candidate cells for resizing, 1 - drag to resize
14
"_IsInsideNode" : function( w, domNode, pos )
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 )
25
"_GetBorderCells" : function( w, tableNode, tableMap, mouse )
27
// Enumerate all the cells in the table.
29
for ( var i = 0 ; i < tableNode.rows.length ; i++ )
31
var r = tableNode.rows[i] ;
32
for ( var j = 0 ; j < r.cells.length ; j++ )
33
cells.push( r.cells[j] ) ;
36
if ( cells.length < 1 )
39
// Get the cells whose right or left border is nearest to the mouse cursor's x coordinate.
40
var minRxDist = null ;
45
for ( var i = 0 ; i < cells.length ; i++ )
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 ) ) ) )
61
var rowNode = FCKTools.GetElementAscensor( rbCell, "tr" ) ;
62
var cellIndex = rbCell.cellIndex + 1 ;
63
if ( cellIndex >= rowNode.cells.length )
65
lbCell = rowNode.cells.item( cellIndex ) ;
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] ;
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 )
79
if ( lxDist > 0 && minRxDist > 0 && lxDist > 3 )
82
return { "leftCell" : rbCell, "rightCell" : lbCell } ;
84
"_GetResizeBarPosition" : function()
86
var row = FCKTools.GetElementAscensor( this._RightCell, "tr" ) ;
87
return FCKTableHandler._GetCellIndexSpan( this._TableMap, row.rowIndex, this._RightCell ) ;
89
"_ResizeBarMouseDownListener" : function( evt )
91
if ( FCKDragTableHandler._LeftCell )
92
FCKDragTableHandler._MouseMoveMode = 1 ;
93
if ( FCKBrowserInfo.IsIE )
94
FCKDragTableHandler._ResizeBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 50 ;
96
FCKDragTableHandler._ResizeBar.style.opacity = 0.5 ;
97
FCKDragTableHandler._OriginalX = evt.clientX ;
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" );
105
for ( var r = 0 ; r < FCKDragTableHandler._TableMap.length ; r++ )
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 ;
119
FCKDragTableHandler._MinimumX = minX + offset.x ;
120
FCKDragTableHandler._MaximumX = maxX + offset.x ;
121
FCKDragTableHandler._LastX = null ;
123
if (evt.preventDefault)
124
evt.preventDefault();
126
evt.returnValue = false;
128
"_ResizeBarMouseUpListener" : function( evt )
130
FCKDragTableHandler._MouseMoveMode = 0 ;
131
FCKDragTableHandler._HideResizeBar() ;
133
if ( FCKDragTableHandler._LastX == null )
136
// Calculate the delta value.
137
var deltaX = FCKDragTableHandler._LastX - FCKDragTableHandler._OriginalX ;
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" ) ;
143
var tableMap = FCKDragTableHandler._TableMap ;
144
for ( var i = 0 ; i < tableMap.length ; i++ )
146
for ( var j = 0 ; j < tableMap[i].length ; j++ )
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 } ) ;
155
var guessItem = colArray[j] ;
156
if ( guessItem.colSpan > colSpan )
158
guessItem.width = width / colSpan ;
159
guessItem.colSpan = colSpan ;
165
// Find out the equivalent column index of the two cells selected for resizing.
166
colIndex = FCKDragTableHandler._GetResizeBarPosition() ;
168
// Note that colIndex must be at least 1 here, so it's safe to subtract 1 from it.
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 ;
175
// Clear all cell widths, delete all <col> elements from the table.
176
for ( var r = 0 ; r < table.rows.length ; r++ )
178
var row = table.rows.item( r ) ;
179
for ( var c = 0 ; c < row.cells.length ; c++ )
181
var cell = row.cells.item( c ) ;
183
cell.style.width = "" ;
186
var colElements = table.getElementsByTagName( "col" ) ;
187
for ( var i = colElements.length - 1 ; i >= 0 ; i-- )
188
colElements[i].parentNode.removeChild( colElements[i] ) ;
190
// Set new cell widths.
191
var processedCells = [] ;
192
for ( var i = 0 ; i < tableMap.length ; i++ )
194
for ( var j = 0 ; j < tableMap[i].length ; j++ )
196
var cell = tableMap[i][j] ;
197
if ( cell._Processed )
199
if ( tableMap[i][j-1] != cell )
200
cell.width = colArray[j].width ;
202
cell.width = parseInt( cell.width, 10 ) + parseInt( colArray[j].width, 10 ) ;
203
if ( tableMap[i][j+1] != cell )
205
processedCells.push( cell ) ;
206
cell._Processed = true ;
210
for ( var i = 0 ; i < processedCells.length ; i++ )
212
if ( FCKBrowserInfo.IsIE )
213
processedCells[i].removeAttribute( '_Processed' ) ;
215
delete processedCells[i]._Processed ;
218
FCKDragTableHandler._LastX = null ;
220
"_ResizeBarMouseMoveListener" : function( evt )
222
if ( FCKDragTableHandler._MouseMoveMode == 0 )
223
return FCKDragTableHandler._MouseFindHandler( FCK, evt ) ;
225
return FCKDragTableHandler._MouseDragHandler( FCK, evt ) ;
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 )
235
var attrGuess = parseInt( table.cellPadding, 10 ) * 2 ;
236
var cssGuess = null ;
237
if ( typeof( window.getComputedStyle ) == "function" )
239
var styleObj = window.getComputedStyle( cell, null ) ;
240
cssGuess = parseInt( styleObj.getPropertyValue( "padding-left" ), 10 ) +
241
parseInt( styleObj.getPropertyValue( "padding-right" ), 10 ) ;
244
cssGuess = parseInt( cell.currentStyle.paddingLeft, 10 ) + parseInt (cell.currentStyle.paddingRight, 10 ) ;
246
var cssRuntime = cell.style.padding ;
247
if ( isFinite( cssRuntime ) )
248
cssGuess = parseInt( cssRuntime, 10 ) * 2 ;
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 ) ;
259
attrGuess = parseInt( attrGuess, 10 ) ;
260
cssGuess = parseInt( cssGuess, 10 ) ;
261
if ( isNaN( attrGuess ) )
263
if ( isNaN( cssGuess ) )
265
return Math.max( attrGuess, cssGuess ) ;
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 )
274
var clientWidth = cell.clientWidth ;
275
if ( isNaN( clientWidth ) )
277
return clientWidth - this._GetCellPadding( table, cell ) ;
279
"MouseMoveListener" : function( FCK, evt )
281
if ( FCKDragTableHandler._MouseMoveMode == 0 )
282
return FCKDragTableHandler._MouseFindHandler( FCK, evt ) ;
284
return FCKDragTableHandler._MouseDragHandler( FCK, evt ) ;
286
"_MouseFindHandler" : function( FCK, evt )
288
if ( FCK.MouseDownFlag )
290
var node = evt.srcElement || evt.target ;
293
if ( ! node || node.nodeType != 1 )
295
this._HideResizeBar() ;
301
this._HideResizeBar() ;
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 )
312
var offset = this._GetIframeOffset() ;
318
if ( this._ResizeBar && this._LeftCell )
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 )
327
else if ( rxDist > 0 && lxDist <= 3 )
329
else if ( lxDist < 0 && rxDist >= -2 )
333
this._ShowResizeBar( FCK.EditorWindow,
334
FCKTools.GetElementAscensor( this._LeftCell, "table" ),
335
{ "x" : mouseX, "y" : mouseY } ) ;
340
var tagName = node.tagName.toLowerCase() ;
341
if ( tagName != "table" && tagName != "td" && tagName != "th" )
343
if ( this._LeftCell )
344
this._LeftCell = this._RightCell = this._TableMap = null ;
345
this._HideResizeBar() ;
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 } ) ;
352
if ( cellTuple == null )
354
if ( this._LeftCell )
355
this._LeftCell = this._RightCell = this._TableMap = null ;
356
this._HideResizeBar() ;
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 } ) ;
368
"_MouseDragHandler" : function( FCK, evt )
370
var mouse = { "x" : evt.clientX, "y" : evt.clientY } ;
372
// Convert mouse coordinates in reference to the outer iframe.
373
var node = evt.srcElement || evt.target ;
374
if ( FCKTools.GetElementDocument( node ) == FCK.EditorDocument )
376
var offset = this._GetIframeOffset() ;
377
mouse.x += offset.x ;
378
mouse.y += offset.y ;
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 ;
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 ;
391
"_ShowResizeBar" : function( w, table, mouse )
393
if ( this._ResizeBar == null )
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)" ;
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 ) ;
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);
416
filler.src = FCKConfig.BasePath + "images/spacer.gif" ;
417
filler.style.position = "absolute" ;
418
paddingBar.appendChild( filler ) ;
420
// Disable drag and drop, and selection for the filler image.
421
var disabledListener = function( evt )
423
if ( evt.preventDefault )
424
evt.preventDefault() ;
426
evt.returnValue = false ;
428
FCKTools.AddEventListener( filler, "dragstart", disabledListener ) ;
429
FCKTools.AddEventListener( filler, "selectstart", disabledListener ) ;
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 )
440
barHeight += tablePos.y ;
441
barTop -= tablePos.y ;
443
var bw = parseInt( table.border, 10 ) ;
446
var cs = parseInt( table.cellSpacing, 10 ) ;
449
var barWidth = Math.max( bw+100, cs+100 ) ;
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'
457
if ( FCKBrowserInfo.IsIE )
458
paddingBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 10 ;
460
paddingStyles.opacity = 0.1 ;
462
FCKDomTools.SetElementStyles( paddingBar, paddingStyles ) ;
463
var filler = paddingBar.getElementsByTagName( "img" )[0] ;
465
FCKDomTools.SetElementStyles( filler,
467
width : paddingBar.offsetWidth + 'px',
468
height : barHeight + 'px'
471
barWidth = Math.max( bw, cs, 3 ) ;
472
var visibleBar = null ;
473
if ( paddingBar.getElementsByTagName( "div" ).length < 1 )
475
visibleBar = this._doc.createElement( "div" ) ;
476
this._avoidStyles( visibleBar );
477
visibleBar.setAttribute('_fcktemp', true);
478
paddingBar.appendChild( visibleBar ) ;
481
visibleBar = paddingBar.getElementsByTagName( "div" )[0] ;
483
FCKDomTools.SetElementStyles( visibleBar,
485
position : 'absolute',
486
backgroundColor : 'blue',
487
width : barWidth + 'px',
488
height : barHeight + 'px',
493
"_HideResizeBar" : function()
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,
504
"_GetIframeOffset" : function ()
506
return FCKTools.GetDocumentPosition( window, FCK.EditingArea.IFrame ) ;
508
"_GetTablePosition" : function ( w, table )
510
return FCKTools.GetWindowPosition( w, table ) ;
512
"_avoidStyles" : function( element )
514
FCKDomTools.SetElementStyles( element,
517
backgroundImage : 'none',
524
FCK.Events.AttachEvent( "OnMouseMove", FCKDragTableHandler.MouseMoveListener ) ;