1var 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 "_IsInsideNode" : function( w, domNode, pos ) 14 { 15 var myCoords = FCKTools.GetWindowPosition( w, domNode ) ; 16 var xMin = myCoords.x ; 17 var yMin = myCoords.y ; 18 var xMax = parseInt( xMin, 10 ) + parseInt( domNode.offsetWidth, 10 ) ; 19 var yMax = parseInt( yMin, 10 ) + parseInt( domNode.offsetHeight, 10 ) ; 20 if ( pos.x >= xMin && pos.x <= xMax && pos.y >= yMin && pos.y <= yMax ) 21 return true; 22 return false; 23 }, 24 "_GetBorderCells" : function( w, tableNode, tableMap, mouse ) 25 { 26 // Enumerate all the cells in the table. 27 var cells = [] ; 28 for ( var i = 0 ; i < tableNode.rows.length ; i++ ) 29 { 30 var r = tableNode.rows[i] ; 31 for ( var j = 0 ; j < r.cells.length ; j++ ) 32 cells.push( r.cells[j] ) ; 33 } 34 35 if ( cells.length < 1 ) 36 return null ; 37 38 // Get the cells whose right or left border is nearest to the mouse cursor's x coordinate. 39 var minRxDist = null ; 40 var lxDist = null ; 41 var minYDist = null ; 42 var rbCell = null ; 43 var lbCell = null ; 44 for ( var i = 0 ; i < cells.length ; i++ ) 45 { 46 var pos = FCKTools.GetWindowPosition( w, cells[i] ) ; 47 var rightX = pos.x + parseInt( cells[i].clientWidth, 10 ) ; 48 var rxDist = mouse.x - rightX ; 49 var yDist = mouse.y - ( pos.y + ( cells[i].clientHeight / 2 ) ) ; 50 if ( minRxDist == null || 51 ( Math.abs( rxDist ) <= Math.abs( minRxDist ) && 52 ( minYDist == null || Math.abs( yDist ) <= Math.abs( minYDist ) ) ) ) 53 { 54 minRxDist = rxDist ; 55 minYDist = yDist ; 56 rbCell = cells[i] ; 57 } 58 } 59 /* 60 var rowNode = FCKTools.GetElementAscensor( rbCell, "tr" ) ; 61 var cellIndex = rbCell.cellIndex + 1 ; 62 if ( cellIndex >= rowNode.cells.length ) 63 return null ; 64 lbCell = rowNode.cells.item( cellIndex ) ; 65 */ 66 var rowIdx = rbCell.parentNode.rowIndex ; 67 var colIdx = FCKTableHandler._GetCellIndexSpan( tableMap, rowIdx, rbCell ) ; 68 var colSpan = isNaN( rbCell.colSpan ) ? 1 : rbCell.colSpan ; 69 lbCell = tableMap[rowIdx][colIdx + colSpan] ; 70 71 if ( ! lbCell ) 72 return null ; 73 74 // Abort if too far from the border. 75 lxDist = mouse.x - FCKTools.GetWindowPosition( w, lbCell ).x ; 76 if ( lxDist < 0 && minRxDist < 0 && minRxDist < -2 ) 77 return null ; 78 if ( lxDist > 0 && minRxDist > 0 && lxDist > 3 ) 79 return null ; 80 81 return { "leftCell" : rbCell, "rightCell" : lbCell } ; 82 }, 83 "_GetResizeBarPosition" : function() 84 { 85 var row = FCKTools.GetElementAscensor( this._RightCell, "tr" ) ; 86 return FCKTableHandler._GetCellIndexSpan( this._TableMap, row.rowIndex, this._RightCell ) ; 87 }, 88 "_ResizeBarMouseDownListener" : function( evt ) 89 { 90 if ( ! evt ) 91 evt = window.event ; 92 if ( FCKDragTableHandler._LeftCell ) 93 FCKDragTableHandler._MouseMoveMode = 1 ; 94 if ( FCKBrowserInfo.IsIE ) 95 FCKDragTableHandler._ResizeBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 50 ; 96 else 97 FCKDragTableHandler._ResizeBar.style.opacity = 0.5 ; 98 FCKDragTableHandler._OriginalX = evt.clientX ; 99 100 // Calculate maximum and minimum x-coordinate delta. 101 var borderIndex = FCKDragTableHandler._GetResizeBarPosition() ; 102 var offset = FCKTools.GetDocumentPosition( window, FCK.EditingArea.IFrame ) ; 103 var table = FCKTools.GetElementAscensor( FCKDragTableHandler._LeftCell, "table" ); 104 var minX = null ; 105 var maxX = null ; 106 for ( var r = 0 ; r < FCKDragTableHandler._TableMap.length ; r++ ) 107 { 108 var leftCell = FCKDragTableHandler._TableMap[r][borderIndex - 1] ; 109 var rightCell = FCKDragTableHandler._TableMap[r][borderIndex] ; 110 var leftPosition = FCKTools.GetWindowPosition( FCK.EditorWindow, leftCell ) ; 111 var rightPosition = FCKTools.GetWindowPosition( FCK.EditorWindow, rightCell ) ; 112 var leftPadding = FCKDragTableHandler._GetCellPadding( table, leftCell ) ; 113 var rightPadding = FCKDragTableHandler._GetCellPadding( table, rightCell ) ; 114 if ( minX == null || leftPosition.x + leftPadding > minX ) 115 minX = leftPosition.x + leftPadding ; 116 if ( maxX == null || rightPosition.x + rightCell.clientWidth - rightPadding < maxX ) 117 maxX = rightPosition.x + rightCell.clientWidth - rightPadding ; 118 } 119 120 FCKDragTableHandler._MinimumX = minX + offset.x ; 121 FCKDragTableHandler._MaximumX = maxX + offset.x ; 122 FCKDragTableHandler._LastX = null ; 123 }, 124 "_ResizeBarMouseUpListener" : function( evt ) 125 { 126 if ( ! evt ) 127 evt = window.event ; 128 FCKDragTableHandler._MouseMoveMode = 0 ; 129 FCKDragTableHandler._HideResizeBar() ; 130 131 if ( FCKDragTableHandler._LastX == null ) 132 return ; 133 134 // Calculate the delta value. 135 var deltaX = FCKDragTableHandler._LastX - FCKDragTableHandler._OriginalX ; 136 137 // Then, build an array of current column width values. 138 // This algorithm can be very slow if the cells have insane colSpan values. (e.g. colSpan=1000). 139 var table = FCKTools.GetElementAscensor( FCKDragTableHandler._LeftCell, "table" ) ; 140 var colArray = [] ; 141 var tableMap = FCKDragTableHandler._TableMap ; 142 for ( var i = 0 ; i < tableMap.length ; i++ ) 143 { 144 for ( var j = 0 ; j < tableMap[i].length ; j++ ) 145 { 146 var cell = tableMap[i][j] ; 147 var width = FCKDragTableHandler._GetCellWidth( table, cell ) ; 148 var colSpan = isNaN( cell.colSpan) ? 1 : cell.colSpan ; 149 if ( colArray.length <= j ) 150 colArray.push( { width : width / colSpan, colSpan : colSpan } ) ; 151 else 152 { 153 var guessItem = colArray[j] ; 154 if ( guessItem.colSpan > colSpan ) 155 { 156 guessItem.width = width / colSpan ; 157 guessItem.colSpan = colSpan ; 158 } 159 } 160 } 161 } 162 163 // Find out the equivalent column index of the two cells selected for resizing. 164 colIndex = FCKDragTableHandler._GetResizeBarPosition() ; 165 166 // Note that colIndex must be at least 1 here, so it's safe to subtract 1 from it. 167 colIndex-- ; 168 169 // Modify the widths in the colArray according to the mouse coordinate delta value. 170 colArray[colIndex].width += deltaX ; 171 colArray[colIndex + 1].width -= deltaX ; 172 173 // Clear all cell widths, delete all <col> elements from the table. 174 for ( var r = 0 ; r < table.rows.length ; r++ ) 175 { 176 var row = table.rows.item( r ) ; 177 for ( var c = 0 ; c < row.cells.length ; c++ ) 178 { 179 var cell = row.cells.item( c ) ; 180 cell.width = "" ; 181 cell.style.width = "" ; 182 } 183 } 184 var colElements = table.getElementsByTagName( "col" ) ; 185 for ( var i = colElements.length - 1 ; i >= 0 ; i-- ) 186 colElements[i].parentNode.removeChild( colElements[i] ) ; 187 188 // Set new cell widths. 189 var processedCells = [] ; 190 for ( var i = 0 ; i < tableMap.length ; i++ ) 191 { 192 for ( var j = 0 ; j < tableMap[i].length ; j++ ) 193 { 194 var cell = tableMap[i][j] ; 195 if ( cell._Processed ) 196 continue ; 197 if ( tableMap[i][j-1] != cell ) 198 cell.width = colArray[j].width ; 199 else 200 cell.width = parseInt( cell.width, 10 ) + parseInt( colArray[j].width, 10 ) ; 201 if ( tableMap[i][j+1] != cell ) 202 { 203 processedCells.push( cell ) ; 204 cell._Processed = true ; 205 } 206 } 207 } 208 for ( var i = 0 ; i < processedCells.length ; i++ ) 209 { 210 if ( FCKBrowserInfo.IsIE ) 211 processedCells[i].removeAttribute( '_Processed' ) ; 212 else 213 delete processedCells[i]._Processed ; 214 } 215 216 FCKDragTableHandler._LastX = null ; 217 }, 218 "_ResizeBarMouseMoveListener" : function( evt ) 219 { 220 if ( ! evt ) 221 evt = window.event ; 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 ( node.ownerDocument == document ) 311 { 312 var offset = FCKTools.GetDocumentPosition( window, FCK.EditingArea.IFrame ) ; 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 ( node.ownerDocument == FCK.EditorDocument ) 375 { 376 var offset = FCKTools.GetDocumentPosition( window, FCK.EditingArea.IFrame ) ; 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 = document.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 document.body.appendChild( paddingBar ) ; 404 FCKTools.AddEventListener( paddingBar, "mousemove", this._ResizeBarMouseMoveListener ) ; 405 FCKTools.AddEventListener( paddingBar, "mousedown", this._ResizeBarMouseDownListener ) ; 406 FCKTools.AddEventListener( document, "mouseup", this._ResizeBarMouseUpListener ) ; 407 FCKTools.AddEventListener( FCK.EditorDocument, "mouseup", this._ResizeBarMouseUpListener ) ; 408 409 // IE doesn't let the tranparent part of the padding block to receive mouse events unless there's something inside. 410 // So we need to create a spacer image to fill the block up. 411 var filler = document.createElement( "img" ) ; 412 filler.border = 0 ; 413 filler.src = FCKConfig.BasePath + "images/spacer.gif" ; 414 filler.style.position = "absolute" ; 415 paddingBar.appendChild( filler ) ; 416 417 // Disable drag and drop, and selection for the filler image. 418 var disabledListener = function( evt ) 419 { 420 if ( ! evt ) 421 evt = window.event ; 422 if ( evt.preventDefault ) 423 evt.preventDefault() ; 424 else 425 evt.returnValue = false ; 426 } 427 FCKTools.AddEventListener( filler, "dragstart", disabledListener ) ; 428 FCKTools.AddEventListener( filler, "selectstart", disabledListener ) ; 429 } 430 431 var paddingBar = this._ResizeBar ; 432 var offset = FCKTools.GetDocumentPosition( window, FCK.EditingArea.IFrame ) ; 433 var tablePos = FCKTools.GetWindowPosition( w, table ) ; 434 var barHeight = table.offsetHeight ; 435 var barTop = offset.y + tablePos.y ; 436 // Do not let the resize bar intrude into the toolbar area. 437 if ( tablePos.y < 0 ) 438 { 439 barHeight += tablePos.y ; 440 barTop -= tablePos.y ; 441 } 442 var bw = parseInt( table.border, 10 ) ; 443 if ( isNaN( bw ) ) 444 bw = 0 ; 445 var cs = parseInt( table.cellSpacing, 10 ) ; 446 if ( isNaN( cs ) ) 447 cs = 0 ; 448 var barWidth = Math.max( bw+100, cs+100 ) ; 449 var paddingStyles = 450 { 451 'top' : barTop + 'px', 452 'height' : barHeight + 'px', 453 'width' : barWidth + 'px', 454 'left' : ( offset.x + mouse.x + FCKTools.GetScrollPosition( w ).X - barWidth / 2 ) + 'px' 455 } ; 456 if ( FCKBrowserInfo.IsIE ) 457 paddingBar.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 10 ; 458 else 459 paddingStyles.opacity = 0.1 ; 460 461 FCKDomTools.SetElementStyles( paddingBar, paddingStyles ) ; 462 var filler = paddingBar.getElementsByTagName( "img" )[0] ; 463 464 FCKDomTools.SetElementStyles( filler, 465 { 466 width : paddingBar.offsetWidth + 'px', 467 height : barHeight + 'px' 468 } ) ; 469 470 barWidth = Math.max( bw, cs, 3 ) ; 471 var visibleBar = null ; 472 if ( paddingBar.getElementsByTagName( "div" ).length < 1 ) 473 { 474 visibleBar = document.createElement( "div" ) ; 475 paddingBar.appendChild( visibleBar ) ; 476 } 477 else 478 visibleBar = paddingBar.getElementsByTagName( "div" )[0] ; 479 480 FCKDomTools.SetElementStyles( visibleBar, 481 { 482 position : 'absolute', 483 backgroundColor : 'blue', 484 width : barWidth + 'px', 485 height : barHeight + 'px', 486 left : '50px', 487 top : '0px' 488 } ) ; 489 }, 490 "_HideResizeBar" : function() 491 { 492 if ( this._ResizeBar ) 493 // IE bug: display : none does not hide the resize bar for some reason. 494 // so set the position to somewhere invisible. 495 FCKDomTools.SetElementStyles( this._ResizeBar, 496 { 497 top : '-100000px', 498 left : '-100000px' 499 } ) ; 500 } 501}; 502 503FCK.Events.AttachEvent( "OnMouseMove", FCKDragTableHandler.MouseMoveListener ) ; 504