1 var FCKDragTableHandler =
\r
6 "_MouseMoveMode" : 0, // 0 - find candidate cells for resizing, 1 - drag to resize
\r
14 "_IsInsideNode" : function( w, domNode, pos )
\r
16 var myCoords = FCKTools.GetWindowPosition( w, domNode ) ;
\r
17 var xMin = myCoords.x ;
\r
18 var yMin = myCoords.y ;
\r
19 var xMax = parseInt( xMin, 10 ) + parseInt( domNode.offsetWidth, 10 ) ;
\r
20 var yMax = parseInt( yMin, 10 ) + parseInt( domNode.offsetHeight, 10 ) ;
\r
21 if ( pos.x >= xMin && pos.x <= xMax && pos.y >= yMin && pos.y <= yMax )
\r
25 "_GetBorderCells" : function( w, tableNode, tableMap, mouse )
\r
27 // Enumerate all the cells in the table.
\r
29 for ( var i = 0 ; i < tableNode.rows.length ; i++ )
\r
31 var r = tableNode.rows[i] ;
\r
32 for ( var j = 0 ; j < r.cells.length ; j++ )
\r
33 cells.push( r.cells[j] ) ;
\r
36 if ( cells.length < 1 )
\r
39 // Get the cells whose right or left border is nearest to the mouse cursor's x coordinate.
\r
40 var minRxDist = null ;
\r
42 var minYDist = null ;
\r
45 for ( var i = 0 ; i < cells.length ; i++ )
\r
47 var pos = FCKTools.GetWindowPosition( w, cells[i] ) ;
\r
48 var rightX = pos.x + parseInt( cells[i].clientWidth, 10 ) ;
\r
49 var rxDist = mouse.x - rightX ;
\r
50 var yDist = mouse.y - ( pos.y + ( cells[i].clientHeight / 2 ) ) ;
\r
51 if ( minRxDist == null ||
\r
52 ( Math.abs( rxDist ) <= Math.abs( minRxDist ) &&
\r
53 ( minYDist == null || Math.abs( yDist ) <= Math.abs( minYDist ) ) ) )
\r
55 minRxDist = rxDist ;
\r
61 var rowNode = FCKTools.GetElementAscensor( rbCell, "tr" ) ;
\r
62 var cellIndex = rbCell.cellIndex + 1 ;
\r
63 if ( cellIndex >= rowNode.cells.length )
\r
65 lbCell = rowNode.cells.item( cellIndex ) ;
\r
67 var rowIdx = rbCell.parentNode.rowIndex ;
\r
68 var colIdx = FCKTableHandler._GetCellIndexSpan( tableMap, rowIdx, rbCell ) ;
\r
69 var colSpan = isNaN( rbCell.colSpan ) ? 1 : rbCell.colSpan ;
\r
70 lbCell = tableMap[rowIdx][colIdx + colSpan] ;
\r
75 // Abort if too far from the border.
\r
76 lxDist = mouse.x - FCKTools.GetWindowPosition( w, lbCell ).x ;
\r
77 if ( lxDist < 0 && minRxDist < 0 && minRxDist < -2 )
\r
79 if ( lxDist > 0 && minRxDist > 0 && lxDist > 3 )
\r
82 return { "leftCell" : rbCell, "rightCell" : lbCell } ;
\r
84 "_GetResizeBarPosition" : function()
\r
86 var row = FCKTools.GetElementAscensor( this._RightCell, "tr" ) ;
\r
87 return FCKTableHandler._GetCellIndexSpan( this._TableMap, row.rowIndex, this._RightCell ) ;
\r
89 "_ResizeBarMouseDownListener" : function( evt )
\r
91 if ( FCKDragTableHandler._LeftCell )
\r
92 FCKDragTableHandler._MouseMoveMode = 1 ;
\r
93 if ( FCKBrowserInfo.IsIE )
\r
94 FCKDragTableHandler._ResizeBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 50 ;
\r
96 FCKDragTableHandler._ResizeBar.style.opacity = 0.5 ;
\r
97 FCKDragTableHandler._OriginalX = evt.clientX ;
\r
99 // Calculate maximum and minimum x-coordinate delta.
\r
100 var borderIndex = FCKDragTableHandler._GetResizeBarPosition() ;
\r
101 var offset = FCKDragTableHandler._GetIframeOffset();
\r
102 var table = FCKTools.GetElementAscensor( FCKDragTableHandler._LeftCell, "table" );
\r
105 for ( var r = 0 ; r < FCKDragTableHandler._TableMap.length ; r++ )
\r
107 var leftCell = FCKDragTableHandler._TableMap[r][borderIndex - 1] ;
\r
108 var rightCell = FCKDragTableHandler._TableMap[r][borderIndex] ;
\r
109 var leftPosition = FCKTools.GetWindowPosition( FCK.EditorWindow, leftCell ) ;
\r
110 var rightPosition = FCKTools.GetWindowPosition( FCK.EditorWindow, rightCell ) ;
\r
111 var leftPadding = FCKDragTableHandler._GetCellPadding( table, leftCell ) ;
\r
112 var rightPadding = FCKDragTableHandler._GetCellPadding( table, rightCell ) ;
\r
113 if ( minX == null || leftPosition.x + leftPadding > minX )
\r
114 minX = leftPosition.x + leftPadding ;
\r
115 if ( maxX == null || rightPosition.x + rightCell.clientWidth - rightPadding < maxX )
\r
116 maxX = rightPosition.x + rightCell.clientWidth - rightPadding ;
\r
119 FCKDragTableHandler._MinimumX = minX + offset.x ;
\r
120 FCKDragTableHandler._MaximumX = maxX + offset.x ;
\r
121 FCKDragTableHandler._LastX = null ;
\r
123 if (evt.preventDefault)
\r
124 evt.preventDefault();
\r
126 evt.returnValue = false;
\r
128 "_ResizeBarMouseUpListener" : function( evt )
\r
130 FCKDragTableHandler._MouseMoveMode = 0 ;
\r
131 FCKDragTableHandler._HideResizeBar() ;
\r
133 if ( FCKDragTableHandler._LastX == null )
\r
136 // Calculate the delta value.
\r
137 var deltaX = FCKDragTableHandler._LastX - FCKDragTableHandler._OriginalX ;
\r
139 // Then, build an array of current column width values.
\r
140 // This algorithm can be very slow if the cells have insane colSpan values. (e.g. colSpan=1000).
\r
141 var table = FCKTools.GetElementAscensor( FCKDragTableHandler._LeftCell, "table" ) ;
\r
142 var colArray = [] ;
\r
143 var tableMap = FCKDragTableHandler._TableMap ;
\r
144 for ( var i = 0 ; i < tableMap.length ; i++ )
\r
146 for ( var j = 0 ; j < tableMap[i].length ; j++ )
\r
148 var cell = tableMap[i][j] ;
\r
149 var width = FCKDragTableHandler._GetCellWidth( table, cell ) ;
\r
150 var colSpan = isNaN( cell.colSpan) ? 1 : cell.colSpan ;
\r
151 if ( colArray.length <= j )
\r
152 colArray.push( { width : width / colSpan, colSpan : colSpan } ) ;
\r
155 var guessItem = colArray[j] ;
\r
156 if ( guessItem.colSpan > colSpan )
\r
158 guessItem.width = width / colSpan ;
\r
159 guessItem.colSpan = colSpan ;
\r
165 // Find out the equivalent column index of the two cells selected for resizing.
\r
166 colIndex = FCKDragTableHandler._GetResizeBarPosition() ;
\r
168 // Note that colIndex must be at least 1 here, so it's safe to subtract 1 from it.
\r
171 // Modify the widths in the colArray according to the mouse coordinate delta value.
\r
172 colArray[colIndex].width += deltaX ;
\r
173 colArray[colIndex + 1].width -= deltaX ;
\r
175 // Clear all cell widths, delete all <col> elements from the table.
\r
176 for ( var r = 0 ; r < table.rows.length ; r++ )
\r
178 var row = table.rows.item( r ) ;
\r
179 for ( var c = 0 ; c < row.cells.length ; c++ )
\r
181 var cell = row.cells.item( c ) ;
\r
183 cell.style.width = "" ;
\r
186 var colElements = table.getElementsByTagName( "col" ) ;
\r
187 for ( var i = colElements.length - 1 ; i >= 0 ; i-- )
\r
188 colElements[i].parentNode.removeChild( colElements[i] ) ;
\r
190 // Set new cell widths.
\r
191 var processedCells = [] ;
\r
192 for ( var i = 0 ; i < tableMap.length ; i++ )
\r
194 for ( var j = 0 ; j < tableMap[i].length ; j++ )
\r
196 var cell = tableMap[i][j] ;
\r
197 if ( cell._Processed )
\r
199 if ( tableMap[i][j-1] != cell )
\r
200 cell.width = colArray[j].width ;
\r
202 cell.width = parseInt( cell.width, 10 ) + parseInt( colArray[j].width, 10 ) ;
\r
203 if ( tableMap[i][j+1] != cell )
\r
205 processedCells.push( cell ) ;
\r
206 cell._Processed = true ;
\r
210 for ( var i = 0 ; i < processedCells.length ; i++ )
\r
212 if ( FCKBrowserInfo.IsIE )
\r
213 processedCells[i].removeAttribute( '_Processed' ) ;
\r
215 delete processedCells[i]._Processed ;
\r
218 FCKDragTableHandler._LastX = null ;
\r
220 "_ResizeBarMouseMoveListener" : function( evt )
\r
222 if ( FCKDragTableHandler._MouseMoveMode == 0 )
\r
223 return FCKDragTableHandler._MouseFindHandler( FCK, evt ) ;
\r
225 return FCKDragTableHandler._MouseDragHandler( FCK, evt ) ;
\r
227 // Calculate the padding of a table cell.
\r
228 // It returns the value of paddingLeft + paddingRight of a table cell.
\r
229 // This function is used, in part, to calculate the width parameter that should be used for setting cell widths.
\r
230 // The equation in question is clientWidth = paddingLeft + paddingRight + width.
\r
231 // So that width = clientWidth - paddingLeft - paddingRight.
\r
232 // The return value of this function must be pixel accurate acorss all supported browsers, so be careful if you need to modify it.
\r
233 "_GetCellPadding" : function( table, cell )
\r
235 var attrGuess = parseInt( table.cellPadding, 10 ) * 2 ;
\r
236 var cssGuess = null ;
\r
237 if ( typeof( window.getComputedStyle ) == "function" )
\r
239 var styleObj = window.getComputedStyle( cell, null ) ;
\r
240 cssGuess = parseInt( styleObj.getPropertyValue( "padding-left" ), 10 ) +
\r
241 parseInt( styleObj.getPropertyValue( "padding-right" ), 10 ) ;
\r
244 cssGuess = parseInt( cell.currentStyle.paddingLeft, 10 ) + parseInt (cell.currentStyle.paddingRight, 10 ) ;
\r
246 var cssRuntime = cell.style.padding ;
\r
247 if ( isFinite( cssRuntime ) )
\r
248 cssGuess = parseInt( cssRuntime, 10 ) * 2 ;
\r
251 cssRuntime = cell.style.paddingLeft ;
\r
252 if ( isFinite( cssRuntime ) )
\r
253 cssGuess = parseInt( cssRuntime, 10 ) ;
\r
254 cssRuntime = cell.style.paddingRight ;
\r
255 if ( isFinite( cssRuntime ) )
\r
256 cssGuess += parseInt( cssRuntime, 10 ) ;
\r
259 attrGuess = parseInt( attrGuess, 10 ) ;
\r
260 cssGuess = parseInt( cssGuess, 10 ) ;
\r
261 if ( isNaN( attrGuess ) )
\r
263 if ( isNaN( cssGuess ) )
\r
265 return Math.max( attrGuess, cssGuess ) ;
\r
267 // Calculate the real width of the table cell.
\r
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
\r
269 // that, the table cell should be of exactly the same width as before.
\r
270 // The real width of a table cell can be calculated as:
\r
271 // width = clientWidth - paddingLeft - paddingRight.
\r
272 "_GetCellWidth" : function( table, cell )
\r
274 var clientWidth = cell.clientWidth ;
\r
275 if ( isNaN( clientWidth ) )
\r
277 return clientWidth - this._GetCellPadding( table, cell ) ;
\r
279 "MouseMoveListener" : function( FCK, evt )
\r
281 if ( FCKDragTableHandler._MouseMoveMode == 0 )
\r
282 return FCKDragTableHandler._MouseFindHandler( FCK, evt ) ;
\r
284 return FCKDragTableHandler._MouseDragHandler( FCK, evt ) ;
\r
286 "_MouseFindHandler" : function( FCK, evt )
\r
288 if ( FCK.MouseDownFlag )
\r
290 var node = evt.srcElement || evt.target ;
\r
293 if ( ! node || node.nodeType != 1 )
\r
295 this._HideResizeBar() ;
\r
301 this._HideResizeBar() ;
\r
305 // Since this function might be called from the editing area iframe or the outer fckeditor iframe,
\r
306 // the mouse point coordinates from evt.clientX/Y can have different reference points.
\r
307 // We need to resolve the mouse pointer position relative to the editing area iframe.
\r
308 var mouseX = evt.clientX ;
\r
309 var mouseY = evt.clientY ;
\r
310 if ( FCKTools.GetElementDocument( node ) == document )
\r
312 var offset = this._GetIframeOffset() ;
\r
313 mouseX -= offset.x ;
\r
314 mouseY -= offset.y ;
\r
318 if ( this._ResizeBar && this._LeftCell )
\r
320 var leftPos = FCKTools.GetWindowPosition( FCK.EditorWindow, this._LeftCell ) ;
\r
321 var rightPos = FCKTools.GetWindowPosition( FCK.EditorWindow, this._RightCell ) ;
\r
322 var rxDist = mouseX - ( leftPos.x + this._LeftCell.clientWidth ) ;
\r
323 var lxDist = mouseX - rightPos.x ;
\r
324 var inRangeFlag = false ;
\r
325 if ( lxDist >= 0 && rxDist <= 0 )
\r
326 inRangeFlag = true ;
\r
327 else if ( rxDist > 0 && lxDist <= 3 )
\r
328 inRangeFlag = true ;
\r
329 else if ( lxDist < 0 && rxDist >= -2 )
\r
330 inRangeFlag = true ;
\r
333 this._ShowResizeBar( FCK.EditorWindow,
\r
334 FCKTools.GetElementAscensor( this._LeftCell, "table" ),
\r
335 { "x" : mouseX, "y" : mouseY } ) ;
\r
340 var tagName = node.tagName.toLowerCase() ;
\r
341 if ( tagName != "table" && tagName != "td" && tagName != "th" )
\r
343 if ( this._LeftCell )
\r
344 this._LeftCell = this._RightCell = this._TableMap = null ;
\r
345 this._HideResizeBar() ;
\r
348 node = FCKTools.GetElementAscensor( node, "table" ) ;
\r
349 var tableMap = FCKTableHandler._CreateTableMap( node ) ;
\r
350 var cellTuple = this._GetBorderCells( FCK.EditorWindow, node, tableMap, { "x" : mouseX, "y" : mouseY } ) ;
\r
352 if ( cellTuple == null )
\r
354 if ( this._LeftCell )
\r
355 this._LeftCell = this._RightCell = this._TableMap = null ;
\r
356 this._HideResizeBar() ;
\r
360 this._LeftCell = cellTuple["leftCell"] ;
\r
361 this._RightCell = cellTuple["rightCell"] ;
\r
362 this._TableMap = tableMap ;
\r
363 this._ShowResizeBar( FCK.EditorWindow,
\r
364 FCKTools.GetElementAscensor( this._LeftCell, "table" ),
\r
365 { "x" : mouseX, "y" : mouseY } ) ;
\r
368 "_MouseDragHandler" : function( FCK, evt )
\r
370 var mouse = { "x" : evt.clientX, "y" : evt.clientY } ;
\r
372 // Convert mouse coordinates in reference to the outer iframe.
\r
373 var node = evt.srcElement || evt.target ;
\r
374 if ( FCKTools.GetElementDocument( node ) == FCK.EditorDocument )
\r
376 var offset = this._GetIframeOffset() ;
\r
377 mouse.x += offset.x ;
\r
378 mouse.y += offset.y ;
\r
381 // Calculate the mouse position delta and see if we've gone out of range.
\r
382 if ( mouse.x >= this._MaximumX - 5 )
\r
383 mouse.x = this._MaximumX - 5 ;
\r
384 if ( mouse.x <= this._MinimumX + 5 )
\r
385 mouse.x = this._MinimumX + 5 ;
\r
387 var docX = mouse.x + FCKTools.GetScrollPosition( window ).X ;
\r
388 this._ResizeBar.style.left = ( docX - this._ResizeBar.offsetWidth / 2 ) + "px" ;
\r
389 this._LastX = mouse.x ;
\r
391 "_ShowResizeBar" : function( w, table, mouse )
\r
393 if ( this._ResizeBar == null )
\r
395 this._ResizeBar = this._doc.createElement( "div" ) ;
\r
396 var paddingBar = this._ResizeBar ;
\r
397 var paddingStyles = { 'position' : 'absolute', 'cursor' : 'e-resize' } ;
\r
398 if ( FCKBrowserInfo.IsIE )
\r
399 paddingStyles.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=10,enabled=true)" ;
\r
401 paddingStyles.opacity = 0.10 ;
\r
402 FCKDomTools.SetElementStyles( paddingBar, paddingStyles ) ;
\r
403 this._avoidStyles( paddingBar );
\r
404 paddingBar.setAttribute('_fcktemp', true);
\r
405 this._doc.body.appendChild( paddingBar ) ;
\r
406 FCKTools.AddEventListener( paddingBar, "mousemove", this._ResizeBarMouseMoveListener ) ;
\r
407 FCKTools.AddEventListener( paddingBar, "mousedown", this._ResizeBarMouseDownListener ) ;
\r
408 FCKTools.AddEventListener( document, "mouseup", this._ResizeBarMouseUpListener ) ;
\r
409 FCKTools.AddEventListener( FCK.EditorDocument, "mouseup", this._ResizeBarMouseUpListener ) ;
\r
411 // IE doesn't let the tranparent part of the padding block to receive mouse events unless there's something inside.
\r
412 // So we need to create a spacer image to fill the block up.
\r
413 var filler = this._doc.createElement( "img" ) ;
\r
414 filler.setAttribute('_fcktemp', true);
\r
415 filler.border = 0 ;
\r
416 filler.src = FCKConfig.BasePath + "images/spacer.gif" ;
\r
417 filler.style.position = "absolute" ;
\r
418 paddingBar.appendChild( filler ) ;
\r
420 // Disable drag and drop, and selection for the filler image.
\r
421 var disabledListener = function( evt )
\r
423 if ( evt.preventDefault )
\r
424 evt.preventDefault() ;
\r
426 evt.returnValue = false ;
\r
428 FCKTools.AddEventListener( filler, "dragstart", disabledListener ) ;
\r
429 FCKTools.AddEventListener( filler, "selectstart", disabledListener ) ;
\r
432 var paddingBar = this._ResizeBar ;
\r
433 var offset = this._GetIframeOffset() ;
\r
434 var tablePos = this._GetTablePosition( w, table ) ;
\r
435 var barHeight = table.offsetHeight ;
\r
436 var barTop = offset.y + tablePos.y ;
\r
437 // Do not let the resize bar intrude into the toolbar area.
\r
438 if ( tablePos.y < 0 )
\r
440 barHeight += tablePos.y ;
\r
441 barTop -= tablePos.y ;
\r
443 var bw = parseInt( table.border, 10 ) ;
\r
446 var cs = parseInt( table.cellSpacing, 10 ) ;
\r
449 var barWidth = Math.max( bw+100, cs+100 ) ;
\r
450 var paddingStyles =
\r
452 'top' : barTop + 'px',
\r
453 'height' : barHeight + 'px',
\r
454 'width' : barWidth + 'px',
\r
455 'left' : ( offset.x + mouse.x + FCKTools.GetScrollPosition( w ).X - barWidth / 2 ) + 'px'
\r
457 if ( FCKBrowserInfo.IsIE )
\r
458 paddingBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 10 ;
\r
460 paddingStyles.opacity = 0.1 ;
\r
462 FCKDomTools.SetElementStyles( paddingBar, paddingStyles ) ;
\r
463 var filler = paddingBar.getElementsByTagName( "img" )[0] ;
\r
465 FCKDomTools.SetElementStyles( filler,
\r
467 width : paddingBar.offsetWidth + 'px',
\r
468 height : barHeight + 'px'
\r
471 barWidth = Math.max( bw, cs, 3 ) ;
\r
472 var visibleBar = null ;
\r
473 if ( paddingBar.getElementsByTagName( "div" ).length < 1 )
\r
475 visibleBar = this._doc.createElement( "div" ) ;
\r
476 this._avoidStyles( visibleBar );
\r
477 visibleBar.setAttribute('_fcktemp', true);
\r
478 paddingBar.appendChild( visibleBar ) ;
\r
481 visibleBar = paddingBar.getElementsByTagName( "div" )[0] ;
\r
483 FCKDomTools.SetElementStyles( visibleBar,
\r
485 position : 'absolute',
\r
486 backgroundColor : 'blue',
\r
487 width : barWidth + 'px',
\r
488 height : barHeight + 'px',
\r
493 "_HideResizeBar" : function()
\r
495 if ( this._ResizeBar )
\r
496 // IE bug: display : none does not hide the resize bar for some reason.
\r
497 // so set the position to somewhere invisible.
\r
498 FCKDomTools.SetElementStyles( this._ResizeBar,
\r
504 "_GetIframeOffset" : function ()
\r
506 return FCKTools.GetDocumentPosition( window, FCK.EditingArea.IFrame ) ;
\r
508 "_GetTablePosition" : function ( w, table )
\r
510 return FCKTools.GetWindowPosition( w, table ) ;
\r
512 "_avoidStyles" : function( element )
\r
514 FCKDomTools.SetElementStyles( element,
\r
517 backgroundImage : 'none',
\r
521 "Reset" : function()
\r
523 FCKDragTableHandler._LeftCell = FCKDragTableHandler._RightCell = FCKDragTableHandler._TableMap = null ;
\r
528 FCK.Events.AttachEvent( "OnMouseMove", FCKDragTableHandler.MouseMoveListener ) ;
\r
529 FCK.Events.AttachEvent( "OnAfterSetHTML", FCKDragTableHandler.Reset ) ;
\r