ASPxClientHtmlEditorSelection =_aspxCreateClass(null, {
 constructor: function(htmlEditor) {
  this.clientSelection = ASPxClientHtmlEditorSelection.Create(htmlEditor);
  this.clientSelection.Save();
  this.isControlSelected = this.clientSelection.IsControl();
  this.html = this.clientSelection.GetHtmlText();
  this.text = this.clientSelection.GetText();
  this.selectedElement = this.clientSelection.GetParentElement();
 },
 Apply: function() {
  this.clientSelection.Restore();
 },
 GetIsControlSelected: function() {
  return this.isControlSelected;
 },
 GetSelectedElement: function() {
  return this.selectedElement;
 },
 GetHtml: function() {
  return this.html;
 },
 GetText: function() {
  return this.text;
 }
});
ASPxClientHtmlEditorSelection.Create = function(htmlEditor) {
 var contentWindow = htmlEditor.GetDesignViewIFrameWindow();
 return ASPxClientSelection.Create(contentWindow);
}
ASPxClientHtmlEditorSelection.SelectElement = function(element, htmlEditor, selectAllContent) {
 if (!_aspxIsExists(selectAllContent))
  selectAllContent = true;
 var iframeWindow = htmlEditor.GetDesignViewIFrameWindow();
 return __aspxIE ? ASPxClientSelectionIE.SelectElementInDocument(element, iframeWindow.document, selectAllContent) :
      ASPxClientSelectionNSOpera.SelectElementInDocument(element, iframeWindow.document, iframeWindow, selectAllContent);
}
ASPxClientSelection = _aspxCreateClass(null, {
 constructor: function(contentWindow) {
  this.contentWindow = contentWindow;
  this.contentDocument = contentWindow.document;
  this.startContainer = null;
  this.endContainer = null;
  this.startOffset = 0;
  this.endOffset = 0;
 },
 GetHtmlText: function() {
 },
 Save: function() {
 },
 Restore: function() {
 },
 GetText: function() {
 },
 GetHtmlText: function() {
 },
 GetStartContainer: function() {
  this.FindStartEndContainerInternal();
  return this.startContainer;
 },
 GetEndContainer: function() {
  this.FindStartEndContainerInternal();
  return this.endContainer;
 },
 GetStartOffset: function() {
  this.FindStartEndContainerInternal();
  return this.startOffset;
 },
 GetEndOffset: function() {
  this.FindStartEndContainerInternal();
  return this.endOffset;
 },
 IsControl: function() {
  return false;
 },
 IsTextOnly: function() {
  return false;
 },
 GetRange: function() {
 },
 GetExtendedBookmark: function() {
  return null;
 },
 GetSelectionMarkerElement: function(isStart) {
  return null;
 },
 SelectExtendedBookmark: function(bookmark) {
 },
 RemoveExtendedBookmark: function(bookmark) {
  if (bookmark) {
   _aspxRemoveElement(_aspxGetElementByIdInDocument(this.contentDocument, bookmark.startMarkerID));
   _aspxRemoveElement(_aspxGetElementByIdInDocument(this.contentDocument, bookmark.endMarkerID));
  }
  return null;
 },
 FindStartEndContainer: function() {
 },
 FindStartEndContainerInternal: function() {
  if (this.startContainer || this.endContainer)
   return;
  this.FindStartEndContainer();
 }
});
ASPxClientSelection.IsHtml = function(text) {
 if (!text || !text.match) return text;
 return text.match(/</);
}
ASPxClientSelection.Create = function(contentWindow) {
 return __aspxIE ? new ASPxClientSelectionIE(contentWindow) : new ASPxClientSelectionNSOpera(contentWindow);
}
ASPxClientSelection.GetMarkerID = function() {
 return 'dx_temp_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000);
}
ASPxClientSelection.IsControlElement = function(element) {
 if (element.nodeType == 1) {
  var tagName = element.tagName.toUpperCase();
  return tagName == "TABLE" || tagName == "IMG";
 }
 return false;
};
ASPxClientSelection.InsertNodeAtPosition = function(containerNode, insertNode, containeNodeOffset, doc) {
 var newTextNode = null;
 if ((containerNode.nodeType == 3) && (insertNode.nodeType == 3))
  containerNode.insertData(containeNodeOffset, insertNode.nodeValue);
 else {
  var afterNode;
  if (containerNode.nodeType == 3) {
   var textNode = containerNode;
   containerNode = textNode.parentNode;
   var nodeText = textNode.nodeValue;
   var textBefore = nodeText.substr(0, containeNodeOffset);
   var textAfter = nodeText.substr(containeNodeOffset);
   var beforeNode = doc.createTextNode(textBefore);
   var afterNode = doc.createTextNode(textAfter);
   containerNode.insertBefore(afterNode, textNode);
   containerNode.insertBefore(insertNode, afterNode);
   newTextNode = beforeNode;
   try {
    containerNode.insertBefore(beforeNode, insertNode);
   }
   catch (exc) {}
   containerNode.removeChild(textNode);
  }
  else {
   if(containerNode.childNodes.length > 0) {
    afterNode = containerNode.childNodes[containeNodeOffset];
    containerNode.insertBefore(insertNode, afterNode);
   }
   else {
    if (containerNode.tagName != "BODY")
     containerNode = containerNode.parentNode;
    containerNode.appendChild(insertNode);
   }
  }
  return newTextNode;
 }
}
ASPxClientSelectionIE = _aspxCreateClass(ASPxClientSelection, {
 constructor: function(contentWindow) {
  this.constructor.prototype.constructor.call(this, contentWindow);
 },
 Save: function() {
  this.contentWindow.focus();
  var curSelection = this.contentDocument.selection;
  var selRange = curSelection.createRange();
  if (selRange.length)
   this.sourceIndex = selRange.item(0).sourceIndex;
  else
   this.startBookmark = this.GetBookmark(selRange);
 },
 Restore: function() {
  if (_aspxIsExists(this.sourceIndex)) {
   var selRange = this.contentDocument.body.createControlRange();
   selRange.addElement(this.contentDocument.all(this.sourceIndex));
   selRange.select();
  }
  else if (_aspxIsExists(this.startBookmark)) {
   var selRange = this.contentDocument.body.createTextRange();
   selRange.moveToBookmark(this.startBookmark);
   selRange.select();
   selRange.collapse();
  }
  this.contentWindow.focus();
 },
 GetBookmark: function(range) {
  return range.getBookmark(); 
 },
 GetSelectionMarkerElement: function(isStart) {
  var rng = this.GetRange();
  var markerID = ASPxClientSelection.GetMarkerID();
  var makerElem = null;
  if (this.IsControl()) {
   makerElem = this.contentDocument.createElement("span");
   makerElem.id = markerID;
   var controlElem = rng.item(0);
   if (isStart)
    controlElem.parentNode.insertBefore(makerElem, controlElem);
   else
    controlElem.parentNode.insertBefore(makerElem, controlElem.nextSibling);
  }
  else {
   if (_aspxIsExists(rng.parentElement) && rng.parentElement().document != this.contentDocument)
    return null;
   if (_aspxIsExists(rng.collapse))
    rng.collapse(isStart);
   try {
    rng.pasteHTML('<span id="' + markerID + '"></span>');
    makerElem = _aspxGetElementByIdInDocument(this.contentDocument, markerID);
   } catch (e) { };
  }
  return makerElem;
 },
 GetExtendedBookmark: function() {
  var controlElementID = null;
  var bookmark = null;
  if (this.IsControl()) {
   var selRange = this.contentDocument.selection.createRange();
   controlElementID = ASPxClientSelection.GetMarkerID();
   _aspxChangeAttribute(selRange.item(0), "id", controlElementID);
   bookmark = { "controlElementID": controlElementID };
  }
  else {
  var startMarker = this.GetSelectionMarkerElement(true);
  var endMarker = this.GetSelectionMarkerElement(false);
  if (startMarker != null && endMarker != null)
    bookmark = { "startMarkerID": startMarker.id, "endMarkerID": endMarker.id };
  }
  return bookmark;
 },
 SelectExtendedBookmark: function(bookmark) {
  var rng1 = null;
  if (bookmark.controlElementID) {
   rng1 = this.contentDocument.body.createControlRange();
   var controlElement = _aspxGetElementByIdInDocument(this.contentDocument, bookmark.controlElementID);
   _aspxRestoreAttribute(controlElement, "id");
   rng1.addElement(controlElement);
  }
  else {
  var startMarker = _aspxGetElementByIdInDocument(this.contentDocument, bookmark.startMarkerID);
  var endMarker = _aspxGetElementByIdInDocument(this.contentDocument, bookmark.endMarkerID);
   rng1 = this.contentDocument.body.createTextRange();
  if (_aspxIsExists(startMarker))
   rng1.moveToElementText(startMarker);
  rng1.moveStart('character', 0);
  var rng2 = this.contentDocument.body.createTextRange();
  if (_aspxIsExists(endMarker))
   rng2.moveToElementText(endMarker);
  rng1.setEndPoint('EndToEnd', rng2);
  rng1.moveEnd('character', 0);
  _aspxRemoveElement(startMarker);
  _aspxRemoveElement(endMarker);
  }
  rng1.select();
 },
 SelectElement: function(elem, selectAllContent) {
  ASPxClientSelectionIE.SelectElementInDocument(elem, this.contentDocument, selectAllContent);
 },
 GetRange: function() {
  return this.contentDocument.selection.createRange();
 },
 GetParentElement: function() {
  var ret = null;
  var rng = this.GetRange();
  if (!rng) return ret;
  if (rng.length)
   ret = rng.item(0);
  else if (rng.parentElement)
   ret = rng.parentElement();
  return ret;
 },
 GetText: function() {
  var ret = "";
  var rng = this.contentDocument.selection.createRange();
  if (_aspxIsExists(rng.text))
   ret = rng.text;
  return ret;
 },
 GetHtmlText: function() {
  var ret = "";
  var rng = this.GetRange();
  if (rng.length)
   ret = rng.item(0).outerHTML;
  else if (rng.htmlText)
   ret = rng.htmlText;
  return ret;
 },
 IsControl: function() {
  return this.contentDocument.selection.type == 'Control';
 },
 IsTextOnly: function() {
  var rng = this.contentDocument.selection.createRange();
  if (_aspxIsExists(rng.text) && _aspxIsExists(rng.htmlText))
   return (rng.text == rng.htmlText);
  return false;
 },
 FindStartEndContainer: function() {
  var startMarker = this.GetSelectionMarkerElement(true);
  var endMarker = this.GetSelectionMarkerElement(false);
  if (!startMarker && !endMarker) {
   this.startContainer = this.contentDocument.body;
   return;
  }
  this.startContainer = startMarker.parentNode;
  this.startOffset = _aspxArrayIndexOf(this.startContainer.childNodes, startMarker);
  _aspxRemoveElement(startMarker);
  this.endContainer = endMarker.parentNode;
  this.endOffset = _aspxArrayIndexOf(this.endContainer.childNodes, endMarker);
  _aspxRemoveElement(endMarker);
  if (this.startContainer != this.endContainer) {
   if (this.endOffset == 0) {
    while (this.endContainer && !this.endContainer.previousSibling)
     this.endContainer = this.endContainer.parentNode;
    if (this.endContainer)
     this.endContainer = this.endContainer.previousSibling;
   }
   else if (this.endContainer.nodeType == 1)
    this.endContainer = this.endContainer.childNodes[this.endOffset - 1];
  }
 }
});
ASPxClientSelectionIE.SelectElementInDocument = function(elem, docObj, selectAllContent) {
 if (!_aspxIsExists(selectAllContent))
  selectAllContent = true;
 var rng;
 if (ASPxClientSelection.IsControlElement(elem)) {
  rng = docObj.body.createControlRange();
  rng.addElement(elem);
 }
 else {
  rng = docObj.selection.createRange();
  try { 
  rng.moveToElementText(elem);
 }
  catch (e) { }
 }
 if (!selectAllContent) {
  try { 
  rng.collapse(false);
  }
  catch (e) { }
 }
 rng.select();
};
DialogSelectionIE = _aspxCreateClass(ASPxClientSelectionIE, {
 Save: function() {
  this.contentWindow.focus();  
  var curSelection = this.contentDocument.selection;
  if (curSelection) {
   this.selectionRange = curSelection.createRange();
   if (curSelection.type.toLowerCase() == "control")
    this.sourceIndex = this.selectionRange.item(0).sourceIndex;
  }
 },
 Restore: function() {
  if (_aspxIsExists(this.sourceIndex)) {
   var selRange = this.contentDocument.body.createControlRange();
   selRange.addElement(this.contentDocument.all(this.sourceIndex));
   selRange.select();
  }
  else if (_aspxIsExists(this.selectionRange))
   this.selectionRange.select();
  this.contentWindow.focus();
 }
});
ASPxClientSelectionNSOpera = _aspxCreateClass(ASPxClientSelection, {
 constructor: function(contentWindow) {
  this.constructor.prototype.constructor.call(this, contentWindow);
 },
 Save: function() {
   var curSelection = this.contentWindow.getSelection();
   if (_aspxIsExists(curSelection)) {
    this.isCollapsedSelection = curSelection.isCollapsed;   
    this.startNodePath = this.GetNodePath(this.contentDocument.documentElement, curSelection.anchorNode);   
   this.startNodeOffset = curSelection.anchorOffset;
    this.endNodePath = this.GetNodePath(this.contentDocument.documentElement, curSelection.focusNode);
   this.endNodeOffset = curSelection.focusOffset;
   if (__aspxOpera) {
    if (this.NeedExchangeStartAndEndNode(this.startNodePath, this.endNodePath, this.startNodeOffset, this.endNodeOffset)) {
     var tmp = this.startNodePath;
     this.startNodePath = this.endNodePath;
     this.endNodePath = tmp;
     tmp = this.startNodeOffset;
     this.startNodeOffset = this.endNodeOffset;
     this.endNodeOffset = tmp;
    }
   }
  }
  else {
    this.isCollapsedSelection = null;
    this.startNodePath = null;
   this.startNodeOffset = null;
    this.endNodePath = null;
   this.endNodeOffset = null;
  }
 },
 Restore: function() {
  var curSelection = this.contentWindow.getSelection();
  var startNode = this.GetNodeByPath(this.contentDocument.documentElement, this.startNodePath);
  var endNode = this.GetNodeByPath(this.contentDocument.documentElement, this.endNodePath);
  ASPxClientSelectionNSOpera.RestoreByStartAndEndNodeCore(startNode, endNode, this.startNodeOffset, 
                this.endNodeOffset, 
                this.isCollapsedSelection, 
                this.contentDocument, 
                this.contentWindow);
 },
 GetParentElement: function() {
  var ret = null;
  var rng = this.GetRange();
  if (!rng) return ret;
  var selection = this.contentWindow.getSelection();
  var startContainer = this.GetStartContainer(rng, selection);
  var endContainer = this.GetEndContainer(rng, selection);
  var startOffset = this.GetStartOffset(rng, selection);
  var endOffset = this.GetEndOffset(rng, selection);
  if (startContainer == endContainer && (endOffset - startOffset) == 1 && 
    (selection.anchorNode.childNodes.length > 0))
   ret = selection.anchorNode.childNodes[selection.anchorOffset];
  else {    
   if (!rng.commonAncestorContainer.tagName) {       
    if (this.contentWindow.document == rng.commonAncestorContainer && 
     selection.baseNode) 
     ret = selection.baseNode.parentNode;
    else
     ret = rng.commonAncestorContainer.parentNode;
   }
   else
    ret = rng.commonAncestorContainer;
  }
  return ret;
 }, 
 GetRange: function() {
  var selection = this.contentWindow.getSelection(); 
  if (!selection || selection.rangeCount < 1)
   return null;
  return selection.getRangeAt ? selection.getRangeAt(0) : this.contentWindow.createRange();
 },
 GetText : function() {
  var ret = "";
  if (this.contentWindow.getSelection)
   ret = this.contentWindow.getSelection().toString();
  return ret;
 },
 GetHtmlText: function() {
  var ret = "";
  var selection = this.contentWindow.getSelection();   
  var rng = null;
  if (selection.getRangeAt && selection.rangeCount > 0) {
   rng = selection.getRangeAt(0);
   var tempDiv = this.contentWindow.document.createElement("div");
   var clonedFragment = rng.cloneContents();   
   if (_aspxIsExists(clonedFragment)) {
    tempDiv.appendChild(clonedFragment);
    ret = tempDiv.innerHTML;
   }
  }
  return ret;
 },
 GetExtendedBookmark : function() {
  var startSpan = this.contentDocument.createElement("span");
  startSpan.id = ASPxClientSelection.GetMarkerID();
  var endSpan = this.contentDocument.createElement("span");
  endSpan.id = ASPxClientSelection.GetMarkerID();  
  var isEmptyTextSelected = false;
  if (this.startContainer == this.endContainer) {
   isEmptyTextSelected = this.endOffset == this.startOffset;
   var newContainer = ASPxClientSelection.InsertNodeAtPosition(this.endContainer, endSpan, this.endOffset, this.contentDocument);
   if (_aspxIsExists(newContainer))
    this.startContainer = newContainer;
   ASPxClientSelection.InsertNodeAtPosition(this.startContainer, startSpan, this.startOffset, this.contentDocument);
  }
  else {
   ASPxClientSelection.InsertNodeAtPosition(this.startContainer, startSpan, this.startOffset, this.contentDocument);
   ASPxClientSelection.InsertNodeAtPosition(this.endContainer, endSpan, this.endOffset, this.contentDocument);
  }
  var bookmark = { "startMarkerID": startSpan.id, "endMarkerID": endSpan.id, "isEmptyTextSelected": isEmptyTextSelected };
  this.SelectExtendedBookmark(bookmark, false);
  return bookmark;
 },
 SelectExtendedBookmark: function(bookmark, withDeleteMarker) {
  if (!_aspxIsExists(withDeleteMarker)) 
   withDeleteMarker = true;
  var startMarker = _aspxGetElementByIdInDocument(this.contentDocument, bookmark.startMarkerID);
  var endMarker = _aspxGetElementByIdInDocument(this.contentDocument, bookmark.endMarkerID);
  var rng1 = this.contentDocument.createRange();
  rng1.setStart(startMarker.nextSibling, 0);
  if (startMarker.nextSibling != endMarker) {
   var nextSibling = endMarker.nextSibling ? endMarker.nextSibling : endMarker;
   rng1.setEnd(nextSibling, 0);
  }
  var sel = this.contentWindow.getSelection();
  sel.removeAllRanges();
  sel.addRange(rng1);
  if (bookmark.isEmptyTextSelected) {
   var index = _aspxArrayIndexOf(endMarker.parentNode.childNodes, startMarker);
   sel.collapse(endMarker.parentNode, index);
  }
  if (withDeleteMarker) {
   _aspxRemoveElement(startMarker);
   _aspxRemoveElement(endMarker);
  }
 },
 FindStartEndContainer: function() {  
    var rng = this.GetRange();
    if(!rng)
     rng = { };
  var selection = this.contentWindow.getSelection();
  if(!selection)
   selection = { };
  this.startContainer = rng.startContainer ? rng.startContainer : selection.baseNode;
  this.endContainer = rng.endContainer ? rng.endContainer : selection.extentNode;
  this.startOffset = rng.startOffset != null ? rng.startOffset : selection.baseOffset;
  this.endOffset = rng.endOffset != null ? rng.endOffset : selection.extentOffset;
 },
 IsControl : function ()  {    
  var selection = this.contentWindow.getSelection();
  if(selection.toString() != "" || !_aspxIsExists(selection.focusNode)) 
   return false;
  var focusNode = selection.focusNode;
  if(focusNode.nodeType == 1) { 
   var rng = this.GetRange();
   var startContainer = this.GetStartContainer();
   var endContainer = this.GetEndContainer();
   var startOffset = this.GetStartOffset();
   var endOffset = this.GetEndOffset();
   if (startContainer == endContainer && (endOffset - startOffset) == 1 && 
     (selection.anchorNode.childNodes.length > 0))
    focusNode = selection.anchorNode.childNodes[selection.anchorOffset];
  }
  return (focusNode.tagName == 'IMG');
 },
 IsTextOnly: function() {
  var selection = this.contentWindow.getSelection();  
  return _aspxIsExists(selection.focusNode) && _aspxIsExists(selection.anchorNode) && 
    ((selection.focusNode == selection.anchorNode) || 
    ((selection.focusNode.nodeType == 3) && (selection.anchorNode.nodeType == 3))); 
 }, 
 SelectElement: function(elem, selectAllContent) {  
  if (!_aspxIsExists(selectAllContent))
   selectAllContent = true; 
  ASPxClientSelectionNSOpera.SelectElementInDocument(elem, this.contentDocument, this.contentWindow, selectAllContent);
 }, 
 NeedExchangeStartAndEndNode: function(startNodePath, endNodePath, startNodeOffset, endNodeOffset) {
  if (startNodePath != endNodePath) {
   var startNodePathArray = startNodePath.split("-");
   var endNodePathArray = endNodePath.split("-");
   var length = Math.min(startNodePathArray.length, endNodePathArray.length);
   for (var i = 0; i < length; i++) {
    var i1 = parseInt(startNodePathArray[i], 10);
    var i2 = parseInt(endNodePathArray[i], 10);
    if (i1 > i2)
     return true;
   }
  }
  return startNodeOffset > endNodeOffset;
 },
 GetNodePath: function(rootNode, node) {
  var path = "";
  var curParentNode = node;
  var curNode = node;
  if (_aspxIsExists(curParentNode)){
   while (rootNode != curParentNode) {
    curParentNode = curParentNode.parentNode;
    if (_aspxIsExists(curParentNode.childNodes)) {
     var index = _aspxArrayIndexOf(curParentNode.childNodes, curNode);
     path = index.toString() + "-" + path;
    }
    curNode = curParentNode;
   }
  }
  return path.substr(0, path.length - 1);
 },
 GetNodeByPath: function(rootNode, path) {
  if (path != "") {
   var pathNodeArray = path.split("-");
   var curNode = rootNode;
   for(var i = 0; i < pathNodeArray.length; i++) {
    var index = parseInt(pathNodeArray[i], 10);
    curNode = curNode.childNodes[index];
   }
   return curNode;
  }
  else
   return null;
 } 
});
ASPxClientSelectionNSOpera.RestoreByStartAndEndNodeCore = function(startNode, 
                 endNode, 
                 startNodeOffset, 
                 endNodeOffset, isCollapsed,
                 docObj, windowObj) {
 var curSelection = windowObj.getSelection();
 ASPxClientSelectionNSOpera.SelectElementInDocument(startNode, docObj, windowObj);
 ASPxClientSelectionNSOpera.SelectElementInDocument(endNode, docObj, windowObj);
 if (_aspxIsExists(startNode))
  curSelection.collapse(startNode, startNodeOffset);
 if (_aspxIsExists(endNode) && !isCollapsed) {
  if (__aspxWebKitFamily)
   curSelection.setBaseAndExtent(startNode, startNodeOffset, endNode, endNodeOffset);
  else
   curSelection.extend(endNode, endNodeOffset);
 }
}
ASPxClientSelectionNSOpera.SelectElementInDocument = function(elem, docObj, windowObj, selectAllContent) {
 if (_aspxIsExists(elem)) {
  if (!_aspxIsExists(selectAllContent))
   selectAllContent = true;
  var range = docObj.createRange();
  range.selectNode(elem);
  if (__aspxOpera)
   range.selectNodeContents(elem);
  if (!selectAllContent)
   range.collapse(false);
  var selection = windowObj.getSelection();   
  if (__aspxWebKitFamily)
   selection.setBaseAndExtent(range.startContainer,range.startOffset,range.endContainer,range.endOffset);
  else {
   selection.removeAllRanges();   
   selection.addRange(range);
  }
 } 
}
ASPxCachedElementsManager = _aspxCreateClass(null, {
 constructor: function(htmlEditor) {
  this.htmlEditor = htmlEditor;
  this.selectedElements = { table: null, tableRow: null, tableCell: null };
  this.needGetElementFromSelection = { table: true, tableRow: true, tableCell: true };
 },
 ClearSeletedElements: function() {
  for (var key in this.selectedElements) {
   this.selectedElements[key] = null;
   this.needGetElementFromSelection[key] = true;
  }
 },
 GetSeletedElement: function(name) {
  return this.selectedElements[name];
 },
 SetSelectedElement: function(name, element) {
  this.selectedElements[name] = element;
  this.needGetElementFromSelection[name] = false;
 },
 NeedGetElementFromSelection: function(name) {
  return this.needGetElementFromSelection[name] && !_aspxIsExists(this.selectedElements[name]);
 }
});

