fckw3crange.js
上传用户:ah_jiwei
上传日期:2022-07-24
资源大小:54044k
文件大小:13k
源码类别:

数据库编程

开发平台:

Visual C++

  1. /*
  2.  * FCKeditor - The text editor for Internet - http://www.fckeditor.net
  3.  * Copyright (C) 2003-2007 Frederico Caldeira Knabben
  4.  *
  5.  * == BEGIN LICENSE ==
  6.  *
  7.  * Licensed under the terms of any of the following licenses at your
  8.  * choice:
  9.  *
  10.  *  - GNU General Public License Version 2 or later (the "GPL")
  11.  *    http://www.gnu.org/licenses/gpl.html
  12.  *
  13.  *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
  14.  *    http://www.gnu.org/licenses/lgpl.html
  15.  *
  16.  *  - Mozilla Public License Version 1.1 or later (the "MPL")
  17.  *    http://www.mozilla.org/MPL/MPL-1.1.html
  18.  *
  19.  * == END LICENSE ==
  20.  *
  21.  * This class partially implements the W3C DOM Range for browser that don't
  22.  * support the standards (like IE):
  23.  * http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html
  24.  */
  25. var FCKW3CRange = function( parentDocument )
  26. {
  27. this._Document = parentDocument ;
  28. this.startContainer = null ;
  29. this.startOffset = null ;
  30. this.endContainer = null ;
  31. this.endOffset = null ;
  32. this.collapsed = true ;
  33. }
  34. FCKW3CRange.CreateRange = function( parentDocument )
  35. {
  36. // We could opt to use the Range implementation of the browsers. The problem
  37. // is that every browser have different bugs on their implementations,
  38. // mostly related to different interpretations of the W3C specifications.
  39. // So, for now, let's use our implementation and pray for browsers fixings
  40. // soon. Otherwise will go crazy on trying to find out workarounds.
  41. /*
  42. // Get the browser implementation of the range, if available.
  43. if ( parentDocument.createRange )
  44. {
  45. var range = parentDocument.createRange() ;
  46. if ( typeof( range.startContainer ) != 'undefined' )
  47. return range ;
  48. }
  49. */
  50. return new FCKW3CRange( parentDocument ) ;
  51. }
  52. FCKW3CRange.CreateFromRange = function( parentDocument, sourceRange )
  53. {
  54. var range = FCKW3CRange.CreateRange( parentDocument ) ;
  55. range.setStart( sourceRange.startContainer, sourceRange.startOffset ) ;
  56. range.setEnd( sourceRange.endContainer, sourceRange.endOffset ) ;
  57. return range ;
  58. }
  59. FCKW3CRange.prototype =
  60. {
  61. _UpdateCollapsed : function()
  62. {
  63.       this.collapsed = ( this.startContainer == this.endContainer && this.startOffset == this.endOffset ) ;
  64. },
  65. // W3C requires a check for the new position. If it is after the end
  66. // boundary, the range should be collapsed to the new start. It seams we
  67. // will not need this check for our use of this class so we can ignore it for now.
  68. setStart : function( refNode, offset )
  69. {
  70. this.startContainer = refNode ;
  71. this.startOffset = offset ;
  72. if ( !this.endContainer )
  73. {
  74. this.endContainer = refNode ;
  75. this.endOffset = offset ;
  76. }
  77. this._UpdateCollapsed() ;
  78. },
  79. // W3C requires a check for the new position. If it is before the start
  80. // boundary, the range should be collapsed to the new end. It seams we
  81. // will not need this check for our use of this class so we can ignore it for now.
  82. setEnd : function( refNode, offset )
  83. {
  84. this.endContainer = refNode ;
  85. this.endOffset = offset ;
  86. if ( !this.startContainer )
  87. {
  88. this.startContainer = refNode ;
  89. this.startOffset = offset ;
  90. }
  91. this._UpdateCollapsed() ;
  92. },
  93. setStartAfter : function( refNode )
  94. {
  95. this.setStart( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) + 1 ) ;
  96. },
  97. setStartBefore : function( refNode )
  98. {
  99. this.setStart( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) ) ;
  100. },
  101. setEndAfter : function( refNode )
  102. {
  103. this.setEnd( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) + 1 ) ;
  104. },
  105. setEndBefore : function( refNode )
  106. {
  107. this.setEnd( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) ) ;
  108. },
  109. collapse : function( toStart )
  110. {
  111. if ( toStart )
  112. {
  113. this.endContainer = this.startContainer ;
  114. this.endOffset = this.startOffset ;
  115. }
  116. else
  117. {
  118. this.startContainer = this.endContainer ;
  119. this.startOffset = this.endOffset ;
  120. }
  121. this.collapsed = true ;
  122. },
  123. selectNodeContents : function( refNode )
  124. {
  125. this.setStart( refNode, 0 ) ;
  126. this.setEnd( refNode, refNode.nodeType == 3 ? refNode.data.length : refNode.childNodes.length ) ;
  127. },
  128. insertNode : function( newNode )
  129. {
  130. var startContainer = this.startContainer ;
  131. var startOffset = this.startOffset ;
  132. // If we are in a text node.
  133. if ( startContainer.nodeType == 3 )
  134. {
  135. startContainer.splitText( startOffset ) ;
  136. // Check if it is necessary to update the end boundary.
  137. if ( startContainer == this.endContainer )
  138. this.setEnd( startContainer.nextSibling, this.endOffset - this.startOffset ) ;
  139. // Insert the new node it after the text node.
  140. FCKDomTools.InsertAfterNode( startContainer, newNode ) ;
  141. return ;
  142. }
  143. else
  144. {
  145. // Simply insert the new node before the current start node.
  146. startContainer.insertBefore( newNode, startContainer.childNodes[ startOffset ] || null ) ;
  147. // Check if it is necessary to update the end boundary.
  148. if ( startContainer == this.endContainer )
  149. {
  150. this.endOffset++ ;
  151. this.collapsed = false ;
  152. }
  153. }
  154. },
  155. deleteContents : function()
  156. {
  157. if ( this.collapsed )
  158. return ;
  159. this._ExecContentsAction( 0 ) ;
  160. },
  161. extractContents : function()
  162. {
  163. var docFrag = new FCKDocumentFragment( this._Document ) ;
  164. if ( !this.collapsed )
  165. this._ExecContentsAction( 1, docFrag ) ;
  166. return docFrag ;
  167. },
  168. // The selection may be lost when cloning (due to the splitText() call).
  169. cloneContents : function()
  170. {
  171. var docFrag = new FCKDocumentFragment( this._Document ) ;
  172. if ( !this.collapsed )
  173. this._ExecContentsAction( 2, docFrag ) ;
  174. return docFrag ;
  175. },
  176. _ExecContentsAction : function( action, docFrag )
  177. {
  178. var startNode = this.startContainer ;
  179. var endNode = this.endContainer ;
  180. var startOffset = this.startOffset ;
  181. var endOffset = this.endOffset ;
  182. var removeStartNode = false ;
  183. var removeEndNode = false ;
  184. // Check the start and end nodes and make the necessary removals or changes.
  185. // Start from the end, otherwise DOM mutations (splitText) made in the
  186. // start boundary may interfere on the results here.
  187. // For text containers, we must simply split the node and point to the
  188. // second part. The removal will be handled by the rest of the code .
  189. if ( endNode.nodeType == 3 )
  190. endNode = endNode.splitText( endOffset ) ;
  191. else
  192. {
  193. // If the end container has children and the offset is pointing
  194. // to a child, then we should start from it.
  195. if ( endNode.childNodes.length > 0 )
  196. {
  197. // If the offset points after the last node.
  198. if ( endOffset > endNode.childNodes.length - 1 )
  199. {
  200. // Let's create a temporary node and mark it for removal.
  201. endNode = FCKDomTools.InsertAfterNode( endNode.lastChild, this._Document.createTextNode('') ) ;
  202. removeEndNode = true ;
  203. }
  204. else
  205. endNode = endNode.childNodes[ endOffset ] ;
  206. }
  207. }
  208. // For text containers, we must simply split the node. The removal will
  209. // be handled by the rest of the code .
  210. if ( startNode.nodeType == 3 )
  211. {
  212. startNode.splitText( startOffset ) ;
  213. // In cases the end node is the same as the start node, the above
  214. // splitting will also split the end, so me must move the end to
  215. // the second part of the split.
  216. if ( startNode == endNode )
  217. endNode = startNode.nextSibling ;
  218. }
  219. else
  220. {
  221. // If the start container has children and the offset is pointing
  222. // to a child, then we should start from its previous sibling.
  223. if ( startNode.childNodes.length > 0 &&  startOffset <= startNode.childNodes.length - 1 )
  224. {
  225. // If the offset points to the first node, we don't have a
  226. // sibling, so let's use the first one, but mark it for removal.
  227. if ( startOffset == 0 )
  228. {
  229. // Let's create a temporary node and mark it for removal.
  230. startNode = startNode.insertBefore( this._Document.createTextNode(''), startNode.firstChild ) ;
  231. removeStartNode = true ;
  232. }
  233. else
  234. startNode = startNode.childNodes[ startOffset ].previousSibling ;
  235. }
  236. }
  237. // Get the parent nodes tree for the start and end boundaries.
  238. var startParents = FCKDomTools.GetParents( startNode ) ;
  239. var endParents = FCKDomTools.GetParents( endNode ) ;
  240. // Compare them, to find the top most siblings.
  241. var i, topStart, topEnd ;
  242. for ( i = 0 ; i < startParents.length ; i++ )
  243. {
  244. topStart = startParents[i] ;
  245. topEnd = endParents[i] ;
  246. // The compared nodes will match until we find the top most
  247. // siblings (different nodes that have the same parent).
  248. // "i" will hold the index in the parents array for the top
  249. // most element.
  250. if ( topStart != topEnd )
  251. break ;
  252. }
  253. var clone, levelStartNode, levelClone, currentNode, currentSibling ;
  254. if ( docFrag )
  255. clone = docFrag.RootNode ;
  256. // Remove all successive sibling nodes for every node in the
  257. // startParents tree.
  258. for ( var j = i ; j < startParents.length ; j++ )
  259. {
  260. levelStartNode = startParents[j] ;
  261. // For Extract and Clone, we must clone this level.
  262. if ( clone && levelStartNode != startNode ) // action = 0 = Delete
  263. levelClone = clone.appendChild( levelStartNode.cloneNode( levelStartNode == startNode ) ) ;
  264. currentNode = levelStartNode.nextSibling ;
  265. while( currentNode )
  266. {
  267. // Stop processing when the current node matches a node in the
  268. // endParents tree or if it is the endNode.
  269. if ( currentNode == endParents[j] || currentNode == endNode )
  270. break ;
  271. // Cache the next sibling.
  272. currentSibling = currentNode.nextSibling ;
  273. // If cloning, just clone it.
  274. if ( action == 2 ) // 2 = Clone
  275. clone.appendChild( currentNode.cloneNode( true ) ) ;
  276. else
  277. {
  278. // Both Delete and Extract will remove the node.
  279. currentNode.parentNode.removeChild( currentNode ) ;
  280. // When Extracting, move the removed node to the docFrag.
  281. if ( action == 1 ) // 1 = Extract
  282. clone.appendChild( currentNode ) ;
  283. }
  284. currentNode = currentSibling ;
  285. }
  286. if ( clone )
  287. clone = levelClone ;
  288. }
  289. if ( docFrag )
  290. clone = docFrag.RootNode ;
  291. // Remove all previous sibling nodes for every node in the
  292. // endParents tree.
  293. for ( var k = i ; k < endParents.length ; k++ )
  294. {
  295. levelStartNode = endParents[k] ;
  296. // For Extract and Clone, we must clone this level.
  297. if ( action > 0 && levelStartNode != endNode ) // action = 0 = Delete
  298. levelClone = clone.appendChild( levelStartNode.cloneNode( levelStartNode == endNode ) ) ;
  299. // The processing of siblings may have already been done by the parent.
  300. if ( !startParents[k] || levelStartNode.parentNode != startParents[k].parentNode )
  301. {
  302. currentNode = levelStartNode.previousSibling ;
  303. while( currentNode )
  304. {
  305. // Stop processing when the current node matches a node in the
  306. // startParents tree or if it is the startNode.
  307. if ( currentNode == startParents[k] || currentNode == startNode )
  308. break ;
  309. // Cache the next sibling.
  310. currentSibling = currentNode.previousSibling ;
  311. // If cloning, just clone it.
  312. if ( action == 2 ) // 2 = Clone
  313. clone.insertBefore( currentNode.cloneNode( true ), clone.firstChild ) ;
  314. else
  315. {
  316. // Both Delete and Extract will remove the node.
  317. currentNode.parentNode.removeChild( currentNode ) ;
  318. // When Extracting, mode the removed node to the docFrag.
  319. if ( action == 1 ) // 1 = Extract
  320. clone.insertBefore( currentNode, clone.firstChild ) ;
  321. }
  322. currentNode = currentSibling ;
  323. }
  324. }
  325. if ( clone )
  326. clone = levelClone ;
  327. }
  328. if ( action == 2 ) // 2 = Clone.
  329. {
  330. // No changes in the DOM should be done, so fix the split text (if any).
  331. var startTextNode = this.startContainer ;
  332. if ( startTextNode.nodeType == 3 )
  333. {
  334. startTextNode.data += startTextNode.nextSibling.data ;
  335. startTextNode.parentNode.removeChild( startTextNode.nextSibling ) ;
  336. }
  337. var endTextNode = this.endContainer ;
  338. if ( endTextNode.nodeType == 3 && endTextNode.nextSibling )
  339. {
  340. endTextNode.data += endTextNode.nextSibling.data ;
  341. endTextNode.parentNode.removeChild( endTextNode.nextSibling ) ;
  342. }
  343. }
  344. else
  345. {
  346. // Collapse the range.
  347. // If a node has been partially selected, collapse the range between
  348. // topStart and topEnd. Otherwise, simply collapse it to the start. (W3C specs).
  349. if ( topStart && topEnd && ( startNode.parentNode != topStart.parentNode || endNode.parentNode != topEnd.parentNode ) )
  350. {
  351. var endIndex = FCKDomTools.GetIndexOf( topEnd ) ;
  352. // If the start node is to be removed, we must correct the
  353. // index to reflect the removal.
  354. if ( removeStartNode && topEnd.parentNode == startNode.parentNode )
  355. endIndex-- ;
  356. this.setStart( topEnd.parentNode, endIndex ) ;
  357. }
  358. // Collapse it to the start.
  359. this.collapse( true ) ;
  360. }
  361. // Cleanup any marked node.
  362. if( removeStartNode )
  363. startNode.parentNode.removeChild( startNode ) ;
  364. if( removeEndNode && endNode.parentNode )
  365. endNode.parentNode.removeChild( endNode ) ;
  366. },
  367. cloneRange : function()
  368. {
  369. return FCKW3CRange.CreateFromRange( this._Document, this ) ;
  370. }
  371. } ;