public static IHTMLElement GetSelectedChildEditField(IHTMLElement parent, MarkupRange selection) { if (selection == null || !selection.Positioned) { Trace.Fail("Selection is invalid!"); return(null); } IHTMLElement element = selection.ParentElement(); if (element == null || !HTMLElementHelper.IsChildOrSameElement(parent, element)) { return(null); } do { if (InlineEditField.IsEditField(element)) { return(element); } element = element.parentElement; } while (element != null && element.sourceIndex != parent.sourceIndex); return(null); }
/// <summary> /// Returns a rectangle based on the given IDisplayPointer /// </summary> /// <param name="element">The element that contains the display pointer</param> /// <param name="displayPointer"></param> /// <returns></returns> protected Rectangle GetLineRect(IHTMLElement element, IDisplayPointerRaw displayPointer) { ILineInfo lineInfo; displayPointer.GetLineInfo(out lineInfo); Rectangle elementRect = HTMLElementHelper.GetClientRectangle(element); //determine the rectangle based on the baseline and text height. //Note: baseline is relative to the parent element, and the text //height includes the textDescent, which is below the baseline int lineBottom = elementRect.Y + lineInfo.baseLine + lineInfo.textDescent; int lineTop = lineBottom - lineInfo.textHeight; int lineLeft = elementRect.X; int lineWidth = elementRect.Width; //Calculate the height of line. Since the bottom pixel line is shared by the next line, //we subtract 1 from the height. This height exactly matches height of the caret. //Note: this height adjustment fixes a bug that can occur with some text styles where a //caret placed on the next line is detected as being within this rectangle. int lineHeight = lineInfo.textHeight - 1; //create a rectangle that exactly fits the caret for this line //Note: this can be verified by painting a rectangle over the line using this rectangle return(new Rectangle(lineLeft, lineTop, lineWidth, lineHeight)); }
protected override int HandlePreHandleEvent(int inEvtDispId, IHTMLEventObj pIEventObj) { if (ShouldProcessEvents(inEvtDispId, pIEventObj)) { if (inEvtDispId == DISPID_HTMLELEMENTEVENTS2.ONMOUSEDOWN) { leftMouseDown = (Control.MouseButtons & MouseButtons.Left) == MouseButtons.Left; if (!Selected && HTMLElementHelper.IsChildOrSameElement(HTMLElement, pIEventObj.srcElement)) { return(HandlePreHandleEventLeftMouseButtonDown(inEvtDispId, pIEventObj)); } rightMouseDown = (Control.MouseButtons & MouseButtons.Right) == MouseButtons.Right; if (rightMouseDown) { //cancel the event so that the editor doesn't try to do a right drag drop //we'll handle showing the context menu on our own. return(HRESULT.S_OK); } } int controlResult = base.HandlePreHandleEvent(inEvtDispId, pIEventObj); UpdateCursor(Selected, inEvtDispId, pIEventObj); if (_resizerControl.Mode == SizerMode.Resizing) { //if the control is resizing, kill all events so that the editor doesn't //try to do a drag and drop. return(HRESULT.S_OK); } else { if (_dragDropController.PreHandleEvent(inEvtDispId, pIEventObj) == HRESULT.S_OK) { return(HRESULT.S_OK); } //eat the mouse events so that the editor doesn't try to //do anything funny (like opening a browser URL). //Note: Allow non-left clicks through for right-click context menus switch (inEvtDispId) { case DISPID_HTMLELEMENTEVENTS2.ONMOUSEUP: if (rightMouseDown & (Control.MouseButtons & MouseButtons.Right) != MouseButtons.Right) { rightMouseDown = false; Point p = EditorContext.PointToScreen(new Point(pIEventObj.clientX, pIEventObj.clientY)); EditorContext.ShowContextMenu(p); return(HRESULT.S_OK); } return(leftMouseDown ? HRESULT.S_OK : HRESULT.S_FALSE); } } return(controlResult); } return(HRESULT.S_FALSE); }
/// <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]); } }
/// <summary> /// Fixes up all the headers in the entire markupRange. /// </summary> /// <param name="turnBold">Whether or not the text should be turning bold.</param> private void FixupHeaders(bool turnBold) { IHTMLElement elementStartHeader = markupRange.Start.GetParentElement(ElementFilters.HEADER_ELEMENTS); IHTMLElement elementEndHeader = markupRange.End.GetParentElement(ElementFilters.HEADER_ELEMENTS); MarkupRange currentRange = markupRange.Clone(); if (elementStartHeader != null) { // Takes care of the following cases: // <h1>...|blah|...</h1> // <h1>...|blah...</h1>...|... MarkupRange startRange = markupServices.CreateMarkupRange(elementStartHeader, false); startRange.Start.MoveToPointer(markupRange.Start); if (startRange.End.IsRightOf(markupRange.End)) { startRange.End.MoveToPointer(markupRange.End); } FixupHeaderRange(startRange, turnBold); currentRange.Start.MoveAdjacentToElement(elementStartHeader, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); if (currentRange.End.IsLeftOf(currentRange.Start)) { currentRange.End.MoveToPointer(currentRange.Start); } } if (elementEndHeader != null && !HTMLElementHelper.ElementsAreEqual(elementStartHeader, elementEndHeader)) { // Takes care of the following case: // ...|...<h1>...blah|...</h1> MarkupRange endRange = markupServices.CreateMarkupRange(elementEndHeader, false); endRange.End.MoveToPointer(markupRange.End); FixupHeaderRange(endRange, turnBold); currentRange.End.MoveAdjacentToElement(elementEndHeader, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); if (currentRange.Start.IsRightOf(currentRange.End)) { currentRange.Start.MoveToPointer(currentRange.End); } } if (!markupRange.InRange(currentRange)) { return; } IHTMLElement[] headerElements = currentRange.GetElements(ElementFilters.HEADER_ELEMENTS, true); if (headerElements != null && headerElements.Length > 0) { foreach (IHTMLElement element in headerElements) { MarkupRange headerRange = markupServices.CreateMarkupRange(element, false); FixupHeaderRange(headerRange, turnBold); } } }
public void RemoveElementsByTagId(_ELEMENT_TAG_ID tagId, bool onlyIfNoAttributes) { if (tagId == _ELEMENT_TAG_ID.TAGID_NULL) { return; } // Remove the tagId up the parent chain IHTMLElement currentElement = ParentElement(); while (currentElement != null) { if (MarkupServices.GetElementTagId(currentElement) == tagId && (!onlyIfNoAttributes || !HTMLElementHelper.HasMeaningfulAttributes(currentElement))) { try { MarkupServices.RemoveElement(currentElement); } catch (COMException e) { Trace.Fail(String.Format("Failed to remove element ({0}) with error: {1}", currentElement.outerHTML, // {0} e // {1} )); } } currentElement = currentElement.parentElement; } // Remove any other instances IHTMLElement[] elements = GetElements(ElementFilters.CreateTagIdFilter(MarkupServices.GetNameForTagId(tagId)), false); foreach (IHTMLElement e in elements) { if (MarkupServices.GetElementTagId(e) == tagId && (!onlyIfNoAttributes || !HTMLElementHelper.HasMeaningfulAttributes(e))) { try { MarkupServices.RemoveElement(e); } catch (COMException ex) { Trace.Fail(String.Format("Failed to remove element ({0}) with error: {1}", e.outerHTML, // {0} ex // {1} )); } } } }
public TableCellEditingElementBehavior GetCellBehavior(IHTMLElement cellElement) { foreach (TableCellEditingElementBehavior cellBehavior in _cellElementBehaviors) { if (cellBehavior.Attached && HTMLElementHelper.ElementsAreEqual(cellElement, cellBehavior.HTMLElement)) { return(cellBehavior); } } // didn't find the behavior return(null); }
public static void InsertEditorHtmlIntoElement(IContentSourceSidebarContext contentSourceContext, SmartContentSource source, ISmartContent sContent, IHTMLElement element) { string content = source.GenerateEditorHtml(sContent, contentSourceContext); // If the plugin returned null has the HTML it would like to insert, remove the element from the editor if (content == null) { HTMLElementHelper.RemoveElement(element); } else { InsertContentIntoElement(content, sContent, contentSourceContext, element); } }
/// <summary> /// Wraps the range from startPointer to endPointer with the given element (as long as the range is non-empty) /// and then moves the pointers past the inserted element. /// </summary> /// <param name="element">The element to wrap the range in.</param> /// <param name="markupServices">The MarkupServices for the start and end pointers.</param> /// <param name="startPointer">Pointer to place the beginning of the element.</param> /// <param name="endPointer">Pointer to place the end of the element.</param> private void InsertElement(IHTMLElement element, MshtmlMarkupServices markupServices, MarkupPointer startPointer, MarkupPointer endPointer) { Debug.Assert(startPointer.IsLeftOfOrEqualTo(endPointer), "Expected start to be left of or equal to end!"); Debug.Assert(HTMLElementHelper.ElementsAreEqual(startPointer.CurrentScope, endPointer.CurrentScope), "Expected start and end to be in the same scope, otherwise resulting HTML will be invalid!"); if (startPointer.IsLeftOf(endPointer)) { markupServices.InsertElement(element, startPointer, endPointer); } endPointer.Right(true); startPointer.MoveToPointer(endPointer); }
/// <summary> /// Delayed processing for showing tooltips (only show them if the user hovers /// over a link for more than a specified period of time) /// </summary> /// <param name="sender">sender</param> /// <param name="e">event args</param> private void toolTipDelayTimer_Tick(object sender, EventArgs e) { try { // get the delay element from the timer ToolTipDelayTimer toolTipDelayTimer = sender as ToolTipDelayTimer; IHTMLElement delayElement = toolTipDelayTimer.DelayElement; // stop and dispose timer toolTipDelayTimer.Stop(); toolTipDelayTimer.Dispose(); // determine the link element the mouse is currently over and check to see // if the delay element is the same as the current element -- if so, show the tooltip IHTMLElement mouseOverElement = _htmlEditorControl.ElementAtPoint(Control.MousePosition); if (mouseOverElement != null && (GetLinkElement(mouseOverElement) == delayElement) && !navigatedToCurrentLinkElement && currentLinkElement != null) { // calculate the screen coordinate of the top of the current link element int elementClientY = HTMLElementHelper.GetTopRelativeToClient(mouseOverElement); Point elementScreenPt = _htmlEditorControl.ClientPointToScreenPoint(new Point(0, elementClientY)); // set location - x-based on mouse, y-based on top of element (minus height of tooltip) toolTip.Location = new Point(Control.MousePosition.X, elementScreenPt.Y - 20); // set tooltip text string href = (string)currentLinkElement.getAttribute("href", 2); // 2 means don't auto-escape href = StringHelper.Ellipsis(href, 35); toolTip.SetToolTip(String.Format(CultureInfo.CurrentCulture, Res.Get(StringId.LinkToolTip), href)); // start timer which monitors whether the main frame is still active and // hides the tooltip if it does not _frameActiveTimer = new Timer(); _frameActiveTimer.Interval = 100; _frameActiveTimer.Tick += new EventHandler(frameActiveTimer_Tick); _frameActiveTimer.Start(); } } catch (Exception ex) { // eat exceptions that occur in here (bizzare timing bugs can occur w/ drag and // drop of images -- this is harmless and the user shouldn't be burdened with // an error message Debug.Fail("Unexpected error during tool tip delay timer: " + ex.ToString()); } }
private IHTMLElement GetTargetCell(Point clientPoint) { // maximum amount of scanning buffer is based on cell spacing int maxScanningRange = Math.Max(TableHelper.GetAttributeAsInteger(_table.cellSpacing), 2); // copy client point so we can modify the x-coordinate while scanning Point targetPoint = new Point(clientPoint.X, clientPoint.Y); // if we go past the end of the table allow the cell closest to the cursor // to become the target cell (necessary for sizing the table larger) Point xTargetPoint = new Point(targetPoint.X, targetPoint.Y); IHTMLTableCell targetCell = null; while (targetCell == null && xTargetPoint.X >= (targetPoint.X - maxScanningRange)) // 0 ) { // determine the cell we are over targetCell = _editorContext.ElementFromClientPoint(xTargetPoint) as IHTMLTableCell; // screen cells that don't belong to us if (!HTMLElementHelper.ElementsAreEqual(_table as IHTMLElement, TableHelper.GetContainingTableElement(targetCell as IHTMLElement) as IHTMLElement)) { targetCell = null; } xTargetPoint.X--; } // if we got a target cell then ensure that the point is over the document area if (targetCell != null) { if (_editorContext.PointIsOverDocumentArea(clientPoint)) { return(targetCell as IHTMLElement); } else { return(null); } } else { return(null); } }
public TableSelection(MarkupRange markupRange) { // calculate the begin and end cells IHTMLTableCell beginCell; IHTMLTableCell endCell; ArrayList selectedCells; FindCellRange(markupRange, out selectedCells, out beginCell, out endCell); // see if the two cells have a single containing table IHTMLTable table = GetSelectedTable(beginCell, endCell, markupRange) as IHTMLTable; // if we have a table then calculate the rest of our states if (table != null) { // validate the table selection if (ValidateTableSelection(table, markupRange, out _entireTableSelected)) { _table = table; _beginCell = beginCell; _endCell = endCell; // filter selected cells to only include direct descendents of this table (no // cells from nested tables) _selectedCells = new ArrayList(); foreach (IHTMLElement cell in selectedCells) { if (HTMLElementHelper.ElementsAreEqual(TableHelper.GetContainingTableElement(cell) as IHTMLElement, _table as IHTMLElement)) { _selectedCells.Add(cell); } } _hasContiguousSelection = !HTMLElementHelper.ElementsAreEqual(_beginCell as IHTMLElement, _endCell as IHTMLElement); _beginRow = GetContainingRowForCell(beginCell); _endRow = GetContainingRowForCell(endCell); _beginColumn = new HTMLTableColumn(_table, beginCell); _endColumn = new HTMLTableColumn(_table, endCell); } } }
//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> /// <font><span>aaa[splitPoint]bbb</span></font> --> <font><span>aaa</span></font><font>[splitPoint]<span>bbb</span></font> /// </summary> private void SplitInlineTags(MarkupPointer splitPoint) { Debug.Assert(splitPoint.Positioned); IHTMLElement currentElement = splitPoint.GetParentElement(ElementFilters.CreateElementPassFilter()); while (currentElement != null) { if (!ElementFilters.IsInlineElement(currentElement)) { return; } IHTMLElement parentElement = currentElement.parentElement; MarkupRange currentElementRange = _markupServices.CreateMarkupRange(currentElement, false); MarkupRange leftRange = _markupServices.CreateMarkupRange(); IHTMLElement leftElement = _markupServices.CreateElement(_markupServices.GetElementTagId(currentElement), null); HTMLElementHelper.CopyAttributes(currentElement, leftElement); leftRange.MoveToPointers(currentElementRange.Start, splitPoint); _markupServices.InsertElement(leftElement, leftRange.Start, leftRange.End); splitPoint.MoveAdjacentToElement(leftElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); MarkupRange rightRange = _markupServices.CreateMarkupRange(); IHTMLElement rightElement = _markupServices.CreateElement(_markupServices.GetElementTagId(currentElement), null); HTMLElementHelper.CopyAttributes(currentElement, rightElement); rightRange.MoveToPointers(splitPoint, currentElementRange.End); #if DEBUG // Verify that the right range does not overlap the left *element* MarkupRange leftElementRange = _markupServices.CreateMarkupRange(leftElement, true); Debug.Assert(leftElementRange.End.IsLeftOfOrEqualTo(rightRange.Start), "Your right range overlaps the left element that you just created!"); #endif _markupServices.InsertElement(rightElement, rightRange.Start, rightRange.End); splitPoint.MoveAdjacentToElement(rightElement, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); _markupServices.RemoveElement(currentElement); currentElement = parentElement; } }
protected override bool QueryElementSelected() { if (_tableIsEditable) { TableSelection tableSelection = new TableSelection(EditorContext.Selection.SelectedMarkupRange); if ((tableSelection.Table != null) && HTMLElementHelper.ElementsAreEqual(HTMLElement, tableSelection.Table as IHTMLElement)) { _currentTableSelection = tableSelection; return(true); } else { _currentTableSelection = null; return(false); } } else { return(false); } }
private IHTMLElement GetSelectedTable(IHTMLTableCell beginCell, IHTMLTableCell endCell, MarkupRange selectionMarkupRange) { // screen null cases if (beginCell == null || endCell == null) { return(null); } // get containing tables IHTMLTable beginTable = TableHelper.GetContainingTableElement(beginCell as IHTMLElement); IHTMLTable endTable = TableHelper.GetContainingTableElement(endCell as IHTMLElement); // see if they are from the same table if (HTMLElementHelper.ElementsAreEqual(beginTable as IHTMLElement, endTable as IHTMLElement)) { return(beginTable as IHTMLElement); } else { return(null); } }
private void CopyBodyAttributes(string sourceHtml, IHTMLElement destinationBody) { Debug.Assert(destinationBody != null, "destinationBody should not be null!"); if (destinationBody == null) { return; } var finder = new BodyTagFinder(sourceHtml); finder.Parse(); if (finder.BodyBeginTag != null) { StringBuilder bodyAttributes = new StringBuilder(); foreach (Attr attr in finder.BodyBeginTag.Attributes) { bodyAttributes.AppendFormat(CultureInfo.InvariantCulture, "{0} ", attr); } IHTMLElement sourceBodyElement = EditorContext.MarkupServices.CreateElement(_ELEMENT_TAG_ID.TAGID_BODY, bodyAttributes.ToString()); HTMLElementHelper.CopyAttributes(sourceBodyElement, destinationBody); } }
public static IHTMLElement[] FindText(string text, IHTMLElement fromElement) { try { string normalizedText = NormalizeText(text); ArrayList elementList = new ArrayList(); AddElementsContainingText(normalizedText, fromElement, elementList); IHTMLElement[] elements = HTMLElementHelper.ToElementArray(elementList); return(elements); } catch (ArgumentException e) { Trace.WriteLine(e.Message); return(new IHTMLElement[0]); } catch (Exception e) { Trace.Fail("exception during findText", e.ToString()); return(new IHTMLElement[0]); } }
/// <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)); }
public bool Filter(IHTMLElement e) { return(HTMLElementHelper.ElementsAreEqual(e, _element)); }
void IHtmlEditorCommandSource.ApplyFontSize(float fontSize) { ApplyFormattingTag("font", "size=\"" + HTMLElementHelper.PointFontSizeToHtmlFontSize(fontSize) + "\""); }
protected Rectangle GetClientRectangle(ELEMENT_REGION outerBoundary) { Rectangle elementBounds = GetClientRectangle(); try { if (outerBoundary == ELEMENT_REGION.BORDER) { return(new Rectangle(elementBounds.Location, elementBounds.Size)); } int marginTop = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringMarginTop, HTMLElement, null, true); int marginBottom = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringMarginBottom, HTMLElement, null, true); int marginLeft = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringMarginLeft, HTMLElement, null, false); int marginRight = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringMarginRight, HTMLElement, null, false); int paddingTop = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringPaddingTop, HTMLElement, null, true); int paddingBottom = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringPaddingBottom, HTMLElement, null, true); int paddingLeft = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringPaddingLeft, HTMLElement, null, false); int paddingRight = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringPaddingRight, HTMLElement, null, false); int borderTop = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringBorderTop, HTMLElement, null, true); int borderBottom = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringBorderBottom, HTMLElement, null, true); int borderLeft = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringBorderLeft, HTMLElement, null, false); int borderRight = (int)HTMLElementHelper.CSSUnitStringToPointSize(HTMLElementHelper.CSSUnitStringBorderRight, HTMLElement, null, false); int offsetX; int offsetY; int offsetRight; int offsetBottom; if (outerBoundary == ELEMENT_REGION.PADDING) { offsetX = borderLeft; offsetY = borderTop; offsetRight = -borderRight; offsetBottom = -borderBottom; } else if (outerBoundary == ELEMENT_REGION.CONTENT) { offsetX = paddingLeft + borderLeft; offsetY = paddingTop + borderTop; offsetRight = -paddingRight - borderRight; offsetBottom = -paddingBottom - borderBottom; } else if (outerBoundary == ELEMENT_REGION.MARGIN) { offsetX = -marginLeft; offsetY = -marginTop; offsetRight = marginRight; offsetBottom = marginBottom; } else { throw new ArgumentException("Unnsupported ELEMENT_REGION: " + outerBoundary.ToString()); } Rectangle rect = new Rectangle(elementBounds.Location, elementBounds.Size); rect.X += offsetX; rect.Y += offsetY; rect.Width += offsetRight - offsetX; rect.Height += offsetBottom - offsetY; return(rect); } catch (Exception e) { Trace.WriteLine("Error calculating element paint boundary: " + e.ToString()); return(new Rectangle(elementBounds.Location, elementBounds.Size)); } }
private static void ProcessInitializedImages(List <NewImageInfo> newImages, IBlogPostHtmlEditor currentEditor, ContentEditor editor, Control owner, bool selectLastImage) { // Remove all invalid images first List <NewImageInfo> newImagesToUpdate = new List <NewImageInfo>(); for (int i = 0; i < newImages.Count; i++) { NewImageInfo info = newImages[i]; if (info.Remove) { using (ContentEditor.EditorUndoUnit undo = new ContentEditor.EditorUndoUnit(currentEditor, true)) { info.DisabledImageBehavior.DetachFromElement(); HTMLElementHelper.RemoveElement(info.Element); undo.Commit(); } } else { newImagesToUpdate.Add(info); } } // Queue up processing for any remaining valid images MultiTaskHelper tasks = new MultiTaskHelper(30); for (int i = 0; i < newImagesToUpdate.Count; i++) { bool lastElement = i == (newImagesToUpdate.Count - 1); NewImageInfo info = newImagesToUpdate[i]; tasks.AddWork(delegate { // WinLive 214012: If the original insertion operation is undone before we get to this point make // sure we don't attempt to update the HTML. Elements that are removed via an undo, but that we // still hold a reference to, are put into another document whose readyState is "uninitialized". // It's also possible that the picture has already been updated if a user undoes and redoes the // initial insertion multiple times. IHTMLDocument2 doc = (IHTMLDocument2)info.Element.document; if (doc == null || doc.readyState.Equals("uninitialized", StringComparison.OrdinalIgnoreCase) || BlogPostImageDataList.LookupImageDataByInlineUri(editor.ImageList, info.ImageData.InlineImageFile.Uri) != null) { info.DisabledImageBehavior.DetachFromElement(); return; } using (new QuickTimer("ProcessInitializedImage")) using (ContentEditor.EditorUndoUnit undo = new ContentEditor.EditorUndoUnit(currentEditor, true)) { editor.ImageList.AddImage(info.ImageData); info.Element.setAttribute("src", UrlHelper.SafeToAbsoluteUri(info.ImageData.InlineImageFile.Uri), 0); info.Element.removeAttribute("srcDelay", 0); // Create the decorators ImageEditingPropertyHandler.UpdateImageSource(info.ImageInfo, info.Element, editor, new ImageInsertHandler(), ImageDecoratorInvocationSource.InitialInsert); // Manually detach the behavior so that the image can be selected and resized. info.DisabledImageBehavior.DetachFromElement(); if (lastElement) { ApplicationPerformance.EndEvent("InsertImage"); HandleNewImage((BlogPostHtmlEditorControl)currentEditor, owner, info.Element, selectLastImage); } undo.Commit(); if (editor.ETWProvider != null) { editor.ETWProvider.WriteEvent("InlinePhotoEnd"); } } }); } // If there were no images to update, stop the perf timer if (newImagesToUpdate.Count == 0) { ApplicationPerformance.EndEvent("InsertImage"); } // When the editor is closing, or changing to a new blog post we need to get rid of this object // which will then stop all the unfinished images from continuing to load. editor.DisposeOnEditorChange(tasks); tasks.Start(); }
private void timer_Tick(object sender, EventArgs e) { if (reentrant) { return; } reentrant = true; Timer timer = null; try { timer = sender as Timer; IHTMLDocument2 document = _browserControl.Document as IHTMLDocument2; // make sure the document is ready if (!DocumentReady(document)) { if (TimedOut) { CleanupAndExit(timer); } return; } if (Ids != null) { IHTMLDocument3 doc3 = document as IHTMLDocument3; foreach (string elementId in Ids) { IHTMLStyle3 style3 = (IHTMLStyle3)(doc3.getElementById(elementId)).style; style3.wordWrap = "normal"; } int originalWidth = _browserControl.Width; int originalHeight = _browserControl.Height; foreach (string elementId in Ids) { try { IHTMLElement element = doc3.getElementById(elementId); _browserControl.Height = element.offsetHeight + 2 + 2; element.scrollIntoView(true); Padding padding = HTMLElementHelper.PaddingInPixels(element); Color backgroundColor = HTMLColorHelper.GetBackgroundColor(element, true, null, Color.White); using (Bitmap elementBitmap = GetElementPreviewImage(doc3, element, _browserControl.Width, _browserControl.Height)) { _htmlScreenCaptureCore.SetElementCaptureProperties(elementId, elementBitmap, backgroundColor, padding); } } catch (Exception ex) { Trace.Fail("Failed to capture element " + elementId + ": " + ex); } } // Restore the browser control size _browserControl.Width = originalWidth; _browserControl.Height = originalHeight; } // fire event to see if the Bitmap is ready using (Bitmap bitmap = HtmlScreenCaptureCore.TakeSnapshot((IViewObject)_browserControl.Document, _browserControl.Width, _browserControl.Height)) { HtmlScreenCaptureAvailableEventArgsCore ea = new HtmlScreenCaptureAvailableEventArgsCore(bitmap); _htmlScreenCaptureCore.FireHtmlScreenCaptureAvailable(ea); if (ea.CaptureCompleted) { // provide the bitmap to our parent object _htmlScreenCaptureCore.SetCapturedBitmap(bitmap); //bitmap.Save(@"c:\temp\captured.bmp"); // exit CleanupAndExit(timer); } else if (TimedOut) // if we have timed out then exit { CleanupAndExit(timer); } // otherwise just let the Timer call us again // at the next interval... } } catch (Exception ex) { _htmlScreenCaptureCore.SetException(ex); CleanupAndExit(timer); } finally { reentrant = false; } }
/// <summary> /// Fixes up a range that is contained in a single header element. /// </summary> /// <param name="range">A range that is contained in a single header element.</param> /// <param name="turnBold">Whether or not the text should be turning bold.</param> private void FixupHeaderRange(MarkupRange range, bool turnBold) { IHTMLElement parentHeaderElement = range.ParentBlockElement(); if (parentHeaderElement == null || !ElementFilters.IsHeaderElement(parentHeaderElement)) { Debug.Fail("Expected entire range to be inside a single header element."); return; } MarkupRange expandedRange = range.Clone(); // Make sure we expand the selection to include any <font> tags that may be wrapping us. MarkupPointerMoveHelper.MoveUnitBounded(expandedRange.Start, MarkupPointerMoveHelper.MoveDirection.LEFT, MarkupPointerAdjacency.BeforeVisible, parentHeaderElement); MarkupPointerMoveHelper.MoveUnitBounded(expandedRange.End, MarkupPointerMoveHelper.MoveDirection.RIGHT, MarkupPointerAdjacency.BeforeVisible, parentHeaderElement); // Walks in-scope elements and clears out any elements or styles that might affect the bold formatting. var elementsToRemove = new List <IHTMLElement>(); expandedRange.WalkRange( delegate(MarkupRange currentexpandedRange, MarkupContext context, string text) { IHTMLElement currentElement = context.Element; if (currentElement != null && context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope) { if (IsStrongOrBold(currentElement)) { elementsToRemove.Add(currentElement); } else if (IsFontableElement(currentElement) && HTMLElementHelper.IsBold((IHTMLElement2)currentElement) != turnBold) { currentElement.style.fontWeight = String.Empty; } } return(true); }, true); elementsToRemove.ForEach(e => markupServices.RemoveElement(e)); // Walks the range to find any segments of text that need to be fixed up. var rangesToWrap = new List <MarkupRange>(); range.WalkRange( delegate(MarkupRange currentRange, MarkupContext context, string text) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) { TextStyles currentTextStyles = new TextStyles(currentRange.Start); if (currentTextStyles.Bold != turnBold) { rangesToWrap.Add(currentRange.Clone()); } } return(true); }, true); rangesToWrap.ForEach(r => WrapRangeInFontIfNecessary(r, turnBold)); }
public override IHTMLElement TitleElement(IHTMLDocument2 doc) { return(HTMLElementHelper.GetFragmentElement((IHTMLDocument3)doc, TITLE_FRAGMENT_ID)); }
private void PasteCellsIntoTable(IHTMLTable sourceTable, TableSelection tableSelection) { // collect up the top level cells we are pasting ArrayList cellsToPaste = new ArrayList(); foreach (IHTMLTableRow row in sourceTable.rows) { foreach (IHTMLElement cell in row.cells) { cellsToPaste.Add(cell); } } // get the list of cells we are pasting into int appendRows = 0; int cellsPerRow = 0; ArrayList targetCells; if (tableSelection.SelectedCells.Count > 1) { targetCells = tableSelection.SelectedCells; } else { targetCells = new ArrayList(); bool accumulatingCells = false; foreach (IHTMLTableRow row in tableSelection.Table.rows) { cellsPerRow = row.cells.length; foreach (IHTMLElement cell in row.cells) { if (!accumulatingCells && HTMLElementHelper.ElementsAreEqual(cell, tableSelection.BeginCell as IHTMLElement)) { accumulatingCells = true; } if (accumulatingCells) { targetCells.Add(cell); } } } // if the target cells aren't enough to paste all of the cells, then // calculate the number of rows we need to append to fit all of the // cells being pasted int cellGap = cellsToPaste.Count - targetCells.Count; if (cellGap > 0 && cellsPerRow > 0) { appendRows = cellGap / cellsPerRow + (cellGap % cellsPerRow == 0 ? 0 : 1); } } // perform the paste using (IUndoUnit undoUnit = EditorContext.CreateUndoUnit()) { // append rows if needed if (appendRows > 0) { // see if we can cast our editor context to the one required // by the table editor IHtmlEditorComponentContext editorContext = EditorContext as IHtmlEditorComponentContext; if (editorContext != null) { // markup range based on last target cell IHTMLElement lastCell = targetCells[targetCells.Count - 1] as IHTMLElement; MarkupRange lastCellRange = EditorContext.MarkupServices.CreateMarkupRange(lastCell); for (int i = 0; i < appendRows; i++) { IHTMLTableRow row = TableEditor.InsertRowBelow(editorContext, lastCellRange); foreach (IHTMLElement cell in row.cells) { targetCells.Add(cell); } lastCellRange = EditorContext.MarkupServices.CreateMarkupRange(row as IHTMLElement); } } else { Debug.Fail("Couldn't cast EditorContext!"); } } // do the paste for (int i = 0; i < cellsToPaste.Count && i < targetCells.Count; i++) { (targetCells[i] as IHTMLElement).innerHTML = (cellsToPaste[i] as IHTMLElement).innerHTML; } undoUnit.Commit(); } }
/// <summary> /// Returns the bounds of the element in client-based coordinatates. /// Note: These bounds seem to map to the outer edge of the element's border region. /// </summary> /// <returns></returns> protected Rectangle GetClientRectangle() { return(HTMLElementHelper.GetClientRectangle(HTMLElement)); }
/// <summary> /// Returns the .NET color that matches an element's background color. /// </summary> /// <param name="element"></param> /// <param name="detectImage"> /// Takes background-image into account when looking for background color. /// This is positionally sensitive so if you're not sure if your elements /// are in the "correct" positions relative to each other (such as in /// Web Layout view) you may want to set this to false. /// </param> /// <param name="pageUrl">The URL that should be used to escape relative background image paths. Can be null.</param> /// <param name="defaultColor"></param> /// <returns></returns> public static Color GetBackgroundColor(IHTMLElement element, bool detectImage, string pageUrl, Color defaultColor) { Rectangle childBounds = new Rectangle(HTMLElementHelper.CalculateOffset(element), new Size(element.offsetWidth, element.offsetHeight)); while (element != null) { IHTMLCurrentStyle style = ((IHTMLElement2)element).currentStyle; string colorStr = style.backgroundColor as string; if (!string.IsNullOrEmpty(colorStr) && colorStr != "transparent") { if (colorStr == "inherit") { detectImage = false; } else { return(GetColorFromHexColor(ParseColorToHex(colorStr), defaultColor)); } } string imageUrl = style.backgroundImage; if (detectImage && !string.IsNullOrEmpty(imageUrl) && imageUrl != "none" && (style.backgroundRepeat == "repeat" || style.backgroundRepeat == "repeat-y")) { StyleUrl styleUrl = new CssParser(imageUrl.Trim()).Next() as StyleUrl; Trace.Assert(styleUrl != null, "Style URL could not be parsed"); if (styleUrl != null) { // If there's a background image URL... string url = styleUrl.LiteralText; using (Stream imageStream = GetStreamForUrl(url, pageUrl, element)) { if (imageStream != null) { // ...and we were able to open/download it... using (Image image = Image.FromStream(imageStream)) { if (image is Bitmap) { // ...and it's a Bitmap, then use it to get the color. Rectangle containerBounds = new Rectangle(HTMLElementHelper.CalculateOffset(element), new Size(element.offsetWidth, element.offsetHeight)); Color color = GetColorFromBackgroundImage((Bitmap)image, childBounds, containerBounds, style); // We can't use semi-transparent backgrounds, keep looking if (color.A == 255) { return(color); } } } } } } } element = element.parentElement; } return(defaultColor); }
public override IHTMLElement PostBodyElement(IHTMLDocument2 doc) { return(HTMLElementHelper.GetFragmentElement((IHTMLDocument3)doc, BODY_FRAGMENT_ID)); }