Mit ‘Javascript’ getaggte Artikel

Javascript im href von HTML-Links

Donnerstag, 22. Juli 2010

Wer Probleme damit hat, browserkompatibel auf clicks bei Links zu reagieren, kann dies mit Hilfe des Schlüsselwortes ‘javascript:’ zu Beginn des href-Attributwertes verwirklichen.

Bsp:

<a href="javascript:myFunction();">Ein Link</a>

Angenommen, die Funktion myFunction() sieht nun beispielsweise so aus:

function myFunction() {
alert("Hallo!");
return false;
}

Dann wird die Seite, die den Link beinhaltet, gelöscht und eine neue Seite angezeigt, auf der lediglich das Wort ‘false’ steht. Das liegt daran, dass das Ergebnis des Javascripts in eine neue Seite gerendert wird.

Wichtig ist also, dass der Rückgabewert von myFunction undefined ist, wenn man möchte, dass die ursprüngliche Seite erhalten bleibt.


Christian Borkowski


JavaScript: Tastatureingaben mit prototype auswerten

Montag, 15. März 2010

Im folgenden Abschnitt möchte ich anhand des Beispiels einer Mehrfachauswahl von Eingabefeldern erläutern, wie einfach es ist, in JavaScript einen Tastendruck auszuwerten.
Ich verwende hier die prototype Bibliothek. Für alle, die prototype nicht kennen, ganz kurz:
$(’name’) entspricht der Methode getElementById(’name’)

var KeyEvent = {
   ctrl: false,
   keyCode: 0,
   element: null,
 
   /**
    * Am uebergebenen Element z.B. einem div Container oder document selbst
    * werden die Methoden fuer die Events keydown und keyup registriert.
    *
    * element: HTML-Element, an dem die Events registriert werden sollen
    * z.B. Tabelle oder Div.
    */
   init: function(element) {
      KeyEvent.element = element;
      // Taste gedrueckt
      Event.observe(KeyEvent.element, 'keydown', KeyEvent.registerDown);
      // Taste wieder losgelassen
      Event.observe(KeyEvent.element, 'keyup', KeyEvent.registerUp);
   },
 
   /**
    * Function, die auf den keydown event reagiert
    */	
   registerDown: function(event) {
      // falls die Taste gedrueckt bleibt, sollen keine weiteren 
      // keydown events verarbeitet werden
      KeyEvent.element.stopObserving('keydown');
      KeyEvent.keyCode = event.keyCode;
      if (event.ctrlKey) {
         KeyEvent.ctrl = true;
      }
   },
 
    /**
     * Function, die auf den keyup event reagiert
     */
   registerUp: function(event) {
      KeyEvent.ctrl = false;
      // wird die Taste losgelassen, starten wir den Observer fuer keydown wieder
      Event.observe(KeyEvent.element, 'keydown', KeyEvent.registerDown);
   }
};
 
/**
 * Wird beim onfocus des Eingabefeldes aufgerufen
 */
function selectField(element) {
   if (KeyEvent.ctrl) {
      // multiselect ... z.B. könnte man hier das Feld mit einer CSS class markieren.
   }
}

Im HTML könnte das dann wie folgt verwendet werden:

<body onload="KeyEvent.init($('content'))">
 
   <div id="content">
      <form ....>
         <input type="text" name="f1" onfocus="selectField(this)" />
         <input type="text" name="f2" onfocus="selectField(this)" />
         ...
      </form>
   </div>
</body>

Das obige Beispiel verwendet jetzt nur den speziellen event.ctrlKey. Eine denkbare Erweiterung wäre z.B. die Shift-Taste auzuwerten um die Felder von – bis zu markieren. Natürlich könnte man auch beliebige andere Tasten auswerten, dafür muss aber dann der numerische keyCode verwendet werden.

Mehr Infos zur Verwendung von Prototype finden sie unter http://prototypejs.org


Christof Aenderl


Integration von Ext JS (AJAX) in eine bestehende Webanwendung

Montag, 02. November 2009

