5. Prototype: Ajax.Request
Funktion
Gewöhnlicher Ajax Request
Wichtige Optionen
asynchronous = true: (A)synchrone Anfrage
contentType: Ändern wenn man z.B. XML senden will
encoding = UTF8: Falls es mal Probleme mit Kodierung gibt
parameters: Parameter im URL oder JSON Format
Wichtige Callbacks
onFailure: Wird bei HTTP Errors geworfen 40x – 50x
onSuccess: Kommt zum Zug bei 20x Statuscodes
6. Prototype: Ajax.Request
JSON Antwortobjekt
var data = {};
data.getres = 1001;
data.language = SV_LANG_DE;
data.isIE = true;
new Ajax.Request('/pfad/zum/script/?id=685', {
parameters : data,
method : 'post',
onSuccess: function(response) {
var json = response.responseText.evalJSON();
alert('Antwort: ' + json.message);
}
});
7. Prototype: Ajax.Request
Synchroner Request
var data = {};
data.getres = 1001;
data.language = SV_LANG_DE;
data.isIE = true;
var myRequest = new Ajax.Request('/service/class/getres/', {
parameters : data,
method : 'post',
asynchronous : false
});
alert(myRequest.transport.responseText);
8. Prototype: Ajax.Response
Funktion
Antwortobjekt eines Ajax.Request
Wichtige Properties
responseText: Text der Ajax Antwort
responseXML: XMLDOM Objekt, wenn application/xml Header
responseJSON: JS Objekt, wenn application/json Header
transport: Zugriff auf das Native XmlHttpRequest Objekt
9. Prototype: Ajax.Updater
Funktion
Updatet einen Container, erbt von Ajax.Request
Und wozu ist das gut?
- Vereinfachung eines oft verwendeten Use-Case
- Verwendet das verhalten von Element.update()
Zusätzliche Properties
evalScripts = false: Führt Code in <script> Tags aus
insertion: Mögliche Werte: top, bottom, before, after
-> Mehr dazu bei den Element Methoden
11. Prototype: Ajax.PeriodicalUpdater
Funktion
Wie Updater, führt sich aber periodisch selbst wieder aus
Wichtige Optionen
frequency = 2: Warten zwischen Abfragen
decay = 1: Erhöht die Rate von frequency, wobei der übergebene Wert
ein Multiplikator ist. 1 Hat daher keine Wirkung, 2 z.B. verdoppelt den
Wert von frequency. Wenn Resultat !=, wird frequency zurückgesetzt.
Nutzen
- Sehr wenig Code nötig für automatische Updater
- Spart Ressourcen durch den decay Parameter
13. Kurze Einführung: JSON
Wer ist Jason?
Die Javascript Object Notation
Wozu wird es verwendet?
- Objektorientiertes Javascript
- Interner Datenaustausch (z.B. Funktionsparameter)
- Externer Datenaustausch (z.B. Ajax)
Syntax
Properties, Arrays, Objektarrays, Funktionen…
… mit relativ wenig Zeichen (Leichtgewichtig)
14. Kurze Einführung: JSON
Einfache Daten und Arrays
var object = {
message : 'this is json',
really : true,
howmany : 1337,
inner : {
value : 'inneres objekt',
great : false
},
array : [ 1,2,3,4,5,6,7,8 ],
strings : [ 'hello', 'world' ]
};
16. Kurze Einführung: JSON
Funktionen (Dazu mehr unter „Klassen“)
var Calculator = {
Add : function(param1,param2) {
return(param1 + param2);
},
Subtract: function(param1,param2) {
return(param1 – param2);
},
};
17. Prototype: $... Die Funktion
Funktion
Alias für document.getElementById und mehr
Wie mehr?
$(‘eleID‘) gibt ein Element zurück
$(‘eleID‘,‘inputID‘,‘textID‘) gibt ein Array zurück
DOM der Elemente wird erweitert (Dazu gleich mehr)
Nutzen
Effizienter / besser lesbarer Code
18. Prototype: $... Die Funktion
Typischer Code einer Validierungsroutine
// Validierbares Element holen
var ele = document.getElementById('eleID');
// Array von Werten für For basteln
var some = [];
some[0] = document.getElementById('eleID');
some[1] = document.getElementById('inputID');
some[2] = document.getElementById('textID');
// Error Message Divs ausblenden
document.getElementById('errorMessage').style.display = 'none';
document.getElementById('errorDiv').style.display = 'none';
19. Prototype: $... Die Funktion
Typischer Code gleicher Code mit Prototype
// Validierbares Element holen
var ele = $('eleID');
// Array von Werten für For-Schlaufe
var some = $('eleID','inputID','textID');
// Mit „hide“ Funktion auf allen Elementen, Divs ausblenden
$('errorMessage','errorDiv').invoke('hide');
Anmerkung: Die hide() und show() Methode ist nur eine der
zahlreichen DOM Erweiterungen die jedes Element bekommt
20. Prototype: Geht‘s noch schneller?
Eine Nanosekunde effizienter
Ja, mit der $F() Methode
Formularwert holen
Erwartet eine ID als Wert, und gibt den Wert des dahinter
liegenden Formularfeldes mit der getValue() Methode zurück.
$(‘example‘).getValue()
Gleich wie .value Property ausser bei Multiselect,
da kommt immer ein Array zurück
21. Prototype: Geht‘s noch schneller?
Schnell ein Formular speichern
var Assistant = Class.create();
Assistant.prototype = {
Save : function() {
new Ajax.Request('/admin/content/?id=324',
method : 'post',
parameters : {
'Name' : $F('Name'),
'Firstname' : $F('Firstname'),
'Email' : $F('Email')
}
);
}
};
22. Prototype: Klassen
Objektbasiert?
Orientiert, wir können Abstrakt.
Wie kann man vorgehen
- Klasse leer erstellen und Body erweitern
- Klasse direkt vollständig ausprogrammieren
Eigenheiten
Klassendefinitionen sind zur Laufzeit erweiterbar (Für alle Instanzen)
Statische Properties kennt Javascript nicht
Public, Private, Protected? Umsetzbar, aber kein Bestandteil
23. Prototype: Klassen
Erstellen und erweitern…
var Assistant = Class.create();
Assistant.prototype = {
// Konstruktor
initialize : function() {
},
// Speicherfunktion
Save : function() {
alert('data saved');
}
};
24. Prototype: Klassen
…oder direkt ausprogrammieren
var Assistant = Class.create({
// Konstruktor
initialize : function(id) {
// Hier sind meist window.onload/dom:loaded Events
},
// Speicherfunktion
Save : function() {
alert('data saved');
}
});
25. Prototype: Klassen
Erben des einer Klasse
var BetterAssistant = Class.create(Assistant,{
// Konstruktor
initialize : function($super,id) {
// Parent Methode aufrufen, geht bei allen überschriebenen
$super(id);
},
// Speicherfunktion überschreiben
Save : function($super) {
this.Validate(); // Erst validieren
$super();
}
});
26. Prototype: Klassen
Methoden überschreiben (Clean way)
BetterAssistant.addMethods({
// Speichern geht noch besser
Save : function($super) {
// Validieren und speichern
$super();
// Meldung an User geben
this.Notify();
},
// Meldung an User
Notify : function() {
$('message').update('Daten gespeichert!');
$('message').show();
}
});
27. Prototype: Element Erweiterungen
Wie bekomme ich die Erweiterungen
Mit Element.method() oder $(‘someElement‘).method()
Einige Beispiele
- Element.update(): Ein Block Element verändern
- Element.setStyle()/getStyle(): CSS, Browserkompatibel
- Element.show()/hide()/toggle(): Anstatt direkt CSS zu modifizieren
- Element.absolutize()/relativize(): Element Positionstyp ändern
- Element.removeClassName()/addClassName(): Sprechend
- Und 76 weitere Methoden
Welche wir hier finden
Gibt es hier: http://api.prototypejs.org/dom/element/
28. Prototype: Element Erweiterungen
Element.update() - Beispiel
var html = '<p>Gleich passiert was<p>' +
'<script type="text/javascript">' +
' alert("sehen sie?");' +
'</script>';
$('message').update(html);
29. Prototype: Element Erweiterungen
Anwendung der toString() Methode mit Element.Update()
var Fruit = Class.create({
initialize : function(name) {
this.Name = name;
}
toString: function() {
return('Hey ' + this.Name + '! I'm an orange.');
}
});
var apple = new Fruit('apple');
$('fruits').update(apple);
$('fruits').innerHTML;
30. Prototype: Element Erweiterungen
Klassen hinzufügen oder entfernen
<div id="msg" class="float left invisible"> </div>
<script type="text/javascript">
$('msg').addClassName('visible','error');
$('msg').removeClassName('invisible');
// -> float left visible error
// -> toggleClassName(cssClass)
</script>
31. Prototype: Element Erweiterungen
XML Arbeit vereinfachen
<ul id="apples">
<li>Mutsu</li>
</ul>
<script type="text/javascript">
$('apples').firstChild.innerHTML;
// -> undefined
$('apples').cleanWhitespace();
$('apples').firstChild.innerHTML;
// -> 'Mutsu'
</script>
32. Prototype: Element Erweiterungen
Elementinhalt Erweitern oder umranden
// Paragraph in ein Element einbauen
$('element').insert('<p>HTML to append</p>');
// Fügt über den Paragraphen ein Bild ein
$('element').insert({
top: Element('img', {src: 'logo.png'})
});
// Fügt vor und nach dem Element ein HR ein
$('element').insert({
before: '<hr>',
after: '<hr>'
});
34. Prototype: Element.Layout
Wozu
Verschiedene Grössen/Abstände eines Elements lesen
Vorteile
- Geht auch, wenn alles in CSS definiert ist
- Umgeht die Tendenz, dass Browser inkorrekte Werte liefern
- Umgeht den Quirksmodus, welcher meist gar nichts liefert
- Umgeht die Schwierigkeit mit unsichtbaren Elementen
Vorsicht
Da Resourcenintensiv sind die Werte gecached!
35. Prototype: Element.Layout
Instanz des Layout Objekts holen
// Mit der Element Methode verwenden
layout = new Element.Layout(element);
// Als Instanzmethode eines Elements
layout = $('element').getLayout();
// Wert lesen, CSS Version ausgeben
var pl = layout.get('padding-left');
var css = layout.toCSS();
37. Prototype: Event Objekt
Events: Ein geordnetes Chaos
Error 10050, too many nerves wasted
Vorteile
- Einfache Eventregistration
- Einheitliche KEY_ Konstanten
- Einheitliches Event-Daten Objekt
- Diverse Helper Methoden
39. Prototype: Event Objekt
Standard Event registrieren
function SomeFunction(event) {
// Event ist immer "event", auch im IE!
// Dieses Event Objekt ist ebenfalls erweitert
}
Event.observe(window, 'load', SomeFunction);
$(window).observe('load', SomeFunction);
$('element').observe('click', SomeOtherFunction);
40. Prototype: Event Objekt
Events löschen
// Genau einen Event löschen, Handler muss übergeben werden
Element.stopObserving(element,'click',SomeFunction);
$('element').stopObserving('click',SomeFunction);
// Alle Events eines Typs löschen (Keinen Handler übergeben)
Element.stopObserving(element,'blur');
$('element').stopObserving('blur');
// Oder komplett alle Event entfernen
Element.stopObserving(element);
$('element').stopObserving();
41. Prototype: Event Objekt
Intelligente Events (Mit Daten)
function SomeFunction(event,param) {
if (event.keyCode == KEY_RETURN) {
alert('daten sind: ' + param);
}
}
$(window).observe('keydown',function(event) {
SomeFunction(event,$('content').getValue());
});
42. Prototype: Event Objekt
Do it the OOP way
var AssistantClass = Class.create({
initialize : function() {
this.Input = $('myInput');
this.WeWillUseThatLater = 'Hello World';
this.Input.observe('blur',this.Validate.bind(this));
},
Validate : function(event) {
// Das Event wird im Objekt Kontext ausgeführt
alert(this.WeWillUseThatLater);
}
});
43. Prototype: Event Extensions
Erweiterungen am Event Objekt
Alle registrierten Events liefern ein modifiziertes ‚event‘ zurück
Beispiele
- event.element(): Das Element auf dem der Event ausgeführt wurde
- event.findElement(): Findet Objekte innerhalb des Event Elements
- event.pointerX/Y(): Für Maus Events, immer absoluter Pixelwert!
- event.is[Left|Right|Middle]Click(): Wie genau wurde geklickt?
44. Prototype: CSS Selektoren
Exkursion zu $$
Damit holen wir alles was mit CSS zu holen ist
Syntax Beispiele
$$(‘div.myclass‘): Alle Divs mit der Klasse myclass
$$(‘.myclass‘): Alle Elemente mit der Klasse myclass
$$(‘.myclass .error‘): Alle Elemente mit myclass und error
$$(‘#mydiv‘): Element mit der ID mydiv
$$(‘#mydiv input[type=checkbox]‘): Alle Checkboxen in #mydiv
$$(‘:checked‘): Alle ausgewählten Elemente. Weitere, :disabled :enabled
$$(‘#mytable tr:nth-child(even)‘): Alle geraden Zeilen von #mytable
…Und alles weitere was bis und mit CSS3 möglich ist!
46. Prototype: Event.Handler
Zurück bei den Events
Diese arbeiten auf Wunsch auch mit Selektoren
Wozu ein weiterer Handler
- Der Event.Handler delegiert an Unterelemente
- Delegation des Callback erfolgt über CSS Selektoren
47. Prototype: Event.Handler
Einen Event Handler definieren
function SaveForm(event) {
// Formular per Prototype Ajax Post speichern
event.element.request();
}
// Speichern aller "saveable" Forms, beim verlassen der Seite
observer = new Event.Handler(
window, // Auf das Window hören
'unload', // Wenn es verlassen wird
'form.saveable', // Alle Forms mit "saveable" Klasse
SaveForm // SaveForm Methode ausführen
);
observer.start();
48. Prototype: Der Form Namespace
Auch die Forms sind erweitert
…Sofern diese mit der $-Funktion geladen werden
Einige Methoden im Überblick
- $(‘frm‘).disable(): Deaktiviert alle Formularelemente
- $(‘frm‘).enable(): Aktiviert alle Formularelemente
- $(‘frm‘).getElements(): Array aller Formularelemente
- $(‘frm‘).getInputs(type): Gibt z.B. alle Checkboxen eines Forms zurück
- $(‘frm‘).request(): Formular per Ajax Posten/Requesten
- $(‘frm‘).serialize(true): Formular Daten als JSON oder Query holen
49. Prototype: Der Form Namespace
Und sonst?
…nur einige Convenience Methoden
Form.Observer
- Trackt Änderungen in einem Formular
- Kann für generische Validation verwendet werden
Form.Element.Observer
- Gleich wie Form.Observer, auf ein einzelnes Element
- Explizite automatische Validation eines Feldes
50. Prototype: Der Form Namespace
Beispiele von Form(.Element).Observer
// Formular alle 500ms prüfen
new Form.Observer(myFrm, 0.5, GenericValidation);
// Formularelement alle 300ms prüfen
new Form.Element.Observer(myEle, 0.3, ExplicitValidation);
51. Prototype: Selector
Noch mehr CSS Selektoren
Mit dem ‚Selector‘ kann nach Elementen gesucht werden
Ist doch das gleiche wie $$?
- Genau, plus eine spezielle Funktion
- .match() gibt an, ob ein Element dem Selektor entspricht
Und sonst?
Das Objekt ist schlecht dokumentiert, kann aber wahrscheinlich
effektiv nicht viel mehr als ein Aufruf der $$-Funktion
52. Prototype: Selector
Anwendung des Selector
// <div id="firstFormContainer" class="FormContainer" />
// <div id="anotherFormContainer" class="FormContainer" />
// <div id="aFormContainer" />
var Sel = new Selector('div.FormContainer');
Sel.match($('someOtherDiv')); // false
Sel.match($('firstFormContainer')); // true
// Beide obigen Container holen
var cont1 = Sel.findElements();
// Oder wenn man es in einem bestimmten div suchen will
var cont2 = Sel.findElements($('containsDivs'));
53. Prototype: document
Erweiterungen des document Objekts
Es wird das registrieren/abfeuern von Events ermöglicht mit den
bekannten Methoden „observe“ und „stopObserving“
Der viewport (was im Browser sichtbar ist)
document.viewport.getHeight(): Höhe des sichtbaren Bereichs
document.viewport.getWidth(): Breite des sichtbaren Bereichs
document.viewport.getScrollOffsets(): left/top Offset des Scrollbalken
54. Prototype: $A
Arrays casten
Hiermit kann man so gut wie alles zu einem Array casten
Warum? Weil man…
…oft eine NodeList oder eine HTMLCollection bekommt und
diese nicht mit Prototype Features erweitert werden (können)
Was kann ein Prototype Array
Basiert auf „Enumerable“ und bietet damit 44 neue Methoden
zum iterieren, suchen und arbeiten mit Arrays
55. Prototype: $A
Beispiel inkl. each() Funktion
var ps = $A(document.getElementsByTagName('p'));
// Nun können wir mit Each jedes Element durchgehen
ps.each(function(item) {
alert(item.innerHTML);
});
// Oder eine bestehende Funktion darauf ausführen
ps.each(Element.hide);
56. Prototype: Array Funktionen
Prüfen ob alle Elemente einem Wert entsprechen
// -> true (Ein leeres Array hat keine falschen Werte)
[].all();
// -> true (Alle Werte in 1 bis 5 sind true)
$R(1, 5).all();
// -> false (0 gilt als false)
[0, 1, 2].all();
// -> false (Auf 9 kommt false zurück)
[9, 10, 15].all(function(n) { return n >= 10; });
// Selbe Funktion mit "any", gibt jedoch schon bei
// einem gültigen Wert true zurück
57. Prototype: Array Funktionen
Funktionsauswertung aller Elemente als Array
// Gibt folgendes Array ['H', 'H', 'G']
['Hitch', "Hiker's", 'Guide'].collect(function(s) {
return(s.charAt(0).toUpperCase());
});
// Gibt alle Quadratzahlen von 1 bis 5 [1, 4, 9, 16, 25]
$R(1,5).collect(function(n) {
return(n * n);
});
58. Prototype: Array Funktionen
Geprüfte Werte zurück bekommen
// Wir wenden auf jedes Objekt Object.IsString an
// Alle Werte die "true" ergeben kommen als Array zurück
[1, 'two', 3, 'four', 5].filter(Object.isString);
// Resultiert daher in ['two','four']
// Wir wenden auf jedes Objekt Object.IsString an
// Alle Werte die "false" ergeben kommen als Array zurück
[1, 'two', 3, 'four', 5].reject(Object.isString);
// Resultiert daher in [1,2,3]
// Das geht auch mit eigenen Funktionen
[1, 'two', 3, 'four', 5].filter(function(item)) {
// Hier item prüfen und true/false zurückgeben
});
59. Prototype: Array Funktionen
Das selbe noch mit Regex
// Alle Strings mit Doppelbuchstaben finden
['hello', 'world', 'this', 'is', 'cool'].grep(/(.)1/);
// Ergibt folgendes Array: ['hello', 'cool']
// Innerhalb 1 bis 30 alle Zahlen die mit 0 oder 5
// enden holen und eins davon abziehen
$R(1, 30).grep(/[05]$/, function(n) { return(n - 1); });
// Ergibt folgendes Array: [4, 9, 14, 19, 24, 29]
60. Prototype: Array Funktionen
Zahl, String oder Objekt in einem Array finden
// Gibt true, da 10 im Range 1 bis 15 vorkommt
$R(1, 15).include(10);
// Gibt false, da Gross-/Kleinschreibung beachtet wird
['hello', 'world'].include('HELLO');
// Gibt true, da hello 1:1 so vorkommt
['hello', 'world'].include('hello');
// Gibt true, da 3 == '3' in JS true ergibt
[1, 2, '3', '4', '5'].include(3);
61. Prototype: Array Funktionen
Objektmethoden aufrufen
// Einfacher Aufruf, der Arraywert ist immer der 1. Parameter
// Resultat ergibt: ['HELLO', 'WORLD']
['hello', 'world'].invoke('toUpperCase');
// Parameter folgen dem Methodennamen
// Substring calls ergeben: ['hel', 'wor']
['hello', 'world'].invoke('substring', 0, 3);
// Stoppt den 'change' event auf allen Input Feldern
$$('input').invoke('stopObserving', 'change');
63. Prototype: Array Funktionen
Feldwerte lesen und als Array zurückbekommen
// Stringlänge aller Objekte herausfinden
// Gibt folgendes Array: [5, 5, 4, 2, 4]
['hello', 'world', 'this', 'is', 'nice'].pluck('length');
// checked Feld aller Checkboxen lesen
var checks = $$('input[type=checkbox]');
var values = checks.pluck('checked')
// Alles umkehren
for (i = 0;i < checks.length;i++) {
checks[i].checked = !values[i];
}
64. Prototype: Array Funktionen
Array Sortieren
// Nach Stringlänge sortieren
// Ergibt: ['is', 'nice', 'this', 'world', 'hello']
['hello', 'world', 'this', 'is', 'nice'].sortBy(function(s) {
return(s.length);
});
// Objekte mit internem Sortierwert sortieren
MyObjectArray.sortBy(function(s) {
// Mit „this“ könnte man hier auf das ganze Array zugreifen
return(s.GetInternalOrder());
});
65. Prototype: Array Funktionen
Zusammenführen von Arrays
var firstNames = ['Jane', 'Nitin'];
var lastNames = ['Doe', 'Patel'];
var ages = [23, 41];
// Ergibt: [['Jane', 'Doe'], ['Nitin', 'Patel']]
firstNames.zip(lastNames);
// Ergibt [['Jane', 'Doe', 23], ['Nitin', 'Patel', 41]]
firstNames.zip(lastNames, ages);
// Oder wir wenden eine Funktion an, um das
// resultierende Array zu beeinflussen
// Ergibt: ['Jane Doe is 23', 'Nitin Patel is 41']
firstNames.zip(lastNames, ages, function(tuple) {
return(tuple[0] + ' ' + tuple[1] + ' is ' + tuple[2]);
});
// Man kann so z.B. Objekte aus Arrays kreieren
66. Prototype: $H / Hash
Was ist ein Hash?
Äquivalent zu „Dictionary“ in ASP oder .NET
Zusammenfassen von Daten
Kann als alternative zu Objekten verwendet werden. Ein Hash
Hat zudem einige Hilfreiche Funktionen
Methoden des Hash
toQueryString(): Falls Post nicht möglich, Daten als Querystring
toJSON()/toObject(): Liefern beide ein Objekt für z.B. Ajax Posts
set()/get()/unset(): Kommen gleich im Codebeispiel
update(): Erweitert den Hash mit dem übergebenen Objekt
keys()/values(): Liefert entsprechende Arrays
67. Prototype: $H / Hash
Anwendung des Hash
var h = $H({name: 'Michael', age: 21, country: 'England'});
// Ist das selbe wie...
var h = new Hash({name: 'Michael', age: 21, country: 'England'});
// Mit "get" erhält man den entsprechenden Wert
var country = h.get('country');
// Mit "set" kann man einen neue Wert setzen oder bearbeiten
h.set('name','John');
h.set('lastname','Doe');
// Iterieren kann man auch hier mit der "each" Methode
h.each(function(pair,index) {
alert('on ' + index + ': ' + pair.key + '=' + pair.value);
});
68. Prototype: $R / ObjectRange
Was ist ein ObjectRange?
Ein Objekt, welches einen Range (Array) kreiert
Wozu kann man es verwenden?
Man weiss es nicht. z.B. um ein Zahle-n oder Buchstabenarray zu
erzeugen, welches man dann irgendwie weiter verwenden kann
Was kann der Range
Als erstes: Alles was eine Enumeration auch kann
include(): Überschreibt include() der Enumeration
end/start: Properties für das beginnende und endende Objekt
69. Prototype: $R / ObjectRange
Anwendung des Range
// Range von 1 - 10
$R(0, 10)
// Range von String aa bis ah: aa ab ac ad af ag ah
$R('aa', 'ah')
// Range von 1 bis 10 ohne letzte Zahl (Also 1 bis 9)
$R(0, 10, true).include(10)
// Range gibt eine Enumeration, man kann also each verwenden
$R(0, 10, true).each(function(value) {
alert(value);
});
70. Prototype: $R / ObjectRange
Anwendung des Range mit eigenem Objekt
var BigCounter = Class.create({
initialize : function(value) {
this.Value = value
},
succ : function() {
return(this.Value + 750);
}
});
// Range mit BigCountern: 1500, 2250 ... 6000, 6750
$R(new BigCounter(1500),new BigCounter(6750));
71. Prototype: Funktionserweiterungen
Methoden für Funktionen
Prototype erweitert die Funktionsreferenzen automatisch
Hier kommt Magie zum Einsatz
Das gibt‘s sonst nirgendwo: Deferier- und delaybare Aufrufe,
Parametererweiterungen und Methodisierung
73. Prototype: Funktionserweiterungen
Kontext binden (Wichtig für OOP implementationen)
var AlertOnClick = Class.create({
initialize: function(msg) {
this.msg = msg;
// Klappt nicht, da Events „kontextlos“ sind
$('submit').observe('click', this.Click);
// Klappt, da der Objektkontext übergeben wird
$('submit').observe('click', this.Click.bind(this));
},
Click: function(event) {
event.stop();
$('message').update(this.msg).show();
}
});
74. Prototype: Funktionserweiterungen
Parametererweiterung (Do it the indian way)
function showArgs() {
// 'arguments' ist ein Array aller Paremter
alert($A(arguments).join(', '));
}
// Liste der Parameter ausgeben: '1, 2, 3'
showArgs(1,2,3);
// Mit Curry eine Funktionskopie erstellen, welche
// Die Funktion mit Default 1,2,3 aufruft
var showExtended = showArgs.curry(1,2,3);
// Diese mit weitere Parametern aufrufen: '1, 2, 3, a, b'
showExtended('a','b');
75. Prototype: Funktionserweiterungen
Deferieren (Verschieben ans Ende)
// Funktionen die mit "defer" aufgerufen werden, wird der
// Interpreter erst Ausführen wenn er nichts mehr zu tun hat
function showMsg(msg) {
alert(msg);
}
showMsg("One"); // Normaler Aufruf
showMsg.defer("Two"); // Verschobener Aufruf
showMsg("Three"); // Normaler Aufruf
// Output: One, Three, Two
76. Prototype: Funktionserweiterungen
Klassisches Beispiel (defer Methode)
// Klassiker, den man immer wieder sieht:
var Assistant = Class.create({
function : initialize() {},
// Funktion die ein Control per Effekt einblendet
function : ShowInput(ele) {
$(ele).appear({ duration: 3.0 });
// 1. Nicht im Objekt Kontext, 2. Unschön
setTimeout('MyObject.DoSomething()',3000);
},
// Funktion die nach dem Effekt aufgerufen werden soll
function : DoSomething() {}
});
77. Prototype: Funktionserweiterungen
Klassisches Beispiel (defer Methode)
var Assistant = Class.create({
function : initialize() {},
// Funktion die ein Control per Effekt einblendet
function : ShowInput(ele) {
$(ele).appear({ duration: 3.0 });
// 1. Im Objektkontext, 2. Optimal, da am Funktionsende.
// Wird ausgeführt wenn der Interpreter idle ist, und das
// ist er zufälligerweise erst, wenn der Effekt beendet ist
this.DoSomething.defer();
},
// Funktion die nach dem Effekt aufgerufen werden soll
function : DoSomething() {}
});
78. Prototype: Funktionserweiterungen
Delayen (Verschieben auf fixen Zeitpunkt)
// Ist defer nicht sicher genug, geht es immer noch so
var Assistant = Class.create({
function : initialize() {},
// Funktion die ein Control per Effekt einblendet
function : ShowInput(ele) {
$(ele).appear({ duration: 3.0 });
// Funktonsaufruf gleich wie Effekt delayen
this.DoSomething.delay(3.0);
},
// Funktion die nach dem Effekt aufgerufen werden soll
function : DoSomething() {}
});
79. Prototype: Funktionserweiterungen
Delayen mit Parameter
var Assistant = Class.create({
function : initialize() {},
// Funktion die ein Control per Effekt einblendet
function : ShowInput(ele) {
$(ele).appear({ duration: 3.0 });
// Erst das Timeout, dann die Parameter
this.DoSomething.delay(3.0, 'hello', 'world');
},
// Funktion die nach dem Effekt aufgerufen werden soll
function : DoSomething(param1, param2) {}
});
80. Prototype: Funktionserweiterungen
Methodisierung (Statische Funktionen an Objekte binden)
// Funktion, die auf ein Objekt, das "name" Prop. setzt
function setName(target, name) {
target.name = name;
}
// Kann man z.B. so ohne Kontext verwenden
object = {};
setName(object, 'Fred');
// Man kann aber auch das Objekt "Methodisieren"
obj.setName = setName.methodize();
// "target" ist nun "this" und wird direkt angewendet
obj.setName('Barney');
// Prototype setzt dies für fast alle Funktionen ein
81. Prototype: Funktionserweiterungen
Bestehende Methoden erweitern
// capitalize Funktion mit einem Parameter erweitern
String.prototype.capitalize = String.prototype.capitalize.wrap(
function(OriginalMethod, eachWord) {
if (eachWord && this.include(" ")) {
// Wenn Parameter (true), jedes Wort kapitalisieren
return(this.split(" ").invoke("capitalize").join(" "));
} else {
// Oder die bisherige Standarmethode anwenden
return(OriginalMethod());
}
}
);
"hello world".capitalize(); // "Hello world"
"hello world".capitalize(true); // "Hello World"
82. Prototype: Number Methoden
Erweiterung von „Math“
Number vereint Math und mehr
Beispiele
- Fügt für jede Zahl abs(), ceil, floor(), und round() hinzu
- toColorPart(): Gibt die Hex Version einer Zahl zurück
- toPaddedString(n): Gibt den Zahlenwert mit führenden Nullen zurück
83. Prototype: The Object Object
Wer profitiert davon
Alle primitiven Datentypen, alle Objekte, selbst Eigenbauten
Hilfreiche Funktionen
- clone(): Erzeugt eine Shallow Copy. Deep Copy umsetzbar
- extend(): Erweitert ein bestehendes Objekt
- inspect(): Gibt Debug-Informationen des Objekts aus
- Anwendbar statisch oder im Objektkontext als Methode
Validierung
Validierung (Nur statisch) kann nicht schaden: isArray(), isElement(),
isFunction(), isHash(), isNumber(), isString(), isUndefined().
84. Prototype: PeriodicalExecuter
Warum nicht setInterval?
Weil die Ausführungszeit dort nicht eingerechnet ist
Und sonst?
- Die stop() Methode haltet den Executer an
- Geeigneter für OOP da Kontextübergabe möglich
85. Prototype: PeriodicalExecuter
Simpler Aufruf
// Übergabe einer direkten Funktion
new PeriodicalExecuter(function(executer) {
if (!confirm('Hey bananas, what'cha doin'?')) {
executer.stop();
}
}, 5.0);
// Verwendung innerhalb eines Objekts
this.Exec = new PeriodicalExecuter(this.DoIt.bind(this),5.0);
// Funktion DoIt als Beispiel
DoIt : function(pe) {
pe.stop(); // Übergebenen Executer stoppen
this.Exec.stop(); // Oder die Objektreferenz, da Kontext
}
86. Prototype: Prototype.Browser
Der Prototype Namespace
Bietet nicht viel gescheites ausser „Browser“
Ein Set von Booleans
Wenns mal doch nicht klappt: Prototype.Browser
.IE: Check ob IE vorhanden (Zudem: IE6, IE7, IE8)
.Opera: Check auf jegliche Versionen von Opera
.WebKit: Check auf Webkit Browser (Safari, Anroid)
.MobileSafari: Expliziter Check auf iPhone Browser
.Gecko: Browser basierend auf Gecko (Firefox, Netscape)
87. Prototype: String
Sind wir nicht endlich durch?
Nein. Mit dem String Objekt kommt nochmal eine grobe Sache
Gültigkeit der Methoden
Jeder String besitzt die neuen Methoden, da Prototype direkt
das String Objekt erweitert (Wie bei Zahlenwerten)
Wichtige Funktionen
.capitalize(): Ersten Buchstaben gross schreiben
.endsWith()/startsWith(): Start oder Ende des Strings prüfen
.(un)escapeHtml(): Konvertiert reinen Text in HTML Entitäten und zurück
88. Prototype: String
Noch etwas mehr Funktionen
.evalJSON(): JSON String zu einem Objekt konvertieren
.isJSON(): Gibt an, ob der String evaluierbares JSON enthält
.evalScripts(): Javascript Code innerhalb des Strings ausführen
.extractScripts(): Gibt ein Array aller Javascript Codezeilen zurück
.sub()/.gsub(): Einfache Form von Regex und/oder Replace
.scan(): Erlaubt die Anwendung eines Callback für jeden Teilstring
.stripScripts(): Löscht alle <script> Tags und JS Codes aus dem String
.stripTags(): Entfernt alle HTML Tags aus dem String
.toArray(): Erstellt ein Char Array aus dem String
.toQueryParams(): Erstellt JSON Code aus URL Parametern
.truncate(): Kürzt den String auf X-Zeichen und fügt Suffix an
89. Prototype: Template
Sowas wie String.Format in .NET
String mit Variablen durch Objektproperties ersetzen
Gedacht für mehrfache Verwendung
Das Template ist z.B. für Listenansichten sehr geeignet, lässt aber
auch herkömmlichen „Verknüpfungscode“ schöner aussehen
Wichtige Funktionen
.evaluate(obj): Ersetzt die Templatevariablen mit entsprechenden
Variablen im gegebenen Objekt (JSON oder Prototype Objekt)
90. Prototype: PeriodicalExecuter
Anwendung des Template
var conv1 = { from: 'meters', to: 'feet', factor: 3.28 };
var conv2 = { from: 'kilojoules', to: 'BTUs', factor: 0.9478 };
var conv3 = { from: 'megabytes', to: 'gigabytes', factor: 1024 };
// Template erstellen
var tpl = new Template(
'Multiply by #{factor} to convert from #{from} to #{to}.'
);
// Alle formatieren... mit on-the-fly-array-each :D
[conv1, conv2, conv3].each(function(conv){
tpl.evaluate(conv);
});
// -> Multiply by 3.28 to convert from meters to feet.
// -> Multiply by 0.9478 to convert from kilojoules to BTUs.
// -> Multiply by 1024 to convert from megabytes to gigabytes.
92. Scriptaculous: Effekte
Zurück zum Kerngeschäft
Scriptaculous bietet Effekte und Controls
Warum bietet Prototype das nicht an?
Prototype und Scriptaculous haben eine strikte Trennung aus
funktionalem Framework und Effekten/Controls
Effekttypen
Es wird zwischen Kerneffekten und Kombinationseffekten unterschieden
93. Scriptaculous: Effektbeispiele
Anzeige-Effekte
Effect.Highlight: Lässt die Hintergrundfarbe kurz aufblinken
Effect.Morph: Erlaubt Farbwechsel zwischen zwei Farben
Effect.Move: Absolute oder Relative Veränderung der Position
Erschein-Effekte
Effect.Appear: Sanftes Einblenden eines Controls
Effect.BlindDown: Herunterfahren eines Controls
Ausblende-Effekte
Effect.Fade: Sanftes ausblenden eines Controls
Effect.BlindUp: Herauffahren eines Controls
94. Scriptaculous: Effekt Queues
Effect.Queue
Jeder Effekt lässt sich in eine Queue stellen, da er ansonsten
parallel mit anderen Effekten ausgeführt würde
Einschränkung
Man muss eindeutige „Scopes“ definieren, um Sie während der
Laufzeit mit Effect.Queue steuern (z.B. Abbrechen) zu können
Beispiel
Das folgende Beispiel zeigt die Grundlegende Arbeit mit Queues.
Merke: Queues sind nur nötig, wenn Effekte auf dem selben Element
nacheinander anstatt gleichzeitig ausgeführt werden sollen
95. Scriptaculous: Effekt Queues
Erstellen von Queues
// Menu anzeigen, ans Ende des 'sc_menu' Scope
new Effect.SlideDown('menu',
{ queue: { position: 'end', scope: 'sc_menu' } }
);
// Banner anzeigen, ans Ende des 'sc_banner' Scope
new Effect.Appear('bannerbig',
{ queue: { position: 'end', scope: 'sc_banner' } }
);
// Menu pulsieren lassen, nach SlideDown Effekt
new Effect.Pulsate('menu',
{ queue: { position: 'end', scope: 'sc_menu' } }
);
96. Scriptaculous: Effekt Queues
Steuern der Scopes
// z.B. die Menu Queue holen
var queue = Effect.Queues.get('sc_menu');
// 'queue' ist eine Prototype Enumeration, daher...
queue.each(function(effect) { effect.cancel(); });
// ... um alles abzubrechen oder ...
queue.invoke('cancel');
// …Wartezeit zwischen Effekten beeinflussen
queue.interval = 100;
97. Scriptaculous: Combination / Toggle
Combinations toggeln und mergeln
SlideUp()/Down(), Appear()/Fade() und BlindDown()/Up() lassen sich mit
toggle() einfach kombinieren bzw. ein- und ausblenden
Sinn dahinter
Spart einiges an Code, da ein-/ausblenden mit einer
Zeile Code realisiert werden kann