Scripting:Lib prettyprint
Aus STNE-Wiki
Das Problem:
Die Script-Engine erlaubt einem einige echt komfortable und nette Dinge, aber irgendwann ist man an dem Punkt, wo Portale schön aussehen sollen. An diesem Punkt wird man merken, dass man viele Verrenkungen machen muss, damit man Text fett bekommt oder andere Sachen damit machen kann.
Diesem Problem habe ich nun hier Abhilfe geschaffen und die Library "PrettyPrint" eingeführt. Diesen Haufen an Funktionen schiebt man einfach bei sich in das Portal und steuert es so an, wie ganz unten im Beispiel angegeben. Nun kann man den Text, den man in die Funktion steckt schon fast so formatieren wie in einer IGM. Folgende Tags funktionieren: br, b, i, u, img, ul, li, small, font
Es wird derzeit noch geplant, [Spieler:] und solche Kurztags einzubauen, sowieso <a href="">hyperlinks</a>.
Library "PrettyPrint"
#UseInterface Web; /** * prettyPrint * Formatiert einen Text gemäß der in IGMs möglichen Funktionen * Gibt ein Objekt zurück, dass an das Response-Objekt gehangen werden kann. * Wichtig: hier wird nur valides XML-artiges zeug geparst! * HTML-durcheinander-Verdreckungen werden mit Fehlermeldung beantwortet. */ Function prettyPrint(text As String) As CHtmlControl { Var stack As New CObjectList(); // Stack für die Verschachtelung Var tmpObj As CObject; // Damit diese blöde Engine damit klar kommt. Var element As New Stackelement(); // Oberste Ebene definieren, macht die Schleife einfacher Var textStart As Integer = 0; Var nextTagAuf As Integer = text.IndexOf("<"); // Such den ersten HTML-Tag Var nextTagZu As Integer = text.IndexOf(">"); // Auch gleich die Position, wo es zu geht nextTagAuf = Math.Min(nextTagAuf, nextTagZu); // Das Minimum der beiden ist -1, wenn etwas nicht gefunden wurde, sonst nextTagAuf Var tag As String; While(nextTagAuf > 0) { If(textStart < nextTagAuf) { // Erstmal ist da Text, hinzufügen element.e.Add(text.Substring(textStart, nextTagAuf - textStart)); } // Den Tag isolieren tag = text.Substring(nextTagAuf + 1, nextTagZu - nextTagAuf - 1); // <dies hier> If(String.Compare(tag, 0, "/", 0, 1) = 0) { // Wenn das erste Zeichen innerhalb des Tags "/" ist --> Endtag // Wenn der Tag ein schließender Tag ist If(tag = element.tag) { // element.tag sieht schon gleich so aus: "/tag" tmpObj = stack.Item(stack.Count - 1); element = tmpObj; stack.RemoveAt(stack.Count - 1); // Letzten vom Stack poppen } Else { // Hier ist was kaputt im Quellcode element.e.Add("[Fehler: schließender Tag " + element.tag + " erwartet, " + tag + "gefunden. Abbruch.]"); Exit While; // While verlassen } } Elseif(is_singleTag(tag)) { // Wenns ein BR oder dergl ist, ersetzen element.e.Add(replaceSingleTag(tag)); } Else { // Ist scheinbar ein umschließender Tag, also verarbeiten tmpObj = element; stack.Add(tmpObj); // Alten aktuellsten Tag auf den Stack schieben element = replaceTag(tag, element); // Baut ein neues Stackelement mit element und endtag } // Lege die neuen Limits fest textStart = nextTagZu + 1; nextTagAuf = text.IndexOf("<", textStart); nextTagZu = text.IndexOf(">", textStart); nextTagAuf = Math.Min(nextTagAuf, nextTagZu); // Das Minimum der beiden ist -1, wenn etwas nicht gefunden wurde, sonst nextTagAuf } // Letzten Text hinzufügen if(textStart < text.Length) { // Wenn da noch Text ist element.e.Add(text.Substring(textStart,text.Length - textStart)); } Return element.e; // oberste Ebene zurückgeben } /** * replaceTag * Bekommt einen Tag und entscheidet dann, was für Formatierungen usw. es daraus macht. * Gibt ein HTML-Objekt zurück, in das der Inhalt reingeschoben werden kann */ Function replaceTag(text As String, element As Stackelement) As Stackelement { text = text.ToLower(); Var tagType As String = text; Var retHtmlPart As New CHtmlSpan(); Var newHtmlPart As New CHtmlSpan(); // Neues Element, in dem weiterer Inhalt reinkommt.- Wird manchmal gebraucht element.e.Add(retHtmlPart); If(text.IndexOf(" ") > 0) { // Checken, ob der Tag Parameter hat tagType = text.Substring(0, text.IndexOf(" ")); If(tagType = "font") { Var firstquote_index As Integer = text.IndexOf("color='"); Var secondquote_index As Integer = text.IndexOf("'", firstquote_index + 7); If(firstquote_index > 0 AND secondquote_index > 0) { retHtmlPart.Style.Add('color', text.Substring(firstquote_index + 7, secondquote_index - firstquote_index -7)); } Else { retHtmlPart.Add("[Fehler: Konnte das Font-Tag nicht korrekt Parsen. Quotes checken?]"); } } Else { // Unbekannter Tag, gib Fehlermeldung aber nerv nicht weiter. retHtmlPart.Add("[Fehler: unbekannter Tag - " + tagType + " - ignoriert.]"); } } Else { // Keine Parameter, erstmal diese Tags implementieren If(tagType = "b") { retHtmlPart.Style.Add('font-weight', 'bold'); } elseif(tagType = "u") { retHtmlPart.Style.Add('font-decoration', 'underline'); } elseif(tagType = "i") { retHtmlPart.Style.Add('font-style', 'italic'); } elseif(tagType = "small") { retHtmlPart.Style.Add('font-size', 'smaller'); } elseif(tagType = "ul") { // Einen UL-Tag simulieren, indem das SPAN drumherum manipuliert wird. retHtmlPart.Style.Add('display', 'block'); retHtmlPart.Style.Add('margin', '13px 39px'); retHtmlPart.Add(newHtmlPart); retHtmlPart = newHtmlPart; // Hier überschreiben, damit das neue Inhaltselement auch zurückgegeben wird.+ } elseif(tagType = "li") { // Einen LI-Tag simulieren, indem das SPAN drumherum manipuliert wird. retHtmlPart.Style.Add('display', 'list-item'); retHtmlPart.Style.Add('list-style-image', 'url(http://game.stne.net/t/1/s/li.gif)'); } Else { // Unbekannter Tag, gib Fehlermeldung aber nerv nicht weiter. retHtmlPart.Add("[Fehler: unbekannter Tag - " + tagType + " - ignoriert.]"); } } // Jetzt sollten auf dem retHtmlPart alle passenden Formatierungen usw. drauf sein. Gib mal zurück. Return New Stackelement(retHtmlPart, "/" + tagType); } /** * replaceSingleTag * Ersetzt Tags, die man nicht schließen muss direkt und gibt ein CHtmlControl zurück. */ Function replaceSingleTag(text As String) As CHtmlControl { text = text.ToLower(); text = text.Replace("""", "'"); // Damit ich nur nach einer Sorte suchen muss Var retHtmlPart As New CHtmlSpan(); If(text.StartsWith("img")) { Var firstquote_index As Integer = text.IndexOf("src='"); Var secondquote_index As Integer = text.IndexOf("'", firstquote_index + 5); If(firstquote_index > 0 AND secondquote_index > 0) { Return New CHtmlImage(text.Substring(firstquote_index + 5, secondquote_index - firstquote_index-5)); } Else { retHtmlPart.Add("[Fehler: Konnte das IMG-Tag nicht korrekt Parsen. Quotes checken?]"); } } Elseif(text = "br") { Return New CHtmlBreak(); } Else { retHtmlPart.Add("[Fehler: Unbekanntes Tag - " + text + " ]"); } Return retHtmlPart; } /** * is_singleTag * Checkt, ob ein Tag mit einem als single-Tag bekannten Tag anfängt. */ Var singleTags[] As String = {"br", "img"}; // Enthält alle einfachen Tags, die keine Ebenen aufspannen Function is_singleTag(text As String) As Boolean { Var walkstring As String; For(Each walkstring In singleTags) { If(String.Compare(walkstring, 0, text, 0, walkstring.Length) = 0) { Return true; } } Return false; } /* Ist eine komplexe Datenstruktur, damit mehr als ein Ding aufm Stack liegen kann */ Class Stackelement { Var e As CHtmlControl; Var tag As String; Function New() { This.e = New CHtmlControl(); This.tag = "/none"; } Function New(e As CHtmlControl, tag As String) { This.e = e; This.tag = tag; } } Var test As String = "hier ist ein <b>fetter<font color='red'> roter </font><u>unterstrichener</u> <i>Testtext</i></b>"; Response.Add(prettyPrint(test));