Das man mit JavaScript und AJAX nicht nur tolle, sondern auch wirklich nützliche Funktionalität in einer Webanwendung unterbringen kann, ist nicht von der Hand zu weisen. Eingabefelder, die schon beim Eintippen mögliche Treffer anzeigen, sind nur ein Beispiel und auf fast allen bekannten Webseiten zu finden.
Solche Funktionalität lässt sich auch in bestehenden Anwendungen nachrüsten, ohne das komplette Projekt umzukrempeln. Die folgenden Beispiele stammen aus der Erweiterung einer Struts 1 Anwendung, in die wir nachträglich Ext JS (Version 2.2) integriert hatten, um einige der Widgets von Ext JS zu nutzen.

1. Ext JS zum Projekt hinzufügen
2. Einbinden von Ext JS in die JSP’s
3. AJAX Request mit Ext JS (Beispiel)
4. Response (HTML oder JSON)

Anmerkung: Expression Language (EL) muss vom Server unterstützt werden.

1. Ext JS zum Projekt hinzufügen

Das Archiv, das man von der Ext JS Seite herunterladen kann, enthält neben den eigentlichen Bibliotheken auch zahlreiche Beispiele und Sourcen, die von der Anwendung nicht benötigt werden. Folgende Dateien* und Verzeichnisse* kopiert man in sein Projekt z.B. in das Unterverzeichnis WebContent/js/ext:
- ext-all.js
- ext-core.js
- /adapter
- /build
- /resources

* Ext JS Version 2.2 oder 2.3 ohne Debug

Man kann auch die oben erwähnten Dateien und Verzeichnisse in ein ZIP packen, z.B. ext-2.2.zip und dieses beim Build der Anwendung durch Ant enstspr. auspacken und zum WAR hinzufügen lassen. Damit ist einigermaßen sichergestellt, dass die Ext-Dateien nicht editiert werden und zudem hat man nur eine Datei auf dem SVN bzw. CVS liegen (erleichtert auch den Wechsel auf eine andere Ext-Version). Das ist aber absolut optional.

2. Einbinden von Ext JS in die JSP’s

Um Ext verfügbar zu machen und den Standardadapter zu nutzen sind folgende Zeilen im HTML-Head nötig:

<script type="text/javascript" 
src="${pageContext.request.contextPath}/js/ext/ext-all.js"></script>
<script type="text/javascript" 
src="${pageContext.request.contextPath}/js/ext/adapter/ext/ext-base.js"></script>

Will man einige der Widgets von Ext nutzen, ist zusätzlich das CSS von Ext einzubinden:

<link rel="stylesheet" type="text/css" 
href="${pageContext.request.contextPath}/js/ext/resources/css/ext-all.css" />

und ggf. ein Theme auszuwählen, wenn man nicht das Standard-Blau verwenden möchte:

<link rel="stylesheet" type="text/css" id="theme" 
href="${pageContext.request.contextPath}/js/ext/resources/css/xtheme-gray.css" />

Eine Besonderheit: Ich weiß nicht, ob die Ext Entwickler das mit Absicht gemacht haben und welchen Zweck es haben soll, aber Ext “funkt” nach Hause. An einigen Stellen wird ein 1×1 Pixel Image von der Ext-Seite abgerufen. Will man das umgehen und stattdessen das Image lokal laden, sollte man diese Zeilen im Header unterbringen:

<script type="text/javascript">
// url for empty image otherwise http://extjs.com will be called
Ext.BLANK_IMAGE_URL = '${pageContext.request.contextPath}/js/ext/resources/images/default/s.gif';
</script>

3. AJAX Request mit Ext JS (Beispiel)

Nun werden wir einen Ajax Request ausführen um z.B. den Wert eines Formularfelds an den Server zu übermitteln, ohne die komplette Seite neu laden zu müssen (also kein Form.submit()).
Die Funktion würde wie folgt aussehen:

function sendValue(value) {
  Ext.Ajax.request({
    url: '${pageContext.request.contextPath}/sendValue.do',
    params: { newValue: value },
    success: function(result, response) {
      // in diesem Fall soll nichts gemacht werden	
    },
    failure: function(result, request) {
      Ext.Msg.alert('Fehler', 'Request konnte nicht ausgeführt werden');
    }
  });
}

Serverseitig rufen wir hiermit eine entspr. gemappte StrutsAction auf.
Auszug aus der struts-config.xml:

