Skip to content

Commit ad6c82f

Browse files
author
ArthurHub
committed
fix single box selection selecting only text
1 parent 4c85238 commit ad6c82f

File tree

1 file changed

+70
-31
lines changed

1 file changed

+70
-31
lines changed

Source/HtmlRenderer/Utils/DomUtils.cs

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,8 @@ public static string GenerateHtml(CssBox root, HtmlGenerationStyle styleGen = Ht
437437
var sb = new StringBuilder();
438438
if (root != null)
439439
{
440-
CssBox selectionRoot = null;
441-
var selectedBoxes = onlySelected ? CollectSelectedBoxes(root, out selectionRoot) : null;
440+
var selectedBoxes = onlySelected ? CollectSelectedBoxes(root) : null;
441+
var selectionRoot = onlySelected ? GetSelectionRoot(root, selectedBoxes) : null;
442442
WriteHtml(sb, root, styleGen, selectedBoxes, selectionRoot);
443443
}
444444
return sb.ToString();
@@ -537,39 +537,12 @@ private static int GetSelectedPlainText(StringBuilder sb, CssBox box)
537537
/// Collect the boxes that have at least one word down the hierarchy that is selected recursively.<br/>
538538
/// </summary>
539539
/// <param name="root">the box to check its sub-tree</param>
540-
/// <param name="selectionRoot">return the box the is the root of selected boxes (the first box to contain multiple selected boxes)</param>
541540
/// <returns>the collection to add the selected tags to</returns>
542-
private static Dictionary<CssBox, bool> CollectSelectedBoxes(CssBox root, out CssBox selectionRoot)
541+
private static Dictionary<CssBox, bool> CollectSelectedBoxes(CssBox root)
543542
{
544543
var selectedBoxes = new Dictionary<CssBox, bool>();
545544
var maybeBoxes = new Dictionary<CssBox, bool>();
546545
CollectSelectedBoxes(root, selectedBoxes, maybeBoxes);
547-
548-
// find the box the is the root of selected boxes (the first box to contain multiple selected boxes)
549-
selectionRoot = root;
550-
while (true)
551-
{
552-
bool foundRoot = false;
553-
CssBox selectedChild = null;
554-
foreach (var childBox in selectionRoot.Boxes)
555-
{
556-
if (selectedBoxes.ContainsKey(childBox))
557-
{
558-
if (selectedChild != null)
559-
{
560-
foundRoot = true;
561-
break;
562-
}
563-
selectedChild = childBox;
564-
}
565-
}
566-
567-
if (foundRoot || selectedChild == null)
568-
break;
569-
570-
selectionRoot = selectedChild;
571-
}
572-
573546
return selectedBoxes;
574547
}
575548

@@ -614,6 +587,72 @@ private static bool CollectSelectedBoxes(CssBox box, Dictionary<CssBox, bool> se
614587
return isInSelection;
615588
}
616589

590+
/// <summary>
591+
/// find the box the is the root of selected boxes (the first box to contain multiple selected boxes)
592+
/// </summary>
593+
/// <param name="root">the root of the boxes tree</param>
594+
/// <param name="selectedBoxes">the selected boxes to find selection root in</param>
595+
/// <returns>the box that is the root of selected boxes</returns>
596+
private static CssBox GetSelectionRoot(CssBox root, Dictionary<CssBox, bool> selectedBoxes)
597+
{
598+
var selectionRoot = root;
599+
var selectionRootRun = root;
600+
while (true)
601+
{
602+
bool foundRoot = false;
603+
CssBox selectedChild = null;
604+
foreach (var childBox in selectionRootRun.Boxes)
605+
{
606+
if (selectedBoxes.ContainsKey(childBox))
607+
{
608+
if (selectedChild != null)
609+
{
610+
foundRoot = true;
611+
break;
612+
}
613+
selectedChild = childBox;
614+
}
615+
}
616+
617+
if (foundRoot || selectedChild == null)
618+
break;
619+
620+
selectionRootRun = selectedChild;
621+
622+
// the actual selection root must be a box with html tag
623+
if (selectionRootRun.HtmlTag != null)
624+
selectionRoot = selectionRootRun;
625+
}
626+
627+
// if the selection root doesn't contained any named boxes in it then we must go one level up, otherwise we will miss the selection root box formatting
628+
if (!ContainsNamedBox(selectionRoot))
629+
{
630+
selectionRootRun = selectionRoot.ParentBox;
631+
while (selectionRootRun.ParentBox != null && selectionRootRun.HtmlTag == null)
632+
selectionRootRun = selectionRootRun.ParentBox;
633+
634+
if (selectionRootRun.HtmlTag != null)
635+
selectionRoot = selectionRootRun;
636+
}
637+
638+
return selectionRoot;
639+
}
640+
641+
/// <summary>
642+
/// Check if the given box has a names child box (has html tag) recursively.
643+
/// </summary>
644+
/// <param name="box">the box to check</param>
645+
/// <returns>true - in sub-tree there is a named box, false - otherwise</returns>
646+
private static bool ContainsNamedBox(CssBox box)
647+
{
648+
foreach (var childBox in box.Boxes)
649+
{
650+
if (childBox.HtmlTag != null || ContainsNamedBox(childBox))
651+
return true;
652+
}
653+
return false;
654+
}
655+
617656
/// <summary>
618657
/// Write the given html DOM sub-tree into the given string builder.<br/>
619658
/// If <paramref name="selectedBoxes"/> are given write html only from those tags.
@@ -633,7 +672,7 @@ private static void WriteHtml(StringBuilder sb, CssBox box, HtmlGenerationStyle
633672
(!box.HtmlTag.Attributes["href"].StartsWith("property") && !box.HtmlTag.Attributes["href"].StartsWith("method")))
634673
{
635674
WriteHtmlTag(sb, box, styleGen);
636-
if( box == selectionRoot )
675+
if (box == selectionRoot)
637676
sb.Append("<!--StartFragment-->");
638677
}
639678

0 commit comments

Comments
 (0)