/// <summary> /// Returns true if the the range contains an element that matches the filter /// </summary> /// <param name="filter"></param> /// <returns></returns> public bool ContainsElements(IHTMLElementFilter filter) { if (!IsEmpty()) { Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupContext context = p.Right(false); //move p through the range to locate each the elements adding elements that pass the filter while (p.IsLeftOfOrEqualTo(End)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { if (usedElements[context.Element] == null) { if (filter(context.Element)) { return(true); } } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } p.Right(true, context); } } return(false); }
/// <summary> /// Makes sure that whole (not parts of) lists are included in the source of a paste. /// </summary> /// <param name="range">The original source range. The range may be modified.</param> /// <param name="markupServices">MarkupServices for the range.</param> private void ExpandToIncludeLists(MarkupRange range, MshtmlMarkupServices markupServices) { MarkupPointer pointer = markupServices.CreateMarkupPointer(); IHTMLElementFilter listFilter = ElementFilters.CreateCompoundElementFilter(ElementFilters.LIST_ELEMENTS, ElementFilters.LIST_ITEM_ELEMENTS); IHTMLElement[] listElements = range.GetElements(listFilter, false); foreach (IHTMLElement element in listElements) { IHTMLElement parentList = element; while (parentList != null && !ElementFilters.IsListElement(parentList)) { parentList = parentList.parentElement; } if (parentList != null) { pointer.MoveAdjacentToElement(parentList, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); if (range.Start.IsRightOf(pointer)) { range.Start.MoveToPointer(pointer); } pointer.MoveAdjacentToElement(parentList, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); if (range.End.IsLeftOf(pointer)) { range.End.MoveToPointer(pointer); } } } }
/// <summary> /// Returns an array of the parent elements that match the specified filter. /// </summary> /// <param name="filter"></param> /// <returns>an array of matching parents (closest parent at index zero)</returns> public IHTMLElement[] GetParentElements(IHTMLElementFilter filter) { ArrayList list = null; IHTMLElement parent = CurrentScope; while (parent != null) { if (filter(parent)) { if (list == null) { list = new ArrayList(); } list.Add(parent); } parent = parent.parentElement; } if (list != null) { return(HTMLElementHelper.ToElementArray(list)); } else { return(new IHTMLElement[0]); } }
public IHTMLElement ParentElement(IHTMLElementFilter filter) { IHTMLElement parent = ParentElement(); while (parent != null && !filter(parent)) { parent = parent.parentElement; } return(parent); }
/// <summary> /// Returns the closest parent element that matches the specified filter. /// </summary> /// <param name="filter"></param> /// <returns></returns> public IHTMLElement GetParentElement(IHTMLElementFilter filter) { IHTMLElement parent = CurrentScope; while (parent != null && !filter(parent)) { parent = parent.parentElement; } return(parent); }
private void MovePointerRightUntilRegionBreak(MarkupPointer p, IHTMLElementFilter regionBreakFilter, MarkupPointer rightBoundary) { MarkupContext moveContext = new MarkupContext(); while (p.IsLeftOf(rightBoundary)) { p.Right(true, moveContext); if (moveContext.Element != null && regionBreakFilter(moveContext.Element)) { p.Left(true); return; } } }
private void ApplyBlockStyle(_ELEMENT_TAG_ID styleTagId, MarkupRange selection, MarkupRange maximumBounds, MarkupRange postOpSelection) { Debug.Assert(selection != maximumBounds, "selection and maximumBounds must be distinct objects"); SelectionPositionPreservationCookie selectionPreservationCookie = null; //update the range cling and gravity so it will stick with the re-arranged block content selection.Start.PushCling(false); selection.Start.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Left); selection.End.PushCling(false); selection.End.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Right); try { if (selection.IsEmpty()) { //nothing is selected, so expand the selection to cover the entire parent block element IHTMLElementFilter stopFilter = ElementFilters.CreateCompoundElementFilter(ElementFilters.BLOCK_ELEMENTS, new IHTMLElementFilter(IsSplitStopElement)); MovePointerLeftUntilRegionBreak(selection.Start, stopFilter, maximumBounds.Start); MovePointerRightUntilRegionBreak(selection.End, stopFilter, maximumBounds.End); } using (IUndoUnit undo = _editor.CreateSelectionUndoUnit(selection)) { selectionPreservationCookie = SelectionPositionPreservationHelper.Save(_markupServices, postOpSelection, selection); if (selection.IsEmptyOfContent()) { ApplyBlockFormatToEmptySelection(selection, styleTagId, maximumBounds); } else { ApplyBlockFormatToContentSelection(selection, styleTagId, maximumBounds); } undo.Commit(); } } finally { selection.Start.PopCling(); selection.Start.PopGravity(); selection.End.PopCling(); selection.End.PopGravity(); } if (!SelectionPositionPreservationHelper.Restore(selectionPreservationCookie, selection, selection.Clone())) { selection.ToTextRange().select(); } }
private void ApplyBlockFormatToEmptySelection(MarkupRange selection, _ELEMENT_TAG_ID styleTagId, MarkupRange maximumBounds) { bool deleteParentBlock = false; //expand the selection to include the parent content block. If the expansion can cover the block element //without exceeding the maximum bounds, then delete the parent element and wrap the selection in the //new block element. If the maximum bounds are exceeded, then just wrap the selection around the bounds. IHTMLElementFilter stopFilter = ElementFilters.CreateCompoundElementFilter(ElementFilters.BLOCK_ELEMENTS, new IHTMLElementFilter(IsSplitStopElement)); MovePointerLeftUntilRegionBreak(selection.Start, stopFilter, maximumBounds.Start); MovePointerRightUntilRegionBreak(selection.End, stopFilter, maximumBounds.End); MarkupRange tmpRange = selection.Clone(); tmpRange.End.MoveToPointer(selection.Start); IHTMLElement startStopParent = tmpRange.End.GetParentElement(stopFilter); if (startStopParent != null) { tmpRange.Start.MoveAdjacentToElement(startStopParent, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); if (tmpRange.IsEmptyOfContent()) //the range from the selection the the block start is empty { tmpRange.Start.MoveToPointer(selection.End); IHTMLElement endStopParent = tmpRange.Start.GetParentElement(stopFilter); if (endStopParent != null && startStopParent.sourceIndex == endStopParent.sourceIndex) { tmpRange.Start.MoveAdjacentToElement(endStopParent, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd); if (tmpRange.IsEmptyOfContent()) //the range from the selection the the block end is empty { tmpRange.MoveToElement(endStopParent, true); if (maximumBounds.InRange(tmpRange) && !(endStopParent is IHTMLTableCell)) { deleteParentBlock = true; //the parent has no useful content outside the selection, so it's safe to delete } } } } } //delete the block parent (if appropriate) and wrap the selection in the new block element. if (deleteParentBlock) { (startStopParent as IHTMLDOMNode).removeNode(false); } IHTMLElement newBlock = WrapRangeInBlockElement(selection, styleTagId); selection.MoveToElement(newBlock, false); }
/*private void DumpBreakRegions(params ElementBreakRegion[] breakRegions) * { * foreach(ElementBreakRegion breakRegion in breakRegions) * { * String elementStartName = breakRegion.BreakStartElement != null ? breakRegion.BreakStartElement.tagName : ""; * String elementEndName = breakRegion.BreakEndElement != null ? breakRegion.BreakEndElement.tagName : ""; * String breakContent = breakRegion.ContentRange.Text; * if(breakContent != null) * breakContent = breakContent.Replace('\r', ' ').Replace('\n', ' '); * else * breakContent = ""; * Trace.WriteLine(String.Format("<{0}>{1}<{2}>", elementStartName, breakContent, elementEndName)); * } * }*/ /// <summary> /// Splits the specified range into regions based on a region break filter. /// </summary> /// <param name="range"></param> /// <returns></returns> private ElementBreakRegion[] SplitIntoElementRegions(MarkupRange range, IHTMLElementFilter regionBreakFilter) { ArrayList regions = new ArrayList(); MarkupRange blockRange = _markupServices.CreateMarkupRange(); blockRange.Start.MoveToPointer(range.Start); blockRange.End.MoveToPointer(range.Start); MarkupContext moveContext = new MarkupContext(); ElementBreakRegion currentRegion = new ElementBreakRegion(blockRange, null, null); while (currentRegion.ContentRange.End.IsLeftOf(range.End)) { if (moveContext.Element != null) { if (regionBreakFilter(moveContext.Element)) { //move the end of the region back before the break element to close this region currentRegion.ContentRange.End.Left(true); //save the closed region and start the next region currentRegion.BreakEndElement = moveContext.Element; regions.Add(currentRegion); currentRegion = new ElementBreakRegion(currentRegion.ContentRange.Clone(), moveContext.Element, null); currentRegion.ContentRange.Start.MoveToPointer(currentRegion.ContentRange.End); //move the region start over the break element currentRegion.ContentRange.Start.Right(true, moveContext); currentRegion.ContentRange.End.MoveToPointer(currentRegion.ContentRange.Start); } } currentRegion.ContentRange.End.Right(true, moveContext); } //save the last break region if (moveContext.Element != null && regionBreakFilter(moveContext.Element)) { //move the end of the region back before the break element to close this region currentRegion.ContentRange.End.Left(true); } if (currentRegion.ContentRange.End.IsRightOf(range.End)) { currentRegion.ContentRange.End.MoveToPointer(range.End); } regions.Add(currentRegion); return((ElementBreakRegion[])regions.ToArray(typeof(ElementBreakRegion))); }
public static void RemoveAttributes(MshtmlMarkupServices markupServices, MarkupRange selection, string[] attributesToRemove) { IHTMLElementFilter[] filters = new IHTMLElementFilter[attributesToRemove.Length]; for (int i = 0; i < attributesToRemove.Length; i++) { filters[i] = ElementFilters.CreateElementAttributeFilter(attributesToRemove[i]); } IHTMLElement[] elements = selection.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false); foreach (IHTMLElement element in elements) { foreach (string attribute in attributesToRemove) { element.removeAttribute(attribute, 0); } } }
//this is similar to the GetTopLevelElements except will also return table cells if correct filter // is set and recurse is equal to true public IHTMLElement[] GetTopLevelBlocksAndCells(IHTMLElementFilter filter, bool recurse) { ArrayList list = new ArrayList(); Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupContext context = p.Right(false); //move p through the range to locate each of the top level elements while (p.IsLeftOf(End)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { p.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); if (usedElements[context.Element] == null) { if (p.IsLeftOfOrEqualTo(End) && (filter == null || filter(context.Element))) { list.Add(context.Element); } //special case--inside of a table element, want to get out the cells inside else if (recurse && ElementFilters.TABLE_ELEMENTS(context.Element)) { MarkupRange newRange = MarkupServices.CreateMarkupRange(context.Element); newRange.Start.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin); if (newRange.Start.IsLeftOf(Start)) { newRange.Start.MoveToPointer(Start); } if (newRange.End.IsRightOf(End)) { newRange.End.MoveToPointer(End); } //recursively check inside table element for table cells list.AddRange(newRange.GetTopLevelBlocksAndCells(filter, true)); } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } } p.Right(true, context); } return(HTMLElementHelper.ToElementArray(list)); }
public IHTMLElement SeekElementRight(IHTMLElementFilter filter, MarkupPointer boundaryPointer) { // initialize markup context used to track seeking MarkupContext markupContext = new MarkupContext(); markupContext.Context = _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope; while ((boundaryPointer == null || IsLeftOf(boundaryPointer)) && // apply boundary if one exists (markupContext.Context != _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None)) // otherwise use end of document { Right(true, markupContext); IHTMLElement element = markupContext.Element; if (element != null && filter(element)) { return(element); } } // none found return(null); }
/// <summary> /// Gets the elements in the range that match the filter. /// </summary> /// <param name="filter">the delegate testing each element to determine if it should be added to the list of elements to return</param> /// <param name="inScopeElementsOnly">if true, the only</param> /// <returns></returns> public IHTMLElement[] GetElements(IHTMLElementFilter filter, bool inScopeElementsOnly) { ArrayList list = new ArrayList(); if (!IsEmpty()) { Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupPointer end = MarkupServices.CreateMarkupPointer(End); MarkupContext context = p.Right(false); //move p through the range to locate each the elements adding elements that pass the filter while (p.IsLeftOfOrEqualTo(end)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { if (usedElements[context.Element] == null) { if ((inScopeElementsOnly && isInScope(context.Element)) || !inScopeElementsOnly) { if (filter(context.Element)) { list.Add(context.Element); } } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } } p.Right(true, context); } } return(HTMLElementHelper.ToElementArray(list)); }
/// <summary> /// Returns true if the provided element is a lt;br> element. /// </summary> /// <param name="element">The element to examine.</param> /// <returns>true if the provided element is a lt;br> element and false otherwise.</returns> private bool IsBrElement(IHTMLElement element) { if (isBrElement == null) { isBrElement = ElementFilters.CreateElementNameFilter(this.sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_BR)); } return isBrElement(element); }
public static void ChangeElementTagIds(MshtmlMarkupServices markupServices, MarkupRange selection, _ELEMENT_TAG_ID[] tagBefore, _ELEMENT_TAG_ID tagAfter) { HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices); int parentStartDiff = 0; MarkupRange rangeToChange; bool selectionStartedEmpty = selection.IsEmpty(); if (selectionStartedEmpty) { // Operate on parent block element rangeToChange = markupServices.CreateMarkupRange(selection.ParentBlockElement()); parentStartDiff = selection.Start.MarkupPosition - rangeToChange.Start.MarkupPosition; } else { rangeToChange = selection; // If expanding the selection would not include any new text, then expand it. // <h1>|abc|</h1> --> |<h1>abc</h1>| rangeToChange.MoveOutwardIfNoText(); } IHTMLElementFilter[] filters = new IHTMLElementFilter[tagBefore.Length]; for (int i = 0; i < tagBefore.Length; i++) filters[i] = ElementFilters.CreateTagIdFilter(markupServices.GetNameForTagId(tagBefore[i])); IHTMLElement[] elements = rangeToChange.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false); foreach (IHTMLElement element in elements) { MarkupRange elementRange = markupServices.CreateMarkupRange(element); int startPositionDiff = rangeToChange.Start.MarkupPosition - elementRange.Start.MarkupPosition; int endPositionDiff = rangeToChange.End.MarkupPosition - elementRange.End.MarkupPosition; // @RIBBON TODO: Appropriately preserve element attributes when changing tag ids? MarkupRange newElementRange = markupServices.CreateMarkupRange(htmlStyleHelper.WrapRangeInSpanElement(tagAfter, null, elementRange)); markupServices.RemoveElement(element); MarkupPointer startPointer = rangeToChange.Start.Clone(); startPointer.MoveToMarkupPosition(startPointer.Container, newElementRange.Start.MarkupPosition + startPositionDiff); if (startPointer.IsLeftOf(rangeToChange.Start)) rangeToChange.Start.MoveToPointer(startPointer); MarkupPointer endPointer = rangeToChange.End.Clone(); endPointer.MoveToMarkupPosition(endPointer.Container, newElementRange.End.MarkupPosition + endPositionDiff); if (endPointer.IsLeftOf(elementRange.End)) rangeToChange.End.MoveToPointer(endPointer); } if (selectionStartedEmpty) { selection.Start.MoveToMarkupPosition(selection.Start.Container, rangeToChange.Start.MarkupPosition + parentStartDiff); selection.Collapse(true); } }
/// <summary> /// Returns the HTML Elements that a direct children of this range. /// Note: Only children that are completely contained in this range will be returned. /// </summary> /// <returns></returns> public IHTMLElement[] GetTopLevelElements(IHTMLElementFilter filter) { return(GetTopLevelBlocksAndCells(filter, false)); }
private bool SupportsAlignmentAttribute(IHTMLElement element) { if (supportsAlignmentAttribute == null) { // Per the HTML 4.01 and XHTML Transitional DTD, the following elements support the HTML // align="LEFT|CENTER|RIGHT|JUSTIFY" attribute. supportsAlignmentAttribute = ElementFilters.CreateCompoundElementFilter( ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_DIV)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_P)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H1)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H2)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H3)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H4)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H5)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H6)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_COLGROUP)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_COL)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_THEAD)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TBODY)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TFOOT)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TR)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TH)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TD))); } return supportsAlignmentAttribute(element); }
private IHTMLElement GetNextElement(MarkupPointer start, MarkupRange boundaries, IHTMLElementFilter filter, bool forward) { start = start.Clone(); MarkupPointer boundary = forward ? boundaries.End : boundaries.Start; MarkupContext moveResult = new MarkupContext(); _MARKUP_CONTEXT_TYPE skipContext = _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope; //advance the pointer if (forward) { start.Right(true, moveResult); } else { start.Left(true, moveResult); } while (forward ? start.IsLeftOf(boundary) : start.IsRightOf(boundary)) { if (moveResult.Element != null && moveResult.Context != skipContext && filter(moveResult.Element)) { return(moveResult.Element); } //advance the pointer if (forward) { start.Right(true, moveResult); } else { start.Left(true, moveResult); } } return(null); }
public IHTMLElement ParentElement(IHTMLElementFilter filter) { IHTMLElement parent = ParentElement(); while (parent != null && !filter(parent)) { parent = parent.parentElement; } return parent; }
public CompoundElementFilter(IHTMLElementFilter[] filters) { _filters = filters; }
public IHTMLElement SeekElementRight(IHTMLElementFilter filter) { return(SeekElementRight(filter, null)); }
//this is similar to the GetTopLevelElements except will also return table cells if correct filter // is set and recurse is equal to true public IHTMLElement[] GetTopLevelBlocksAndCells(IHTMLElementFilter filter, bool recurse) { ArrayList list = new ArrayList(); Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupContext context = p.Right(false); //move p through the range to locate each of the top level elements while (p.IsLeftOf(End)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { p.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); if (usedElements[context.Element] == null) { if (p.IsLeftOfOrEqualTo(End) && (filter == null || filter(context.Element))) { list.Add(context.Element); } //special case--inside of a table element, want to get out the cells inside else if (recurse && ElementFilters.TABLE_ELEMENTS(context.Element)) { MarkupRange newRange = MarkupServices.CreateMarkupRange(context.Element); newRange.Start.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin); if (newRange.Start.IsLeftOf(Start)) { newRange.Start.MoveToPointer(Start); } if (newRange.End.IsRightOf(End)) { newRange.End.MoveToPointer(End); } //recursively check inside table element for table cells list.AddRange(newRange.GetTopLevelBlocksAndCells(filter, true)); } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } } p.Right(true, context); } return HTMLElementHelper.ToElementArray(list); }
/// <summary> /// Returns the HTML Elements that a direct children of this range. /// Note: Only children that are completely contained in this range will be returned. /// </summary> /// <returns></returns> public IHTMLElement[] GetTopLevelElements(IHTMLElementFilter filter) { return GetTopLevelBlocksAndCells(filter, false); }
public static void RemoveAttributes(MshtmlMarkupServices markupServices, MarkupRange selection, string[] attributesToRemove) { IHTMLElementFilter[] filters = new IHTMLElementFilter[attributesToRemove.Length]; for (int i = 0; i < attributesToRemove.Length; i++) filters[i] = ElementFilters.CreateElementAttributeFilter(attributesToRemove[i]); IHTMLElement[] elements = selection.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false); foreach (IHTMLElement element in elements) { foreach (string attribute in attributesToRemove) element.removeAttribute(attribute, 0); } }
private bool SupportsPixelHeightAttribute(IHTMLElement element) { if (this.supportsPixelHeightAttribute == null) { // Per the HTML 4.01 and XHTML Transitional DTD, the following elements support the HTML height="X" // attribute (where X is in pixels). this.supportsPixelHeightAttribute = ElementFilters.CreateCompoundElementFilter( ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_IMG)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_APPLET)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_OBJECT)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TH)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TD)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_IFRAME))); } return this.supportsPixelHeightAttribute(element); }
/// <summary> /// Returns the closest parent element that matches the specified filter. /// </summary> /// <param name="filter"></param> /// <returns></returns> public IHTMLElement GetParentElement(IHTMLElementFilter filter) { IHTMLElement parent = CurrentScope; while (parent != null && !filter(parent)) { parent = parent.parentElement; } return parent; }
private bool SupportsPercentageWidthAttribute(IHTMLElement element) { if (this.supportsPercentageWidthAttribute == null) { // Per the HTML 4.01 and XHTML Transitional DTD, the following elements support the HTML width="X" // attribute (where X is in pixels). this.supportsPercentageWidthAttribute = ElementFilters.CreateCompoundElementFilter( ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_IMG)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TABLE)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_COLGROUP)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_COL)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TH)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TD)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_HR)), ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_IFRAME))); } return this.supportsPercentageWidthAttribute(element); }
/// <summary> /// Returns an array of the parent elements that match the specified filter. /// </summary> /// <param name="filter"></param> /// <returns>an array of matching parents (closest parent at index zero)</returns> public IHTMLElement[] GetParentElements(IHTMLElementFilter filter) { ArrayList list = null; IHTMLElement parent = CurrentScope; while (parent != null) { if (filter(parent)) { if (list == null) list = new ArrayList(); list.Add(parent); } parent = parent.parentElement; } if (list != null) return HTMLElementHelper.ToElementArray(list); else return new IHTMLElement[0]; }
public static void ChangeElementTagIds(MshtmlMarkupServices markupServices, MarkupRange selection, _ELEMENT_TAG_ID[] tagBefore, _ELEMENT_TAG_ID tagAfter) { HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices); int parentStartDiff = 0; MarkupRange rangeToChange; bool selectionStartedEmpty = selection.IsEmpty(); if (selectionStartedEmpty) { // Operate on parent block element rangeToChange = markupServices.CreateMarkupRange(selection.ParentBlockElement()); parentStartDiff = selection.Start.MarkupPosition - rangeToChange.Start.MarkupPosition; } else { rangeToChange = selection; // If expanding the selection would not include any new text, then expand it. // <h1>|abc|</h1> --> |<h1>abc</h1>| rangeToChange.MoveOutwardIfNoText(); } IHTMLElementFilter[] filters = new IHTMLElementFilter[tagBefore.Length]; for (int i = 0; i < tagBefore.Length; i++) { filters[i] = ElementFilters.CreateTagIdFilter(markupServices.GetNameForTagId(tagBefore[i])); } IHTMLElement[] elements = rangeToChange.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false); foreach (IHTMLElement element in elements) { MarkupRange elementRange = markupServices.CreateMarkupRange(element); int startPositionDiff = rangeToChange.Start.MarkupPosition - elementRange.Start.MarkupPosition; int endPositionDiff = rangeToChange.End.MarkupPosition - elementRange.End.MarkupPosition; // @RIBBON TODO: Appropriately preserve element attributes when changing tag ids? MarkupRange newElementRange = markupServices.CreateMarkupRange(htmlStyleHelper.WrapRangeInSpanElement(tagAfter, null, elementRange)); markupServices.RemoveElement(element); MarkupPointer startPointer = rangeToChange.Start.Clone(); startPointer.MoveToMarkupPosition(startPointer.Container, newElementRange.Start.MarkupPosition + startPositionDiff); if (startPointer.IsLeftOf(rangeToChange.Start)) { rangeToChange.Start.MoveToPointer(startPointer); } MarkupPointer endPointer = rangeToChange.End.Clone(); endPointer.MoveToMarkupPosition(endPointer.Container, newElementRange.End.MarkupPosition + endPositionDiff); if (endPointer.IsLeftOf(elementRange.End)) { rangeToChange.End.MoveToPointer(endPointer); } } if (selectionStartedEmpty) { selection.Start.MoveToMarkupPosition(selection.Start.Container, rangeToChange.Start.MarkupPosition + parentStartDiff); selection.Collapse(true); } }
public IHTMLElement SeekElementRight(IHTMLElementFilter filter) { return SeekElementRight(filter, null); }
private IHTMLElement GetNextElement(MarkupPointer start, MarkupRange boundaries, IHTMLElementFilter filter, bool forward) { start = start.Clone(); MarkupPointer boundary = forward ? boundaries.End : boundaries.Start; MarkupContext moveResult = new MarkupContext(); _MARKUP_CONTEXT_TYPE skipContext = _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope; //advance the pointer if (forward) start.Right(true, moveResult); else start.Left(true, moveResult); while (forward ? start.IsLeftOf(boundary) : start.IsRightOf(boundary)) { if (moveResult.Element != null && moveResult.Context != skipContext && filter(moveResult.Element)) { return moveResult.Element; } //advance the pointer if (forward) start.Right(true, moveResult); else start.Left(true, moveResult); } return null; }
public IHTMLElement SeekElementRight(IHTMLElementFilter filter, MarkupPointer boundaryPointer) { // initialize markup context used to track seeking MarkupContext markupContext = new MarkupContext(); markupContext.Context = _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope; while ((boundaryPointer == null || IsLeftOf(boundaryPointer)) && // apply boundary if one exists (markupContext.Context != _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None)) // otherwise use end of document { Right(true, markupContext); IHTMLElement element = markupContext.Element; if (element != null && filter(element)) return element; } // none found return null; }
/// <summary> /// Gets the elements in the range that match the filter. /// </summary> /// <param name="filter">the delegate testing each element to determine if it should be added to the list of elements to return</param> /// <param name="inScopeElementsOnly">if true, the only</param> /// <returns></returns> public IHTMLElement[] GetElements(IHTMLElementFilter filter, bool inScopeElementsOnly) { ArrayList list = new ArrayList(); if (!IsEmpty()) { Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupPointer end = MarkupServices.CreateMarkupPointer(End); MarkupContext context = p.Right(false); //move p through the range to locate each the elements adding elements that pass the filter while (p.IsLeftOfOrEqualTo(end)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { if (usedElements[context.Element] == null) { if ((inScopeElementsOnly && isInScope(context.Element)) || !inScopeElementsOnly) if (filter(context.Element)) { list.Add(context.Element); } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } } p.Right(true, context); } } return HTMLElementHelper.ToElementArray(list); }
/// <summary> /// MSHTML does not natively support adding/removing the <s> tag which is the equivalent of the /// <strike> tag. /// </summary> /// <param name="element">The element to check.</param> /// <returns>true if the element is a <s> tag and false otherwise.</returns> private bool IsNonSupportedStrikeThroughElement(IHTMLElement element) { if (isNonSupportedStrikeThroughElement == null) { isNonSupportedStrikeThroughElement = ElementFilters.CreateElementNameFilter(this.sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_S)); } return isNonSupportedStrikeThroughElement(element); }
/// <summary> /// Returns true if the the range contains an element that matches the filter /// </summary> /// <param name="filter"></param> /// <returns></returns> public bool ContainsElements(IHTMLElementFilter filter) { if (!IsEmpty()) { Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupContext context = p.Right(false); //move p through the range to locate each the elements adding elements that pass the filter while (p.IsLeftOfOrEqualTo(End)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { if (usedElements[context.Element] == null) { if (filter(context.Element)) { return true; } } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } p.Right(true, context); } } return false; }
/*private void DumpBreakRegions(params ElementBreakRegion[] breakRegions) { foreach(ElementBreakRegion breakRegion in breakRegions) { String elementStartName = breakRegion.BreakStartElement != null ? breakRegion.BreakStartElement.tagName : ""; String elementEndName = breakRegion.BreakEndElement != null ? breakRegion.BreakEndElement.tagName : ""; String breakContent = breakRegion.ContentRange.Text; if(breakContent != null) breakContent = breakContent.Replace('\r', ' ').Replace('\n', ' '); else breakContent = ""; Trace.WriteLine(String.Format("<{0}>{1}<{2}>", elementStartName, breakContent, elementEndName)); } }*/ /// <summary> /// Splits the specified range into regions based on a region break filter. /// </summary> /// <param name="range"></param> /// <returns></returns> private ElementBreakRegion[] SplitIntoElementRegions(MarkupRange range, IHTMLElementFilter regionBreakFilter) { ArrayList regions = new ArrayList(); MarkupRange blockRange = _markupServices.CreateMarkupRange(); blockRange.Start.MoveToPointer(range.Start); blockRange.End.MoveToPointer(range.Start); MarkupContext moveContext = new MarkupContext(); ElementBreakRegion currentRegion = new ElementBreakRegion(blockRange, null, null); while (currentRegion.ContentRange.End.IsLeftOf(range.End)) { if (moveContext.Element != null) { if (regionBreakFilter(moveContext.Element)) { //move the end of the region back before the break element to close this region currentRegion.ContentRange.End.Left(true); //save the closed region and start the next region currentRegion.BreakEndElement = moveContext.Element; regions.Add(currentRegion); currentRegion = new ElementBreakRegion(currentRegion.ContentRange.Clone(), moveContext.Element, null); currentRegion.ContentRange.Start.MoveToPointer(currentRegion.ContentRange.End); //move the region start over the break element currentRegion.ContentRange.Start.Right(true, moveContext); currentRegion.ContentRange.End.MoveToPointer(currentRegion.ContentRange.Start); } } currentRegion.ContentRange.End.Right(true, moveContext); } //save the last break region if (moveContext.Element != null && regionBreakFilter(moveContext.Element)) { //move the end of the region back before the break element to close this region currentRegion.ContentRange.End.Left(true); } if (currentRegion.ContentRange.End.IsRightOf(range.End)) currentRegion.ContentRange.End.MoveToPointer(range.End); regions.Add(currentRegion); return (ElementBreakRegion[])regions.ToArray(typeof(ElementBreakRegion)); }