<action path="/sendValue"
  type="de.baderundjene.example.ValueChangeAction">
</action>

Ein Form kann man sich sogar sparen und den Parameter direkt auslesen:

public final class ValueChangeAction extends Action {
  @Override
  public final ActionForward execute(....) {
    final String newValue = request.getParameter("newValue");
    // irgendwas mit dem newValue machen
 
    return null;
  }
}

Am Ende geben wir null zurück, es soll ja kein ActionForward erfolgen und der Response soll leer sein.

4. Response (HTML oder JSON)

Möchten wir aber einen Wert, Werte oder ein HTML-Fragment zurückgeben, muss dieses als String in den Response geschrieben werden.
Um Daten an den Client (Browser) zu schicken, die dort per JavaScript verarbeitet werden sollen um z.B. die Werte einer Select-Box zu verändern, eignet sich JSON (JavaScript Object Notation) besonders gut. Details zu JSON findet man ganz leicht im Internet. Bevor wir also in unserer Action null zurückgeben, schreiben wir unseren JSON-String in den Response:

// ein Attribut data mit dem Wert Test
final String json = "({data:'Test'})";
// HttpServletResponse response;
// hier können wir auch das Encoding auf z.B. UTF-8 stellen
response.setContentType("text/json; charset=UTF-8");
final PrintWriter out = response.getWriter();
out.println(json);
out.flush();

Im JavaScript erweitern wir unsere success Methode:

function sendValue(value) {
  Ext.Ajax.request({
    url: '${pageContext.request.contextPath}/sendValue.do',
    params: { newValue: value },
    success: function(result, response) {
      var responseObj = Ext.decode(result.responseText);
      Ext.Msg.alert('Erfolg', responseObj.data);
    },
    failure: function(result, request) {
      Ext.Msg.alert('Fehler', 'Request konnte nicht ausgeführt werden');
    }
  });
}

Möchte man ein HTML-Fragment zurückgeben, um z.B. einen Teil der Seite neu zu laden, kann man in der Action einen ActionForward auf eine entspr. JSP durchführen. Diese JSP enthält dann eben keine ganze HTML-Seite sondern nur den Teil, den wir neu laden möchten, z.B. eine Tabelle mit den Kundendaten.
D.h. struts-config.xml anpassen:

<action path="/sendValue"
  type="de.baderundjene.example.ValueChangeAction">
  <forward name="success" path="inc/customerTable.jsp"/>
</action>

und statt null den ActionForward mapping.findForward(”success”); zurückgeben.
Unsere angepasste JavaScript Methode:

function sendValue(value) {
  Ext.Ajax.request({
    url: '${pageContext.request.contextPath}/sendValue.do',
    params: { newValue: value },
    success: function(result, response) {
      // <div id="customer-data">&nbsp;</div>
      var customerDiv = Ext.get('customer-data');
      customerDiv.update(response.responseText, true);
    },
    failure: function(result, request) {
      Ext.Msg.alert('Fehler', 'Request konnte nicht ausgeführt werden');
    }
  });
}

Fazit

Ein Projekt kann sehr leicht mit Ajax erweitert werden ohne bestehende Funktionalität anzufassen. Welches MVC-Framework hier zum Einsatz kommt, spielt eigentlich keine Rolle. Modernere Frameworks bieten allerdings teilweise out-of-the-box Unterstützung für Ajax und JSON an.
Bei unserem Projekt haben wir neue Erweiterungen direkt mit Ext JS implementiert, möglichst alle eigenen oder sonstiges JavaScript durch Ext Funktionen ersetzt und bauen jetzt bei Bedarf und wenn es sinnvoll ist, ältere Teile der Anwendung auf Ext um. Z.B. verwenden wir das Tree Widget inkl. Drag and Drop und Kontextmenü, welches sehr mächtig ist und einen sehr stabilen Eindruck macht.
Zu wünschen wäre jetzt nur noch eine bessere Unterstützung durch eclipse, aber das kommt vielleicht auch noch.
Falls es sich ergibt, werde ich auch noch näher auf interessante Widgets von Ext JS eingehen.

Viel Spaß und Erfolg beim Ausprobieren und Anwenden.


Christof Aenderl


Erstellen eines Plugins für den CKEditor 3.0

