/// <summary> /// Transforms HTML tags to word element labels with different styles to enable rich text. /// </summary> /// <param name="htmlText"></param> /// <param name="targetContainer"> /// The following need to set for the container's style: /// flex-direction: row; /// flex-wrap: wrap; /// </param> public static void RichTextToVisualElements(string htmlText, VisualElement targetContainer) { bool addError = false; string errorText = ""; try { XDocument.Parse("<content>" + htmlText + "</content>"); } catch (Exception e) { targetContainer.Clear(); errorText = e.Message; htmlText = ShowContentWithError(htmlText); addError = true; } // TODO should translation be a responsibility of the caller of this function instead? htmlText = Localization.Tr(htmlText); targetContainer.Clear(); bool boldOn = false; // <b> sets this on </b> sets off bool italicOn = false; // <i> </i> bool linkOn = false; string linkURL = ""; bool firstLine = true; bool lastLineHadText = false; // start streaming text per word to elements while retaining current style for each word block string[] lines = htmlText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); foreach (string line in lines) { string[] words = line.Split(new[] { " " }, StringSplitOptions.None); if (!firstLine && !lastLineHadText) { AddParagraphToElement(targetContainer); } if (!firstLine && lastLineHadText) { AddLinebreakToElement(targetContainer); //AddParagraphToElement(targetContainer); lastLineHadText = false; } foreach (string word in words) { if (word == "" || word == " " || word == " ") { continue; } lastLineHadText = true; string strippedWord = word; bool removeBold = false; bool removeItalic = false; bool addParagraph = false; bool removeLink = false; if (strippedWord.Contains("<b>")) { strippedWord = strippedWord.Replace("<b>", ""); boldOn = true; } if (strippedWord.Contains("<i>")) { strippedWord = strippedWord.Replace("<i>", ""); italicOn = true; } if (strippedWord.Contains("<a")) { strippedWord = strippedWord.Replace("<a", ""); linkOn = true; } if (linkOn && strippedWord.Contains("href=")) { strippedWord = strippedWord.Replace("href=", ""); int linkFrom = strippedWord.IndexOf("\"", StringComparison.Ordinal) + 1; int linkTo = strippedWord.LastIndexOf("\"", StringComparison.Ordinal); linkURL = strippedWord.Substring(linkFrom, linkTo - linkFrom); strippedWord = strippedWord.Substring(linkTo + 2, (strippedWord.Length - 2) - linkTo); strippedWord.Replace("\">", ""); } if (strippedWord.Contains("</a>")) { strippedWord = strippedWord.Replace("</a>", ""); // TODO </a>text -> also text part is still blue. Parse - for now we can take care when authoring. removeLink = true; } if (strippedWord.Contains("<br/>")) { strippedWord = strippedWord.Replace("<br/>", ""); addParagraph = true; } if (strippedWord.Contains("</b>")) { strippedWord = strippedWord.Replace("</b>", ""); removeBold = true; } if (strippedWord.Contains("</i>")) { strippedWord = strippedWord.Replace("</i>", ""); removeItalic = true; } if (boldOn) { Label wordLabel = new Label(strippedWord); wordLabel.style.unityFontStyleAndWeight = new StyleEnum <FontStyle>(FontStyle.Bold); targetContainer.Add(wordLabel); } else if (italicOn) { Label wordLabel = new Label(strippedWord); wordLabel.style.unityFontStyleAndWeight = new StyleEnum <FontStyle>(FontStyle.Italic); targetContainer.Add(wordLabel); } else if (addParagraph) { AddParagraphToElement(targetContainer); } else if (linkOn && !string.IsNullOrEmpty(linkURL)) { var label = new HyperlinkLabel { text = strippedWord, tooltip = linkURL }; label.RegisterCallback <MouseUpEvent, string>( (evt, linkurl) => { // Supporting only hyperlinks to Unity's websites. // The user needs be be logged in in order the hyperlink to work. UnityConnectProxy.OpenAuthorizedURLInWebBrowser(linkurl); }, linkURL ); targetContainer.Add(label); } else { Label newlabel = new Label(strippedWord); targetContainer.Add(newlabel); } if (removeBold) { boldOn = false; } if (removeItalic) { italicOn = false; } if (removeLink) { linkOn = false; linkURL = ""; } } firstLine = false; } if (addError) { var label = new ParseErrorLabel() { text = Localization.Tr("PARSE ERROR"), tooltip = Localization.Tr("Click here to see more information in the console.") }; label.RegisterCallback <MouseUpEvent>((e) => Debug.LogError(errorText)); targetContainer.Add(label); } }
/// <summary> /// Transforms HTML tags to word element labels with different styles to enable rich text. /// </summary> /// <param name="htmlText"></param> /// <param name="targetContainer"> /// The following need to set for the container's style: /// flex-direction: row; /// flex-wrap: wrap; /// </param> /// <returns>List of VisualElements made from the parsed text.</returns> public static List <VisualElement> RichTextToVisualElements(string htmlText, VisualElement targetContainer) { bool addError = false; string errorText = ""; try { XDocument.Parse("<content>" + htmlText + "</content>"); } catch (Exception e) { targetContainer.Clear(); errorText = e.Message; htmlText = ShowContentWithError(htmlText); addError = true; } List <VisualElement> elements = new List <VisualElement>(); targetContainer.Clear(); bool boldOn = false; // <b> sets this on </b> sets off bool italicOn = false; // <i> </i> bool forceWordWrap = false; bool linkOn = false; string linkURL = ""; bool firstLine = true; bool lastLineHadText = false; // start streaming text per word to elements while retaining current style for each word block string[] lines = htmlText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); foreach (string line in lines) { // Check if the line begins with whitespace and turn that into corresponding Label string initialWhiteSpaces = ""; foreach (char singleCharacter in line) { if (singleCharacter == ' ' || singleCharacter == '\t') { initialWhiteSpaces += singleCharacter; } else { break; } } string processedLine = PreProcessRichText(line); // Separate the line into words string[] words = processedLine.Split(new[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries); if (!lastLineHadText) { if (!firstLine) { elements.Add(AddParagraphToElement(targetContainer)); } if (initialWhiteSpaces.Length > 0) { WhiteSpaceLabel indentationLabel = new WhiteSpaceLabel(initialWhiteSpaces); targetContainer.Add(indentationLabel); elements.Add(indentationLabel); } } if (!firstLine && lastLineHadText) { elements.Add(AddLinebreakToElement(targetContainer)); lastLineHadText = false; if (initialWhiteSpaces.Length > 0) { WhiteSpaceLabel indentationLabel = new WhiteSpaceLabel(initialWhiteSpaces); targetContainer.Add(indentationLabel); elements.Add(indentationLabel); } } foreach (string word in words) { // Wrap every character instead of word in case of Chinese and Japanese // Note: override with <wordwrap>Force word wrapping here</wordwrap> if (word == "" || word == " " || word == " ") { continue; } lastLineHadText = true; string strippedWord = word; bool removeBold = false; bool removeItalic = false; bool addParagraph = false; bool removeLink = false; bool removeWordWrap = false; strippedWord = strippedWord.Trim(); if (strippedWord.Contains("<b>")) { strippedWord = strippedWord.Replace("<b>", ""); boldOn = true; } if (strippedWord.Contains("<i>")) { strippedWord = strippedWord.Replace("<i>", ""); italicOn = true; } if (strippedWord.Contains("<wordwrap>")) { strippedWord = strippedWord.Replace("<wordwrap>", ""); forceWordWrap = true; } if (strippedWord.Contains("<a")) { strippedWord = strippedWord.Replace("<a", ""); linkOn = true; } bool wrapCharacters = !forceWordWrap && NeedSymbolWrapping(word); if (linkOn && strippedWord.Contains("href=")) { strippedWord = strippedWord.Replace("href=", ""); int linkFrom = strippedWord.IndexOf("\"", StringComparison.Ordinal) + 1; int linkTo = strippedWord.LastIndexOf("\"", StringComparison.Ordinal); linkURL = strippedWord.Substring(linkFrom, linkTo - linkFrom); strippedWord = strippedWord.Substring(linkTo + 2, (strippedWord.Length - 2) - linkTo); strippedWord.Replace("\">", ""); } if (strippedWord.Contains("</a>")) { strippedWord = strippedWord.Replace("</a>", ""); removeLink = true; } if (strippedWord.Contains("<br/>")) { strippedWord = strippedWord.Replace("<br/>", ""); addParagraph = true; } if (strippedWord.Contains("</b>")) { strippedWord = strippedWord.Replace("</b>", ""); removeBold = true; } if (strippedWord.Contains("</i>")) { strippedWord = strippedWord.Replace("</i>", ""); removeItalic = true; } if (strippedWord.Contains("</wordwrap>")) { strippedWord = strippedWord.Replace("</wordwrap>", ""); removeWordWrap = true; } if (boldOn && strippedWord != "") { if (wrapCharacters) { foreach (char character in strippedWord) { AddLabel <BoldLabel>(character.ToString(), elements, targetContainer); } } else { AddLabel <BoldLabel>(strippedWord, elements, targetContainer); } } else if (italicOn && strippedWord != "") { if (wrapCharacters) { foreach (char character in strippedWord) { AddLabel <ItalicLabel>(character.ToString(), elements, targetContainer); } } else { AddLabel <ItalicLabel>(strippedWord, elements, targetContainer); } } else if (addParagraph) { elements.Add(AddParagraphToElement(targetContainer)); } else if (linkOn && !string.IsNullOrEmpty(linkURL)) { var label = new HyperlinkLabel { text = strippedWord, tooltip = linkURL }; label.RegisterCallback <MouseUpEvent, string>( (evt, linkurl) => { TutorialEditorUtils.OpenUrl(linkurl); }, linkURL ); targetContainer.Add(label); elements.Add(label); } else { if (strippedWord != "") { if (wrapCharacters) { foreach (char character in strippedWord) { AddLabel <TextLabel>(character.ToString(), elements, targetContainer); } } else { AddLabel <TextLabel>(strippedWord, elements, targetContainer); } } } if (removeBold) { boldOn = false; } if (removeItalic) { italicOn = false; } if (removeLink) { linkOn = false; linkURL = ""; } if (removeWordWrap) { forceWordWrap = false; } } firstLine = false; } if (addError) { var label = new ParseErrorLabel() { text = Localization.Tr("PARSE ERROR"), tooltip = Localization.Tr("Click here to see more information in the console.") }; label.RegisterCallback <MouseUpEvent>((e) => Debug.LogError(errorText)); targetContainer.Add(label); elements.Add(label); } return(elements); }