APEX Plugin-Programmierung - von APEX lernen

Die Plugins, die wir in diesem Blog untersuchen werden, finden sich im Verzeichnis /i/libraries/apex. Dort existiert jeweils eine vollständige und eine minifizierte Version. Ich beziehe mich hier auf die Version 4.2, ältere Versionen haben die vorgestellten Dateien zum Teil nicht, zum Teil liegen sie in anderen Versionen vor. In diesem Verzeichnis wiederum befinden sich zwei Gruppen von JavaScript-Dateien, die mit dem Präfix "widget" und die anderen. Die "anderen" enthalten generelle JavaScript-Funktionalität, die zum großen Teil in den Plugins genutzt wird. Besonders interessant ist hier die Datei server.js, die Funktionalität rund um das Thema AJAX-Calls zum Server enthält, aber auch zum Beispiel die Datei page.js, die Dinge wie apex.submit etc. definiert. Es ist sehr lehrreich, sich in diesen Dateien einmal umzusehen. Schon seit Version 3.2 ist eine Tendenz innerhalb des APEX-Teams zu einer professionelleren JavaScript-Programmierung, insbesondere zur Kapselung eigener Funktionalität in Namensräumen, zu beobachten. Diese Tendenz ist in diesen Dateien deutlich zu erkennen, insbesondere zum Beispiel an der Datei legacy.js, in der die "alten", nicht einem Namensraum zugeordneten Hilfsfunktionen versammelt sind. Es darf wohl vorausgesetzt werden, dass APEX in Zukunft versuchen wird, diese Funktionen in den Hintergrund zu rücken zu Gunsten einer Namensraum-orientierten Programmierung.

Mein Augenmerk gilt aber den Dateien mit dem Präfix widget. Diese JavaScript-Dateien implementieren die Schnittstelle zwischen APEX und dem (JQuery-) Plugin. Die Aufgabe dieser Dateien ist es, die APEX-spezifischen Events zu implementieren, sowie, eine einigermaßen einheitliche Schnittstelle zur Integration externer Plugins in APEX zu gewährleisten.

Grundlegender Programmierstil

Die Plugins werden so implementiert, dass alle den Namensraum apex.widget erweitern. Anschließend werden Item-Plugins mit der Funktion initPageItem initialisiert. Diese Methode ist in widget.js definiert und leitet weiter auf item.js. Die Aufgabe dieses Objektes ist es, eine einheitliche Funktionalität der im nächsten Listing definierten Funktionen sicherzustellen. apex.item versucht, den Typ des Elementes, dessen Wert zum Beispiel gelesen werden soll, zu erkennen und entsprechend zu behandeln. Bei eigenen Plugins geht das natürlich nicht, daher definieren diese Callbacks, also Funktionen, die ausgeführt werden, wenn APEX eine entsprechende Funktion dieses Plugins anfordert. Möglich sind die im folgenden aufgeführten Methoden, es ist aber nicht nötig, alle zu implementieren, sondern nur diejenigen, für die im Plugin eine sinnvolle Funktionalität erstellt werden kann:

(function(widget, $)
{
	widget.myPlugin = function(pSelector, pOptions) {
		// Register apex.item callbacks
		$(pSelector, apex.gPageContext$).each(function(){
			widget.initPageItem(this.id, {
				setValue     : function() {},
				getValue     : function() {},
				addValue     : function() {},
				removeValue  : function() {},
				isEmpty      : function() {},
				enable       : function() {},
				disable      : function() {},
				show         : function() {},
				hide         : function() {},
				setFocus     : function() {},
				setStyle     : function() {},
				afterModify  : function() {}
			});
		});
	}; // myPlugin
})(apex.widget, apex.jQuery);

Einige interessante Punkte: Zunächst werden die Objekte apex.widget und apex.jQuery als Parameter widget und $ übergeben. Auf diese Weise ist insbesondere sichergestellt, dass die von Apex verwende JQuery-Version verwendet wird. Innerhalb dieser Funktion wird dann der Namensraum apex.widget durch myPlugin erweitert. Zunächst verwirrend ist vielleicht der Parameter apex.gPageContext$, der als zweiter Parameter dem JQuery-Selektor übergeben wird. Die Lösung findet sich in der Datei core.js, in der diese Variable mit document belegt wird. Dies stellt sicher, dass der JQuery-Ausdruck nur im aktuellen Dokument angewendet wird.

Aufruf eines Item-Plugins

Programmieren Sie Ihre Plugins ebenso, werden sie anschließend auf der Seite mit folgendem JavaScript eingebunden:

(function(){
	apex.widget.myPlugin("#P100_MY_PLUGIN",{"myOptions":"Options"});
})();

Und genau das ist es auch, was Sie sehen, wenn Sie auf einer Seite zum Beispiel einen Datepicker verwenden. Die Datei widget.datepicker.js wird durch APEX eingebunden und eine Funktion analog zur obigen in der document.ready-Methode ausgeführt.

Region Plugin

