public static IEnumerable <RangeNode> InRange(IEnumerable <INode> bodyNodes, MarkUpRange range) { int offset = 0; int iPosRangeStart = range.PositionStart - 1; int iPosRangeEnd = range.PositionEnd - 1; List <RangeNode> rangeNodes = new List <RangeNode>(); if (bodyNodes.Count() == 1 && bodyNodes.First().NodeName == HTMLConstants.SpanDiv) { rangeNodes.Add(new RangeNode(bodyNodes.First(), 0)); } else { foreach (var node in bodyNodes) { if (offset > iPosRangeEnd + 1) { break; } if (node.NodeType == NodeType.Text) { string nodeText = node.TextContent; int iNodeLength = nodeText.Length; int iRange = iPosRangeEnd - iPosRangeStart; bool rangeStartInNode = iPosRangeStart < offset || (iPosRangeStart + 1) < offset + iNodeLength; bool rangeEndInNode = iPosRangeEnd >= offset || iPosRangeEnd == iPosRangeStart; if (rangeStartInNode && rangeEndInNode) { rangeNodes.Add(new RangeNode(node, offset)); } offset += iNodeLength; } } } return(rangeNodes); }
private bool RangeOutreachesTexNodeLength(MarkUpRange range, int length) { return(range.PositionEnd > Offset + length); }
/// <summary> /// Applies/Unapplies style to the elements in the given range. /// </summary> /// <param name="range">Range</param> /// <param name="cmd">A style command</param> /// <param name="document"></param> /// <param name="attributeValue">The attribute value, that fits the style command</param> public void ApplyStyleCommand(MarkUpRange range, EStyleCommand cmd, IDocument document, Func <string> attributeValue) { IElement elem; void createStyleElement() { elem = CreateElem(cmd, StyleAttribute, document, attributeValue); } var isCmdForBlockElement = CommandIsBlockNodeCommand(cmd); if (cmd == EStyleCommand.FormatClear) { var elementWithStyle = FindParentElementWithAStyleAttribute(Node) as IElement; if (elementWithStyle != null) { elementWithStyle.RemoveAttribute(HTMLConstants.Style); if (elementWithStyle.NodeName == HTMLConstants.SpanTag) { RemoveFromParentKeepContent(Node, HTMLConstants.SpanTag, document); } } return; } if (isCmdForBlockElement) { var blockElement = FindBlockParent(Node) as IElement; if (blockElement != null) { var blockstyleAttr = blockElement.GetAttribute(HTMLConstants.Style); StyleAttribute = ReDefineStyle(blockstyleAttr, HTMLConstants.TextAlign, attributeValue()); blockElement.SetAttribute(HTMLConstants.Style, StyleAttribute); } return; } var rangeLength = (range.PositionEnd - range.PositionStart); var posEndWord = range.PositionEnd - Offset; var posStartWord = range.PositionStart > Offset ? range.PositionStart - Offset : 0; string nodeText = Node.TextContent; int nodeTextLength = Node.TextContent.Length; if (nodeText.Trim().Length == 0) { return; } _styleattribute = GetParentElement(Node).GetAttribute(HTMLConstants.Style); if (RangeOutreachesTexNodeLength(range, nodeTextLength)) { ApplyElementStyle(cmd, this.Node, attributeValue, document); return; } if (ContainsZeroCharachtersOrOnlyWhiteSpaces(posStartWord, posEndWord, nodeText)) { return; } var poslength = posEndWord - posStartWord; if (poslength == 0) { poslength = 1; } string extractedTextRange = nodeText.Substring(posStartWord, poslength); //rangeLength == 0 -> no selection only cursor. Then apply style to the word under the cursor if (rangeLength == 0) { var startIndex = Math.Max(nodeText.LastIndexOf(" ", posStartWord), nodeText.LastIndexOf((char)160, posStartWord)); startIndex = startIndex == -1 ? 0 : startIndex; var endIndex = Math.Max(nodeText.IndexOf(" ", posStartWord), nodeText.IndexOf((char)160, posStartWord)); endIndex = endIndex == -1 ? nodeTextLength : endIndex; extractedTextRange = ExtractWord(startIndex, endIndex, nodeText); if (extractedTextRange == "") { return; } posStartWord = startIndex == 0 ? startIndex : startIndex + 1; } posEndWord = extractedTextRange.Length; if (ExtractedRangeEqualsTextRange(extractedTextRange, nodeText) || isCmdForBlockElement) { ApplyElementStyle(cmd, Node, attributeValue, document); return; } if (ExtractedRangeIsAtStartOfTextRange(posStartWord)) { createStyleElement(); elem.TextContent = nodeText.Substring(0, posEndWord); ((ICharacterData)Node).Data = nodeText.Substring(posEndWord); Node.InsertBefore(new[] { elem }); return; } if (ExtractedRangeIsAtEndOfTextRange(posStartWord, posEndWord, extractedTextRange)) { createStyleElement(); elem.TextContent = nodeText.Substring(posStartWord); Node.TextContent = nodeText.Substring(0, posStartWord); Node.InsertAfter(new[] { elem }); return; } //range is in the middle of the textnode var newElementname = GetElementName(cmd); if (newElementname != HTMLConstants.SpanTag) { var alreadyPresent = ParentElementAlreadyExists(Node, newElementname.ToUpper()); if (alreadyPresent != null && alreadyPresent.IndexOf(Node) != 0) { //redefine all ApplyElementStyle(cmd, Node, attributeValue, document); return; } } createStyleElement(); elem.TextContent = nodeText.Substring(posStartWord, posEndWord); Node.TextContent = nodeText.Substring(0, posStartWord); var restNode = Node.Clone(); restNode.TextContent = nodeText.Substring(posStartWord + posEndWord); Node.ReplaceWith(new[] { Node.Clone(), elem, restNode }); }