/// <summary> /// Determines if element contains given position /// </summary> /// <param name="position">Position in a text buffer</param> public override bool Contains(int position) { if (base.Contains(position)) { return(true); } if (StartTag.Contains(position)) { return(true); } if (EndTag != null) { if (EndTag.Contains(position)) { return(true); } } else { if (position == VirtualEnd && !IsShorthand() && !IsSelfClosing()) { return(true); } } return(false); }
/// <summary> /// Shifts node components that are located at or beyond given start point by the specified range /// </summary> /// <param name="start">Start point</param> /// <param name="offset">Offset to shift by</param> public override void ShiftStartingFrom(int start, int offset) { // short-circuit in the case where the shift starts after our end if (start > End) { return; } // if tag is not closed and change is right at the end, // e need to grow start tag rather than element inner range if (StartTag.Contains(start) || StartTag.Start >= start || (!StartTag.IsClosed && start == StartTag.End)) { StartTag.ShiftStartingFrom(start, offset); } if (EndTag != null && (EndTag.Contains(start) || EndTag.Start >= start)) { EndTag.ShiftStartingFrom(start, offset); } if (OrphanedEndTagsCollection != null) { OrphanedEndTagsCollection.ShiftStartingFrom(start, offset); } if (VirtualEnd >= start) { VirtualEnd = Math.Max(start, VirtualEnd + offset); } int count = Children.Count; for (int i = 0; i < count; i++) { Children[i].ShiftStartingFrom(start, offset); } }
/// <summary> /// Determines position type and enclosing element node for a given position in the document text. /// </summary> /// <param name="position">Position in the document text</param> /// <param name="element">Element that contains position</param> /// <param name="attribute">Attribute that contains position (may be null)</param> /// <returns>Position type as a set of flags combined via OR operation</returns> public virtual HtmlPositionType GetPositionElement(int position, out ElementNode element, out AttributeNode attribute) { element = null; attribute = null; // If start tag is not closed, consider end position to be inside it // so user can continue getting attribute intellisense, like in <a href=|<a ...></a> if (StartTag.Contains(position) || (position == StartTag.End && !StartTag.IsClosed)) { // If position is right at the start, it is actually before the tag (in parent's content), // as if when caret position is like this: <table>|<tr></tr><table> if (position == StartTag.Start) { element = this.Parent; return(HtmlPositionType.InContent); } if (position >= QualifiedNameRange.Start && position <= StartTag.QualifiedNameRange.End) { element = this; return(HtmlPositionType.ElementName); } element = this; for (int i = 0; i < Attributes.Count; i++) { var attrNode = Attributes[i]; bool hasClosingQuote = false; var valueToken = attrNode.ValueToken; hasClosingQuote = (valueToken != null) && (valueToken.CloseQuote != '\0'); if (position == attrNode.End && hasClosingQuote) { break; } if (position > attrNode.End) { continue; } if (position < attrNode.Start) { break; } if (attrNode.Contains(position) || (position == attrNode.End && !hasClosingQuote)) { attribute = attrNode; return(attrNode.GetPositionType(position)); } } return(HtmlPositionType.InStartTag); } if (!this.Contains(position)) { return(HtmlPositionType.Undefined); } for (int i = 0; i < this.Children.Count; i++) { var child = Children[i]; if (position < child.Start) { break; } if (child.Contains(position)) { return(child.GetPositionElement(position, out element, out attribute)); } } element = this; // If position is right at the start, it is actually before the end tag, // like when caret is between opening and closing tags: <table>|<table> if (EndTag != null) { if (position == EndTag.Start) { return(HtmlPositionType.InContent); } if (EndTag.Contains(position)) { return(HtmlPositionType.InEndTag); } } if (this.IsScriptBlock()) { return(HtmlPositionType.InScriptBlock); } if (this.IsStyleBlock()) { return(HtmlPositionType.InStyleBlock); } return(HtmlPositionType.InContent); }