Etwas anders ist die Situation bei einem Region-Plugin. Dort verwendet das APEX-Team eine "entpackte" Variante im Vergleich zu einem Item-Plugin: Das Item-Plugin wurde ja eingebunden, indem ein JQuery-Selektor und ein Options-Objekt an apex.widget.myPlugin übergeben wurde. Daher ist es auch möglich, viele Items in einem Rutsch mit diesem Plugin zu binden, lediglich der Selektor muss entsprechend angepasst werden (Daher auch die each-Funktion im JavaScript). Bei einem Region-Plugin wird dieser Mantel nicht programmiert, sondern es wird direkt apex.widget erweitert:

/**
 * @namespace apex.widget.myPlugin
 **/
apex.widget.myPlugin = {};

(function(myPlugin, server, $) {
	"use strict";
	// Store options in an array to support multiple instance per page
	myPlugin.Options = [];

	myPlugin.init = function(pMyPluginId, pOptions) {
		myPlugin.Options[pMyPluginId] = pOptions;
		
        // Register 'Refresh' event, ready to be triggered
        // by a 'Refresh' dynamic action, or manually in JS via the apexrefresh event.
        // Also add WAI-ARIA 'aria-live' attribute, to signal the region as a 'live' region,
        // such that screen reader users will be informed when PPR takes place
        $("#" + pRegionId, apex.gPageContext$)
            .attr( "aria-live", "polite" )
            .bind( "apexrefresh", function() {
                myPlugin._refresh(pMyPluginId);
            });	
	};
	
	function _refresh(pId){
		var options = myPlugin.Options[pId];
		// Implement refresh functionality here
	}
})(apex.widget.myPlugin, apex.server, apex.jQuery);

Sie sehen, dass ein Region-Plugin direkt den Namensraum apex.widget erweitert und eine init-Methode implementiert. Bei einem Region-Plugin existiert keine Standardfunktionalität wie bei einem Item-Plugin, mit Ausnahme des Region Refresh. Daher wird in dieser Methode auch der Event apexrefresh gebunden, um das Plugin durch eine Dynamic Action vom Typ Refresh aktualisierbar zu machen. In diesem Zusammenhang müssen die Events apexbeforerefresh und apexafterrefresh nur dann von Ihnen geworfen werden, wenn ein AJAX-Call an die Datenbank nicht durch apex.server durchgeführt wird, weil diese Methode die Events wirft. Diese Events zu implementieren ist sinnvoll, um weitere Aktivitäten nach dem (asynchron über AJAX ablaufenden) Laden des Plugin-Contents durchzuführen. Stellen Sie sich hierzu vielleicht vor, Sie möchten auf einen Klick auf eine Zeile eines Berichts reagieren, den Ihr Plugin anzeigt. Dann könnten Sie eine Dynamic Action ausführen lassen, die an den Event apexafterrefresh bindet und die entsprechenden Aktivitäten ausführt.

Wichtig: Falls Sie mehrere Instanzen Ihres Plugins auf einer Seite zulassen möchten, müssen Sie sich vor Augen führen, dass im Objekt apex.widget.myPlugin alle Plugin-Instanzen dieses Typs verwaltet werden, es werden nicht pro Aufruf separate Instanzen angelegt. Um nun die einzelnen Plugin-Instanzen auseinanderhalten zu können, müssen alle relevanten Einstellungen und Optionen in einem Optionen-Array verwaltet werden (es bietet sich an, die einzelnen Optionen über ihre Static-ID zu referenzieren). Laden Sie also bei allen Funktionen, die mit dem Plugin arbeiten, stets die Optionen aus diesem Array in ein lokales Optionen-Objekt um, um sicher zu sein, mit den richtigen Einstellungen an der richtigen Plugin-Instanz zu arbeiten.

Aufruf eines Region-Plugins

Der Aufruf eines solchen Region-Plugins ist beinahe analog zum Aufruf eines Item-Plugins:

(function(){
	apex.widget.myPlugin.init("MY_STATIC_ID",{"myOptions":"Options"});
})();

Eine Analyse der APEX-JavaScript-Dateien verrät Ihnen viel über die interne Arbeits- und Denkweise des APEX-Teams. Viele Hilfsfunktionen lassen sich sehr gut nutzen, um den eigenen Code schlanker, aber auch konformer zum allgemeinen APEX-Standard zu machen. Auf der Habenseite dieses Ansatzes steht die nahtlose Integration Ihrer Plugins in die Architektur von APEX, zudem sind viele der Erweiterungsdateien immer auf der Seite verfügbar und müssen daher nicht zusätzlich geladen werden.

 

Kommentare   

 
0 #2 Addie 2018-05-13 02:20
Simply a smiling visitor here to share the love (:, btw great pattern.
Zitieren
 
 
0 #1 home blog 2016-11-13 15:01
Hurrah, that's what I was seeking for, what a material!
present here at this web site, thanks admin of this site.



Review my blog; home blog: http://www.jzqudou.com/comment/html/index.php?page=1&id=67507
Zitieren
 

Kommentar schreiben


Sicherheitscode
Aktualisieren