Dienstag, 27. Oktober 2009

Im Folgenden soll anhand eines kleinen Beispiels gezeigt werden, wie man ein Plugin für den CKEditor schreibt und dieses einbindet. Es soll ein Button in die Toolbar aufgenommen werden. Ein Klick auf diesen Button soll einen Dialog öffnen. In diesem Dialog wird man einen Text eingeben und eine Schriftfarbe für diesen Text auswählen können. Beim Klick auf den Ok-Button des Dialogs, wird dann der entsprechende Text in der gewählten Schriftfarbe in den Editierbereich eingefügt.

Zunächst benötigt man eine eigene Konfigurationsdatei “config.js”, um die Toolbar anzupassen.

CKEDITOR.editorConfig = function( config )
{	
	CKEDITOR.plugins.addExternal( 'insertText', CKEDITOR.basePath + '../ckeditor_customized/plugins/InsertText/' );	
 
	config.extraPlugins = "insertText";	
 
	CKEDITOR.config.toolbar = 'MyToolbar';
 
        config.toolbar_MyToolbar =
          [
            ['NewPage','insertText'],
          ];    
};

MyToolbar enthält lediglich 2 Buttons. Zum einen enthält sie den NewPage-Button, hinter dem sich ein bereits mit dem CKEditor-Source mitgeliefertes Plugin versteckt. Und zum anderen enthält sie den neuen Button. Für diesen legen wir das Verzeichnis “x/ckeditor_customized/plugins/InsertText/” an, wobei x für das Verzeichnis steht, in dem sich auch das CKEditor-Verzeichnis befindet. In das angelegte Verzeichnis fügen wir nun die Datei “plugin.js” ein, die folgenden Code enthält:

CKEDITOR.plugins.add('insertText', {
	init : function( editor )
	{
		editor.addCommand( 'insertTextDlg', new CKEDITOR.dialogCommand( 'insertTextDlg' ) );
 
		editor.ui.addButton( 'insertText',
			{
				label : 'Text einfügen',
				command : 'insertTextDlg',
				icon: <icon path>
			});
 
		CKEDITOR.dialog.add( 'insertTextDlg', CKEDITOR.basePath + '../ckeditor_customized/dialogs/insertTextDlg.js');
 
	}
});

Zunächst fügen wir in dem Plugin der Editor-Instanz ein neues Dialog-Kommando namens insertTextDlg hinzu, welches bei Klick auf den neuen Button ausgeführt werden soll. Anschließend registrieren wir den neuen Dialog, der sich beim Button-Klick öffnen soll. Der Dialog wird in der Datei “insertTextDlg.js” definiert.

CKEDITOR.dialog.add( 'insertTextDlg', function( editor ) {
	return { 
		title: 'Text einfügen',
 
		minWidth: 200,
		minHeight: 80,
 
 
		contents: [ 
			{
				id: 'tab1',
				label: 'Tab1',
				title: 'Tab1',
				elements : [ 
					{
						id: 'mytext',
						type: 'text',
						label: "Text",
						validate : function() {
							// potentielle Validierungen
							if (this.getValue() == "") {
								alert("Das Feld darf nicht leer sein!");
							}
							return this.getValue() != "";
						}
					},
					{
						id: 'mycolor',
						type: 'select',
						label: "Farbe",
						items: [
						        ['rot'],
						        ['grün'],
						        ['blau']
						       ],
						validate : function() {
							// Validierungen
							return true;
						}
					},
				 ]
			}
		 ],
 
 
		 onOk: function() { 
			var color = this.getContentElement('tab1', 'mycolor').getValue();
			var numColor;
			if (color == 'rot') numColor = '#F00';
			else if (color == 'grün') numColor = '#0F0';
			else if (color == 'blau') numColor = '#00F';
 
			var element = CKEDITOR.dom.element.createFromHtml(
					'<span style="color:' + numColor + ';">' + 
						this.getContentElement('tab1', 'mytext').getValue() + 
					'</span>');
			editor.insertElement(element);
		 }
 
	};
 
} );

Bei einem Klick auf Ok, werden die selektierten und eingegebenen Werte ermittelt. Nun kann der eingegebene Text in der gewünschten Farbe eingefügt werden.


Christian Borkowski