Note
<set property=”...”> ist verwirrend. müsste <set name=”...”> o.ä. heißen! jo! (stimmt)
Es gibt keine Entsprechung für define in JavaScript. (genau!) Wäre wünschenswert. (Warum? => Weil ich sonst in XML definen und in JS weiter damit arbeiten muss. Ein Ort wäre schöner.) var deklariert nur lokale Variablen. jo
Lookup im JavaScript hat sich im Vgl. zu MaongoCore verändert! (this-Parameter)
Section author: jo
Wie andere Programmierumgebungen bietet auch MAD die Möglichkeit, Variablen zu definieren und auf diese zuzugreifen. In MAD wird eine Variable mit define im Kontext des jeweiligen Widgets deklariert. Daneben dienen auch die MAD-Tags map und list und eine Reihe weiterer Tags dazu, komplexe Variablentypen auf Widgets zu definieren.
Im Kontext des Widgets, auf dem die entsprechende Variable deklariert wurde, steht diese direkt als Objektvariable zur Verfügung, auf die mit der Objektreferenz this zugegriffen werden kann:
<widget>
<define name="MyVar" />
<action>
trace(this.myVar);
</action>
</widget>
Optional kann die Objektreferenz this auch weggelassen werden.
Wie aber greift man auf Variablen zu, die an anderer Stelle deklariert wurden? Dafür gibt es übergreifend für Widgets, Properties und Variablen einen einheitlichen Weg in MAD: Das “Lookup”. Lookups dienen dazu, auf Objekte an beliebiger Stelle in der MAD-Anwendung zuzugreifen.
Der Namensraum eines Widgets setzt sich zusammen aus
Sobald wir ein beliebiges Widget in der MAD-Anwendung mit lookup adressiert haben, können wir auf alle diese im Namensraum des Widgets gespeicherten Informationen auf dieselbe Art und Weise zugreifen. (Ein weiterer Effekt ist, dass die Benennung von Child-Widgets und Variablen nicht mit den Widget-Properties und untereinander kollidieren darf!)
Manchmal ist es zudem wünschenswert, eine Widget-Eigenschaft dauerhaft an die Eigenschaft eines anderen Widgets oder an den Wert einer Variablen zu koppeln. Dieser Vorgang nennt sich Binding; er kann im MAD-XML mit dem bind-Tag ausgedrückt werden.
Lookups dienen dazu, Objekte (Widgets und ihre Properties, selbstdefinierte Variablen) innerhalb einer Maongo-Presentation zu adressieren. Soll ein Widget dieselbe Hintergrundfarbe erhalten wie ein zweites, so kann das so formuliert werden:
<widget name="W1" />
<widget name="W2">
<property name="BackgroundColor" lookup="W1.BackgroundColor" />
</widget>
Widgets in einem anderen Zweig der Presentation müssen von einem gemeinsamen Parent aus adressiert werden:
<presentation>
<widget name="W1">
<widget name="W2">
<widget name="W3" />
<widget name="X1">
<widget name="X2">
<property name="BackgroundColor" lookup="W3.BackgroundColor" />
</widget>
</widget>
</widget>
</widget>
</presentation>
Das Lookup findet W3 im NameSpace des gemeinsamen Parent-Widgets W2. Dieselbe Referenz lässt sich im Beispiel ausdrücken durch:
<property name="BackgroundColor" lookup="W3.BackgroundColor" />
(gemeinsamer Parent: W2)
<property name="BackgroundColor" lookup="W2.W3.BackgroundColor" />
(gemeinsamer Parent: W1)
<property name="BackgroundColor" lookup="W1.W2.W3.BackgroundColor" />
(gemeinsamer Parent: presentation)
Eine alternative Schreibweise zum lookup-Attribut ist, wie gewohnt das value-Attribut zu nutzen, aber ein @ voranzustellen:
<property name="BackgroundColor" value="@W3.BackgroundColor" />
Diese Schreibweise erlaubt Lookups auch an Stellen, an denen kein Lookup-Attribut möglich ist. Beispiel:
<tween from="@startValue" to="@endValue" />
funktioniert, wenn die beiden Variablen startValue und endValue über Lookup erreichbar sind. Diese Syntax ist für alle Attribute erlaubt.
Um ein Lookup durch die Hierarchie der Engines und Widgets zu machen, verwendet man die Funktion $(). Ein einfaches Lookup wie $(this,"myvar") würde zunächst in dem durch this referenzierten Widget nach der Property myvar suchen, danach im Parent des Widget und so weiter bis zur Presentation. Kann dei Property nicht gefunden werdn, wird eine Exception geworfen. dies lässt sich jedoch vermeiden, indem man einen Default-Wert mit angibt, der zurückgegeben wird wenn die Suche erfolglos bleibt. Der Default-Wert wird als dritter Parameter angegeben: $(this,"myvar","")
Komplexe Lookups
Lookups können verkettet werden, indem man mehrere Suchschlüssel mit Punkten verbindet: $(this,"foo.bar.boo") Die Property foo wird wie oben beschrieben in der Hierarchie gesucht, danach wird auf dem gefundenen Object eine Property bar angefragt und auf dem Resultierenden Objekt wiederum die Property boo.
TO BE CONTINUED
In Actions muss die Funktion lookup() (oder die Kurzschreibweise $()) benutzt werden, um das automatische Lookup hinauf zu den Widget-Parents zu erhalten. Ein direktes Referenzieren von Widgets (this.WidgetName oder WidgetName) ist nur möglich, wenn diese direkte Children des Widgets mit einer solchen Action sind:
<presentation>
<widget name="W1">
<widget name="W2">
<widget name="W3" />
<widget name="X1">
<widget type="Button" name="X2">
<action trigger="button-clicked">
BackgroundColor = $(this, "W3").BackgroundColor; // OK
BackgroundColor = $(this, "W3.BackgroundColor"); // OK
BackgroundColor = W3.BackgroundColor; // Fehler:
// Widget W3 not fond
BackgroundColor = X3.BackgroundColor; // OK
BackgroundColor = this.X3.BackgroundColor; // OK
</action>
<widget name="X3" />
</widget>
</widget>
</widget>
</widget>
</presentation>
Die beiden Schreibweisen
BackgroundColor = $(this, "W3").BackgroundColor; // OK
BackgroundColor = $(this, "W3.BackgroundColor"); // OK
haben dabei eine unterschiedliche Herangehensweise, erreichen im Beispiel aber dasselbe.
Eine Referenz auf ein Widget (statt eine Property) per Lookup abzufragen, macht beispielsweise dann Sinn, wenn mehrere Eigenschaften des Widgets abgefragt oder gesetzt werden sollen:
<action>
var w = $(this, "W3");
w.Shape = "R 100,100";
w.Location = w.Location + $$("Point", "10,20");
</action>
Die beiden Schreibweisen
var w = $(this, "W3");
var w = this.lookup("W3");
sind gleichbedeutend.
Defines sind auf einem Widget deklarierte Variablen.
Im Gegensatz zu Widget-Properties, die durch das Maongo-Framework vordefiniert sind und nicht vom Autor einer Applikation geändert werden können, bieten Defines die Möglichkeit, eigene Variablen zu definieren.
<define name="myLabelSpacing" type="Number" value="10"/>
Defines, Properties und auch benannte Childobjekte teilen sich einen Namespace. Das macht es erforderlich, dass auf demselben Widget derselbe Name nicht zweimal benutzt wird.
Zugriff auf eine oben definierte Variable:
<widget type="LabelSpace">
<property name="LabelSpacing" lookup="sLabelSpacing" />
</widget>
Mehrere Definitions können zu einer map zusammengefasst werden:
<map name="DesignSet1">
<define name="HeadlineTextColor" type="Color" value="0x4e4e4e"/>
<define name="LegendeTextColor" type="Color" value="0x4e4e4e"/>
<define name="HeadlineColorMarkShape" type="Shape" value="R 0 0"/>
</map>
Auf die Elemente der Map wird per Punktsyntax zugegriffen:
<widget>
<property name="ForegroundColor" lookup="DesignSet1.HeadlineTextColor"/>
</widget>
Die folgenden Datentypen werden - wie einfache Defines - auf einem Widget definiert und sind sodann über Lookup erreichbar:
Binding ist die dauerhafte Bindung einer Widget-Property an ein Datenobjekt. Ändert sich das Objekt, wird diese Änderung durch Binding auch an den Abnehmer weitergegeben.
Der bind-Tag nennt die gebundene property, das Datenobjekt (to) und die Objektvariable (key), deren Wert übernommen werden soll. Außerdem kann ein Defaultwert (default) angegeben werden, der greift, wenn das Datenobjekt oder der Zugriff auf key den Wert null ergibt:
<bind property="Text" to="Obj" key="ObjKey" default="MeinDefault" />
Das to-Attribut wird als Lookup interpretiert und kann enthalten:
Wird an ein Widget gebunden, so sind alle Widgets-Properties als key möglich.
Beispiel für andere Datentypen:
Binden an das dritte Listenelement in einer Liste antworten in einem DataObserver:
<bind property="AnswerText" to="quiz.DataObserver" key="antworten[2]"/>
Binden an den Key antwort2 einer Map:
<bind property="AnswerText" to="quiz.DataObserver.antwortMap"
key="antwort2"/>
<bind property="AnswerText" to="quiz.DataObserver"
key="antwortmap.antwort2"/>
Binden an ein Tabellenfeld (vgl. auch Data.Table in Data und Routen):
<bind property="AnswerText" to="quiz.DataObserver" key="Table[1][0]"/>
Binding in Chart-Elementen (beispielsweise des BarCharts): Hier können Eigenschaften der (Label-, Bar-) Templates an den Controller des Charts gebunden werden.
Zugriff mit arrangedObjects.current. Beispiel:
<widget type="BarChart" name="myChart">
<bind property="ControllerContent" to="ObservableData" key="Table"/>
<property name="ColumnNames" type="List" value="label,color,value"/>
<property name="BarValues" type="List[Number]"
value="arrangedObjects.lists.value"/>
<template name="Bar">
<bind property="BackgroundColor" to="myChart.Controller"
key="arrangedObjects.current.color"/>
</template>
<template name="Label">
<bind property="Text" to="myChart.Controller"
key="arrangedObjects.current.label"/>
</template>
</widget>
Binding wird im XML der MAD-Presentation definiert. Es gibt keine JavaScript-Entsprechung.
In JavaScript-Actions erfolgt die Zuweisung mit dem =-Operator.
XML-Actions können mit dem set-Tag Werte zuweisen:
<action>
<set property="PLabels.Visible" value="true" />
<set property="PLabels.Visible" lookup="Settings.isLabelVisible" />
</action>