src/cm/media/js/client/c_selection.js
changeset 0 40c8f766c9b8
child 341 053551f213fb
equal deleted inserted replaced
-1:000000000000 0:40c8f766c9b8
       
     1 getWrapperAncestor = function(elt) {
       
     2 	var parent = elt ;
       
     3 	while (parent != null) {
       
     4     	if (CY.DOM.hasClass(parent, 'c-s')) 
       
     5     		return parent ;
       
     6     	parent = parent.parentNode ;
       
     7 	}
       
     8 	return null ; 
       
     9 }
       
    10 
       
    11 hasWrapperAncestor = function(elt) {
       
    12 	return (getWrapperAncestor(elt) != null) ;
       
    13 /*	var parent = elt ;
       
    14 	while (parent != null) {
       
    15     	if (CY.DOM.hasClass(parent, 'c-s')) 
       
    16     		return true ;
       
    17     	parent = parent.parentNode ;
       
    18 	}
       
    19 	return false ;*/ 
       
    20 }
       
    21 
       
    22 // returns null or :
       
    23 // {'text' : textcontent, 'start': {'elt':startNode, 'nbChar':startOffset(==number of characters to selection start in the start node},
       
    24 // 'end': ....}
       
    25 // the text attribute is informational having it empty doesn't mean selection is empty !!
       
    26 
       
    27 // when selection starts/ends in/on a non textual element (<hr/> for example) we very often have anchorNode/focusNode == body elt
       
    28 // TODO adapt this body case by considering offset ( cf. http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html)
       
    29 getSelectionInfo  = function () {
       
    30 	var startNode = null, endNode = null, startOffset = 0, endOffset = 0, text = '' ;
       
    31 	
       
    32 	if (window.getSelection) { // everything else than IE
       
    33 		var userSelection = window.getSelection();
       
    34 
       
    35 		if (userSelection.rangeCount > 0) {
       
    36 			var range = userSelection.getRangeAt(0) ;
       
    37 			text = range.toString() ;
       
    38 			if (text != "")  {
       
    39 				
       
    40 				// selection occured from right to left ? :
       
    41 				var r1 = document.createRange() ;r1.setStart(userSelection.anchorNode, userSelection.anchorOffset) ;r1.collapse(true) ;
       
    42 				var r2 = document.createRange() ;r2.setEnd(userSelection.focusNode, userSelection.focusOffset) ;r2.collapse(false) ;
       
    43 				var leftToRight = (r2.compareBoundaryPoints(2, r1) == 1) ; // 2 is for END_TO_END
       
    44 //				CY.log("leftToRight : " + leftToRight) ;
       
    45 				startNode = (leftToRight) ? userSelection.anchorNode.parentNode : userSelection.focusNode.parentNode ;  
       
    46 				innerStartNode = (leftToRight) ? userSelection.anchorNode : userSelection.focusNode ;
       
    47 				endNode = (leftToRight) ? userSelection.focusNode.parentNode : userSelection.anchorNode.parentNode;
       
    48 				innerEndNode = (leftToRight) ? userSelection.focusNode : userSelection.anchorNode;
       
    49 					
       
    50 				startOffset = (leftToRight) ? userSelection.anchorOffset : userSelection.focusOffset;
       
    51 				endOffset = (leftToRight) ? userSelection.focusOffset : userSelection.anchorOffset ;
       
    52 
       
    53 				if (!hasWrapperAncestor(endNode) && hasWrapperAncestor(startNode)){
       
    54 					var r3 = document.createRange() ;
       
    55 					r3.setStart(innerStartNode, startOffset) ;
       
    56 
       
    57 					var csStartAncestor = getWrapperAncestor(startNode) ;
       
    58 					var next = csStartAncestor ;
       
    59 					r3.setEndAfter(next) ;
       
    60 					
       
    61 					var ind = parseInt(csStartAncestor.id.substring('sv_'.length)) ;
       
    62 					while(r3.toString().length < range.toString().length) {
       
    63 							ind++ ;
       
    64 							var node = CY.get("#sv_"+ind) ;
       
    65 							if (node) {
       
    66 								next = CY.Node.getDOMNode(node) ;
       
    67 								r3.setEndAfter(next) ;
       
    68 							}
       
    69 							else 
       
    70 								break ;
       
    71 					}
       
    72 					endNode = next.lastChild ;
       
    73 					endOffset = CY.DOM.getText(endNode).length ;
       
    74 				}
       
    75 				else if (!hasWrapperAncestor(startNode) && hasWrapperAncestor(endNode)){
       
    76 					var r3 = document.createRange() ;
       
    77 					r3.setEnd(innerEndNode, endOffset) ;
       
    78 
       
    79 					var csEndAncestor = getWrapperAncestor(endNode) ;
       
    80 					var prev = csEndAncestor ;
       
    81 					r3.setStartBefore(prev) ;
       
    82 					
       
    83 					var ind = parseInt(csEndAncestor.id.substring('sv_'.length)) ;
       
    84 					while(r3.toString().length < range.toString().length) {
       
    85 							ind-- ;
       
    86 							var node = CY.get("#sv_"+ind) ;
       
    87 							if (node) {
       
    88 								prev = CY.Node.getDOMNode(node) ;
       
    89 								r3.setStartBefore(prev) ;
       
    90 							}
       
    91 							else 
       
    92 								break ;
       
    93 					}
       
    94 					startNode = prev.firstChild ;
       
    95 					startOffset = 0 ;
       
    96 				}
       
    97 				else if (!hasWrapperAncestor(startNode) && !hasWrapperAncestor(endNode)){
       
    98 					var textLength = text.length ;
       
    99 					
       
   100 					// gather nodes with id sv_xxxx as candidates for start ancestor
       
   101 					var startNodeInds = [] ;
       
   102 					for (var ind = 0 ;  ; ind++) {
       
   103 						var svNode = CY.get("#sv_"+ind) ;
       
   104 						if (svNode == null) {
       
   105 							break;
       
   106 						}
       
   107 						else {
       
   108 							var svText = svNode.get("text") ;
       
   109 							if (text.indexOf(svText) == 0) {
       
   110 								startNodeInds.push(ind) ;
       
   111 							}
       
   112 						}
       
   113 					}
       
   114 					
       
   115 					// gather nodes with id sv_xxxx as candidates for end ancestor
       
   116 					var endNodeInds = [] ;
       
   117 					for (var ind = 0 ;  ; ind++) {
       
   118 						var svNode = CY.get("#sv_"+ind) ;
       
   119 						if (svNode == null) {
       
   120 							break;
       
   121 						}
       
   122 						else {
       
   123 							var svText = svNode.get("text") ;
       
   124 							if (text.indexOf(svText) == (textLength - svText.length)) { // i.e. the selection exactly ends with svText
       
   125 								endNodeInds.push(ind) ;
       
   126 							}
       
   127 						}
       
   128 					}
       
   129 
       
   130 					var stop = false ;
       
   131 					for (var i = 0 ; i < startNodeInds.length ; i++) {
       
   132 						for (var j = 0 ; j < endNodeInds.length ; j++) {
       
   133 							var r4 = document.createRange() ;
       
   134 							
       
   135 							var s = CY.Node.getDOMNode(CY.get("#sv_"+startNodeInds[i])) ; var e = CY.Node.getDOMNode(CY.get("#sv_"+endNodeInds[j])) ;
       
   136 							
       
   137 							r4.setStartBefore(s) ; r4.setEndAfter(CY.Node.getDOMNode(e)) ;
       
   138 							
       
   139 							// does r4 starts after range start and r4 ends before range end ? 
       
   140 							if ((-1 < r4.compareBoundaryPoints(0, range)) && (1 > r4.compareBoundaryPoints(2, range))) { 
       
   141 								startNode = s.firstChild ;
       
   142 								startOffset = 0 ;
       
   143 								endNode = e.lastChild ;
       
   144 								endOffset = CY.DOM.getText(e).length ;
       
   145 								
       
   146 								stop = true ; 
       
   147 								break ;
       
   148 							}
       
   149 						}
       
   150 						if (stop)
       
   151 							break ;
       
   152 					}							
       
   153 				}				
       
   154 				
       
   155 				r1.detach() ;
       
   156 				r2.detach() ;
       
   157 			}
       
   158 			else 
       
   159 				return null ;
       
   160 		}
       
   161 		else 
       
   162 			return null ;
       
   163 		
       
   164 	}
       
   165 	else if (document.selection) { // IE case
       
   166 		var rng = document.selection.createRange();
       
   167 		if (rng.text.length == 0) 
       
   168 			return null ;
       
   169 		var el = rng.parentElement();
       
   170 
       
   171 		// duplicate the range and collapse it to its start, to ask IE the parent element of the start textNode.		
       
   172 		var rngStart = rng.duplicate();
       
   173 		var rngEnd = rng.duplicate();
       
   174 
       
   175 		rngStart.collapse(true); // collapse to start
       
   176 		rngEnd.collapse(false);  // collapse to end
       
   177 		
       
   178 		startNode = rngStart.parentElement() ;
       
   179 		while(rngStart.moveStart('character', -1) != 0) {
       
   180 			if (rngStart.parentElement() != startNode)
       
   181 				break ;
       
   182 			startOffset++ ;
       
   183 		}
       
   184 		endNode = rngEnd.parentElement() ;
       
   185 		while(rngEnd.moveEnd('character', -1) != 0) {
       
   186 			if (rngEnd.parentElement() != endNode)
       
   187 				break ;
       
   188 			endOffset++ ;
       
   189 		}
       
   190 		
       
   191 		text = rng.text ;
       
   192 	}
       
   193 	
       
   194 	if (!hasWrapperAncestor(startNode) || !hasWrapperAncestor(endNode)){
       
   195 		// CY.log('no wrapper on one end') ;
       
   196 		return null ;
       
   197 	}
       
   198 	return {'text' : text, 'start' : {'elt':startNode, 'offset':startOffset}, 'end' : {'elt':endNode, 'offset':endOffset}} ;
       
   199 }