Kategorie: HTML

Fix und sicher – jQuery datepicker kombiniert mit altField

17. November 2013 - HTML, JavaScript

Das Lieferdatum steht in der Datenbank im date Format und wird dem Kunden nur angezeigt.
Plötzlich will der Kunde es änderbar haben und das möglichst vorgestern.

Ein Textfeld soll her!

Nein!!! Oh, Schock, mit dem Datum ist nicht zu spassen, es gibt ja schließlich mehrere Milliarden Möglichkeiten, was der Kunde da hineinschreiben könnte.
z.B. „drei Tage später“ oder „1,septemba zweitausendneun10“.
Wie bekommt man sowas wieder in die Datenbank zurück mutiert?

Die Lösung ist, wir nehmen den datepicker vom jQuery UI und nutzen dessen altField Option.
Wir brauchen noch zusätzlich im Formular ein hidden input field und (doch!) ein einfaches Text field, das wir aber eher ignorieren als nutzen.

<tr>
<th>Liefertermin</th>
<td>---hier wird der Liefertermin wie immer schon angezeigt  27. August 2019 </td>";
</tr>

<tr id='picker_start'>
<th>Liefertermin ändern:</th>
<td><input type='text' id='picker' ></td>   hier steht später das vom Kunden geänderte Lieferdatum
<input type='hidden' name='liefertermin' id='get_date' value='---hier schreiben wir das Datum aus der DB im date Format hinein--'></td>";
</tr>

Das ist alles bis auf das Javascript

$( "#picker" ).datepicker({
altField: "#get_date",altFormat: "yy-m-d",dateFormat: "d.M.yy"
});

Der datepicker poppt auf, wenn das Textfield mit der id „picker“ den Focus erhält, bezieht dann sein Start-Datum aus dem hidden field, der Kunde ändert das Datum und datepicker schreibt das neue Datum  in das hidden field und das Textfield, hier aber in etwas schönerer Form.
Wenn man deutsche Monatsnamen haben möchte, muss man dem datepicker dies mitteilen (weiter unten)
Wenn der Kunde das Formular abschickt, machen wir das update in die Datenbak vom hidden field.

Achtung: date in mysql hat die Form Y-m-d für den 27. August 2019, also 2019-08-27 , der datepicker hat aber eine eigene andere Formatanweisung: yy-m-d

Datepicker deutsch:

$.datepicker.setDefaults($.datepicker.regional['de']);

Tut sich dann nichts, muss man
$.datepicker.regional[‚de‘] von google herunterladen.
Zur Zeit sieht die Datei so aus:

$.datepicker.regional['de'] = {clearText: 'löschen', clearStatus: 'aktuelles Datum löschen',
closeText: 'schließen', closeStatus: 'ohne Änderungen schließen',
prevText: 'currentText: 'heute', currentStatus: '',
monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],
monthStatus: 'anderen Monat anzeigen', yearStatus: 'anderes Jahr anzeigen',
weekHeader: 'Wo', weekStatus: 'Woche des Monats',
dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
dayStatus: 'Setze DD als ersten Wochentag', dateStatus: 'Wähle D, M d',
dateFormat: 'dd.mm.yy', firstDay: 1,
initStatus: 'Wähle ein Datum', isRTL: false};
$.datepicker.setDefaults($.datepicker.regional['de']);

Internet Explorer, display:none, image width = 0

1. März 2012 - HTML, IE, JavaScript

Wenn ihr ein Element (hier ein <div> mit einem img) auf eine Webseite stellt und es mit display: none versteckt, um es im Browser dynamisch anzupassen, kann es sein, dass ihr über einen kleinen feinen Unterschied zwischen dem IE und dem Rest der Browserwelt stolpert.

 

English Summary for „Internet Explorer, display:none, image width = 0“:

If it comes to hidden elements (display: none) on your website, your software may step over  some subtle differences between Internet Explorer and for example FireFox. FireFox and IE implement  „display:none“ elements in different ways that affect their width and height values.

IE und Firefox implementieren display:none unterschiedlich

Ich hatte per Plugin ein paar Zeilen in meine Seite eingefügt:

echo '<div id="bgimage" style="display: none; z-index: 0; overflow: hidden; position: fixed; width: 100%; height: 100%; top: 0px; left: 0px;">'
echo '<img src="'. plugins_url().'/hintergrundbild/images/'.$akt_image. '" alt="" width="'.$image_dims[0].'" height="'.$image_dims[1].'" style="z-index:1 ;" />';
echo '</div>';

Das Bild wollte ich im Browser per jQuery anpassen

...
var viewportWidth,viewportHeight,width_aspect_ratio,height_aspect_ratio,factor;
var bgimage=jQuery('#bgimage');
var imageWidth;
var imageHeight;
imageWidth=bgimage.find('img').attr("width");
imageHeight=bgimage.find('img').attr("height");
viewportWidth= jQuery(window).width();
viewportHeight= jQuery(window).height();
...

Das klappte auch beim FF ohne Probleme, aber der IE zeigte die Bilder nicht an.

Ursache war das „display:none“

Firefox baut das <div> so ein:

Internet Explorer ( Versionen 7-9) aber so:

Im ersten Fall waren die Bilddimensionen vorhanden, im zweiten Fall nicht.

Bilder nicht mit display: none verstecken

Also: in diesem Fall ist es besser, die Finger von display: none zu lassen und mit top:-32767 zu arbeiten.

Komplexe Formulare, rekursives Ajax und promise() Interface

21. Oktober 2011 - HTML, JavaScript

Nehmen wir mal an, dass ihr auf auf eurer Webseite ein komplexes Formular habt (Beispiel: order.php), in dem viel geprüft (Spam, Adressen…) werden muss, was die Wahrscheinlichkeit erhöht, dass das Formular mehrfach zwischen Client und Server hin- und hergeschickt wird. Nun möchtet ihr dieses Formular  ohne Änderungen an mehreren Stellen eurer Webseite aufrufen können, ohne dass der Benutzer die aktuelle Seite verlassen muss.

Hier ist eine Lösung dafür.

English Summary: If you want to call a complex form page (order sheet, inquiry form,…) from several locations inside your website without the need to follow a link to that form page, here is a solution using recursive Ajax, UI-Dialog und the jQuery promise interface.

Dieses kurze Javascript sorgt dafür, dass euer Formular richtig ausgefüllt wird. Bei Fragen: bitte Kommentar schicken.

jQuery(document).ready(
function()
{

jQuery(".****class der Elemente, die das Formular aufrufen können****").click(
function()
{
var sendpost=jQuery.Deferred();
function send_post_req ()
sendpost=jQuery.post(order.php);
}
function show_post (response) {
clean_up();
jQuery("***id des Elements auf der Seite, nach dem eingefügt werden soll***").append('<div id="**ID des Formulars****" style="display: none;">'+response+'</div>');
}
function clean_up () {
jQuery("**ID des Formulars****").remove();
}

function add_submit () {
jQuery("form #**** ID eures Submit-Buttons****").click ( function (e) {
e.preventDefault;
var ser2=jQuery('form').serialize();
sendpost=jQuery.post(order.php, ser2);
proc_post();
});
}
function add_dialog ()
jQuery("**ID des Formulars****").dialog({
width: 600,
resizable: true,
title: 'Einfache Bestellung',
position: 'center',
close: function(event, ui) { clean_up();
}
});

}
send_post_req();
proc_post();
function proc_post() {
jQuery.when (sendpost)
.done (function (response) {
show_post (response);
add_dialog();
add_submit();
});
}
});
});

Zunächst werden einige Funktionen definiert:
send_post_req:  Post-Request; damit holen wir den Inhalt eurer Formular-Seite zum ersten Mal
show_post:  damit wird der Inhalt  im DOM der aktuellen Seite unsichtbar angelegt
clean_up:  damit wird dieser Inhalt bei Bedarf wieder entfernt
add_submit:  übernimmt den Submit-Button und schickt das Formular an den Server zurück
add_dialog:  stellt den Inhalt des Formulars in einem UI-Dialog auf der Seite dar.
proc_post:  bindet alle Funktionen zusammen und nutzt das promise Interface von jQuery.

Gestartet wird in das Ganze in der Zeile 39.

Die Zeile 25 sorgt für das rekursive Abarbeiten, wenn das Formular mehrmals zwischen Server und Client hin- und hergeschickt werden muss.

Damit proc_post nicht schon verfrüht losfeuert, wird in Zeile 8 ein Deferred Objekt (sendpost) erzeugt, auf das proc_post warten muss.  Dieses Objekt wird in send_post_req überschrieben, so dass proc_post jetzt auf den Ausgang der Ajax-Anfrage wartet.

Die zweite Ajax-Anfrage in add_submit schickt beim Anklicken den mit einem zweiten Parameter serialisierten Inhalt eures (hoffentlich vom Benutzer ausgefüllten) Formulars  an den Server.  Dabei wird das „resolved“ Deferred sendpost überschrieben und wieder aktiviert.

Für die wenigen, die es noch nicht wissen:  jQuery und Javascript kann man prima und ohne Formalitäten bei jsFiddle austesten.

Wenn ihr mit einem Content-Management System arbeitet, werdet Ihr in der Regel keine Seite „order.php“ haben, weil dort die Seite erst auf Anforderung vom CMS zusammen gebaut wird .

Im Falle CMS=wordpress kann man so vorgehen:

Der Post-Request muss etwas modifiziert werden (Doku hier)


var nf_data = {
action: 'order',
_ajax_nonce: MyAjax.akt_nonce
};
sendpost=jQuery.post(MyAjax.ajaxurl, jQuery.param(nf_data));

MyAjax.ajaxurl ist die Seite, die den Request erhalten soll: admin-ajax.php. Wo sie im Verzeichnisbaum liegt, muss dem Script über


wp_localize_script('simple', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php'),
'akt_nonce' => $this->nonce) );

mitgeteilt werden. Zusätzlich  wird noch ein Nonce  zum Überprüfen des Requests  mitgegeben.

action: ‚order‘ ist eure callback-Funktion (hier:“order“), die von admin-ajax.php aufgerufen wird und das Formular erzeugt.

Der zweite Post-Request sieht so aus:


var ser2=jQuery('form').serialize();
var ser=jQuery.param(nf_data);

sendpost=jQuery.post(MyAjax.ajaxurl, ser+'&'+ser2 );

Zum besseren Verständnis könnt Ihr den Original Code hier downloaden:  Template einfacher_bestellen

Denkt bitte daran: das Plugin muss für eure Zwecke noch modifiziert werden. Der Code für das Formular ist z.B. in einer Klasse enthalten, die in der Webseite an anderer Stelle definiert und hier nicht beigefügt wird.
Einige Teile des jQuery Codes sind formularspezifisch (z.B. wird das Formular über „form.yform“ gefunden).

IE7 z-index bug in WordPress Menüs

14. September 2011 - HTML, IE7, JavaScript, wordpress

Wenn ihr den IE7 noch unterstützen müßt und lange (mehrreihige) WordPress Menüs habt: hier ist eine Hilfe gegen den z-index bug von IE7.

English Summary: The following is dedicated for people who have to support IE7 and encounter the z-index bug in their wordpress menues.

Über den z-index bug vom IE7 ist ja schon viel geschrieben worden, z.B. hier. Wenn das Menü nur unter den nachfolgenden Content rutscht, kann man sich durch Vergabe eines z-index per style.css für den Container, der das Menü enthält, behelfen.

Anders ist es leider, wenn man eine Webseite untersützen muss, deren Redakteure gerne viele Toplevel Menüeinträge generieren. Auf einmal wird das Menü mehrzeilig.

Für moderne Browser ist dies kein Problem. Für den IE7 schon. Der aufgeklappte Inhalt des ersten Menüpunktes rutscht hier unter einen Menüpunkt in der zweiten Zeile. Folge: das Menü ist nicht mehr funktionstüchtig.

Jetzt hilft leider keine style.css weiter. Die einzige Möglichkeit ist, jedem Menüpunkt der obersten Ebene einen passenden z-index zu verpassen: der erste Menüpunkt bekommt den höchsten z-index, der zweite den zweithöchsten usw.

Da das Menü dynamisch ist, kann man das nur mit einem JavaScript hinbekommen.

Zum Glück ist es sehr kurz 🙂

jQuery(document).ready(
function()
{
var maxzindex=2000;
jQuery('#access > .menu > ul > li').each(function(index,value) {
jQuery(this).css("z-index",maxzindex-index);
});
});

#access > .menu > ul > li ist bei meiner Webseite der eindeutige Pfad zu den Top-Level
Menüs. Sie erhalten die z-indizes 2000, 1999, 1998 usw.

Einbinden kann man script z.B. so:


<!--[if IE 7]>
<script type='text/javascript' src='<?php bloginfo('template_directory'); ?>/js/patch_menue_ie7.js'></script>
<![endif]-->

Und wenn man alles richtig gemacht hat, sieht es dann so aus:

WordPress und JQuery-UI-datepicker

7. September 2011 - HTML, JavaScript, wordpress

Die Integration von datepicker in eine WordPress Seite mit einem Datumsfeld ist sehr einfach.

English Summary:  “ The datepicker is tied to a standard form input field. Focus on the input (click, or use the tab key) to open an interactive calendar in a small overlay. Choose a date, click elsewhere on the page (blur the input), or hit the Esc key to close. If a date is chosen, feedback is shown as the input’s value.“ jquerui.com

Folgende Elemente vom datepicker müssen von jquery.com ins Plugin geladen werden.

  • jquery.ui.datepicker.js
  • jquery-ui-1.8.16.custom.css
  • alle Bilder
  • die Anpassung an das deutsche Datumsformat von http://jquery-ui.googlecode.com/svn/trunk/ui/i18n/jquery.ui.datepicker-de.js

Dazu benötigt man noch den jquery-ui-core, der ist aber in WordPress bereits vorhanden.

Die JavaScript Datei zum Init vom datepicker sieht dann etwa so aus:

jQuery(document).ready(function()
{jQuery('.nf_datum').datepicker();

jQuery(function($){
 $.datepicker.regional['de'] = {
 closeText: 'schließen',
 prevText: 'zurück',
 nextText: 'Vor',
 currentText: 'heute',
 monthNames: ['Januar','Februar','März','April','Mai','Juni',
 'Juli','August','September','Oktober','November','Dezember'],
 monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',
 'Jul','Aug','Sep','Okt','Nov','Dez'],
 dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
 dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
 dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
 weekHeader: 'Wo',
 dateFormat: 'dd.mm.yy',
 firstDay: 1,
 isRTL: false,
 showMonthAfterYear: false,
 yearSuffix: ''};
 $.datepicker.setDefaults($.datepicker.regional['de']);
 });   .....................................

In diesem Fall wird der datepicker an alle input Felder mit der Klasse „nf_datum“ gebunden.

WP-Syntax oder SyntaxHighlighter Evolved

7. September 2011 - HTML, wordpress

Seit einiger Zeit versuche ich, die Darstellung von Code in meinem Blog zu verbessern.

Der erste Plugin-Kandidat war WP-Sytax

Es gab aber Probleme mit den WordPress-Editoren und WordPress.

Der Code wird so umschlossen (ohne die Leerzeichen nach < und >)

< pre lang=“PHP“ line=“1″ > und < /pre >

Der wysiwyg Editor wirft z.B. das attribut line hinaus, weil es nicht erlaubt es.  Dadurch kann man aber keine Zeilennummern ausgeben. WordPress macht die ganzen eckigen Klammern unschädlich. Dann wird <pre> aber nicht mehr vom Plugin erkannt.

Man muß den ganzen Code-Block nochmal mit < code > < /code > kapseln und in den Artikel vor dem Sichern nochmal  mit dem HTML Editor das line=“1″ einfügen. Und den Artikel nicht mehr später mit wysiwyg wieder öffnen.

Das war mir zu mühselig.

Jetzt verwende ich SyntaxHighlighter Evolved .

Hier werden die Code-Zeilen im Shortcode-Stil mit [ php ] und [ /php ] umschlossen. Tut auf Anhieb in beiden Editoren.

 function kiju_init() {
wp_register_script('jquery-ui-datepicker',WP_PLUGIN_URL.'/kiju_admin/js/jquery.ui.datepicker.js',array('jquery', 'jquery-ui-core'),false,true);
wp_register_script('check_selected', WP_PLUGIN_URL.'/kiju_admin/js/check_selected.js', array('jquery', 'jquery-ui-core'),false,true);
wp_register_style('kiju_admin_css',WP_PLUGIN_URL.'/kiju_admin/css/kiju_admin.css');
}

ältere Webseiten mit CSS Navigation: Abreißen oder Modernisieren

28. Juli 2011 - HTML, JavaScript, wordpress

Unter Kollegen gab es kürzlich die Diskussion,  wie man bei vorhandenen und älteren Webseiten die Navigation verbessert. Abreißen und durch ein JavaScript Plugin ersetzen oder modernisieren?

Eine Fraktion war die „nimm doch superfish oder ….  und dann hast du keinen Ärger mehr“, die andere Fraktion war eher nachdenklich. Durch ein aktuelles Projekt etwas schlauer geworden, gehörte ich auch zu den nachdenklichen.

Fakt ist wohl, dass die JavaScript-Navigations Plugins auch nur mit Wasser (=CSS) kochen und JavaScript lediglich zum Vorbereiten und Verbessern der HTML Struktur der Navigation benutzen. Natürlich fügen sie den Menüs auch noch ein paar Effekte hinzu. Die Hauptarbeit (90%) wird aber immer noch über CSS erledigt.

Wenn man eine vorhandene CSS Navigation mit sicherlich einigen Dutzend Zeilen CSS durch ein „fertiges“ JavaScript Produkt ersetzt, das eigene, völlig neue  CSS Dateien mit wiederum einigen Dutzend Zeilen CSS benötigt, ist dies wie ein Neuanfang. Man versteht zunächst nichts und es funktioniert auch erstmal nichts.

Deshalb, und weil ich auch nicht unbegrenzte Zeit habe und auch nicht unbegrenzte Lust, wieder da anzufangen, wo ich vor drei Jahren schon mal stand, plädiere ich für das behutsame Modernisieren:

Belasse die CSS Struktur wie sie ist und ändere gezielt über JavaScript.

Ein Beispiel dafür ist dieser Artikel.

Wenn man neu anfängt, sollte man das beste und flexibelste Tool auswählen oder auf das vertrauen, was einem ggf. sein Framework anbietet 🙂

 

 

Add arrows to menus in WordPress

27. Juli 2011 - HTML, JavaScript, wordpress

Wenn ihr ein vorhandenes Menü mit Richtungspfeilen ergänzen möchtet:  hier ist ein kleines Plugin dafür.

English summary: If you have an existing menu on your WordPress blog or site and want to enhance it with arrows to indicate submenus: here is a proposal to do so.  But be aware, that the plugin isn’t out of the box and needs slight modifications to meet your special requirements.

Die Grundidee findet man  z.B. auch beim superfish Menu: per JavaScript/ jQuery werden dem Menü beim Laden der Seite kleine Pfeilchen hinzugefügt, wenn ein Menüpunkt Untermenüs besitzt.

Der js Code besteht nur aus wenigen Zeilen:

jQuery(document).ready( function()<
{
       jQuery(".vlist li:has(ul) > a").each(function() {
       jQuery(this).html(jQuery(this).text() + '<img src="' + pathtoimage.jsmenuImageUrl + 'arrow_down.png" width="20px" height="10px"/>');
});
       jQuery("#access > .menu > ul > li:has(ul) > a").each(function() {
       jQuery(this).html(jQuery(this).text() + '<img src="' + pathtoimage.jsmenuImageUrl + 'arrow_down.png" width="20px" height="10px"/>');
       });
       jQuery("#access > .menu > ul > li:not(ul) li:has(ul) > a").each(function() {
       jQuery(this).html(jQuery(this).text() + '<img src="' + pathtoimage.jsmenuImageUrl + 'arrow_right.png" width="20px" height="10px"/>');
        });

});

Die erste Funktion:

jQuery(".vlist li:has(ul) > a").each(function() {.....

findet alle li- Listpunkte nach dem div mit der Klasse vlist, die Untermenüs besitzen und fügt einen arrow-down an.
Ich benutze dies für ein Menü in der Sidebar, das Untermenüs durch Einrückung anzeigt und nicht „aufklappt“.

Die zweite Funktion:

jQuery("#access > .menu > ul > li:has(ul) > a").each(function() {...

findet alle li-Listpunkte mit Untermenüs auf der ersten Ebene und fügt ebenfalls einen arrow-down an.
Dass benutze ich für das Hauptmenü, das die zweite Ebene nach unten aufklappt.

Die dritte Funktion

jQuery("#access > .menu > ul > li:not(ul) li:has(ul) > a").each(function() {...

findet alle li-Listpunkte mit Untermenüs nach der ersten Ebene und fügt einen arrow-right an. Dies benutze ich im Hauptmenü für alle folgenden Untermenüs.

Mit

jQuery(this).html(jQuery(this).text() + ....

wird der angezeigte Menüname  gefunden und um das entsprechende Bild erweitert.

Damit das Plugin funktioniert, müsst ihr für jQuery den Suchpfad (z.B („.vlist li…“ oder „#access > .menu > ul > li…“ modifizieren, damit die richtigen li-Listpunkte gefunden werden.

 

Hier könnt ihr das Plugin downloaden: jsmenu. Denkt aber daran, dass ihr es anpassen müsst

Mehr Kontrolle über eine Select-Schaltfläche mit JavaScript

18. März 2011 - HTML, JavaScript

Wenn man ein Select in einem Formular verwendet, kann es hilfreich sein, wenn man den Status des Selects überwachen kann – besonders dann, wenn durch die Änderung der Select-Auswahl ein neuer Datensatz aktiviert wird. Möglich ist dies mit Javascript.

English Summary: select controls in forms may be used for convenience to input text. If a select control is bound to a dataset, it may be necessary to monitor it’s behaviour with JavaScript.

In einem Projekt wird über ein Select gesteuert, welcher Datensatz behandelt werden soll. Der Benutzer kann den Datensatz ändern oder löschen. Ändert er die Daten, muss man den Zustand des Selects bis zum Speichern der Daten überwachen, damit der Datensatz nicht falsch zugeordnet wird.

Hier ist ein Javascript dazu:

jQuery(document).ready(function() {
var capt=jQuery('select.critical_click_select').val();
var cnpt;
 
jQuery('select.critical_click_select').change(function() {
cnpt=jQuery('select.critical_click_select').val();});

if (cnpt == capt) { // passiert beim Rücksetzen der selektion; mach nix
} else {
  if (.. der Benutzer hat die Daten verändert..) {
  var jj=confirm("Wenn Du jetzt einen neuen Datensatz wählst und dann die Änderungen speicherst, werden sie\n zum neuen Datensatz hinzugefügt.\n Fortsetzen?");
  if (jj) {
   capt=cnpt;
  } else {jQuery('select.critical_click_select').val(capt);}
 } else { capt=cnpt; // normale Änderung, mach nix
 }
}  

 });

Das Select hat die Klasse .critical_click_select. Zunächst wird der aktuelle Zustand in capt gespeichert. Wenn das Select verändert wird, speichert man den neuen Zustand in der Variablen cnpt. Dann muss man feststellen, ob Änderungen an den Daten vorgenommen wurden. In dem Confirm-Dialog fragt man den Benutzer, ob er den Datensatz wechseln möchte. Wenn nein, stellt man den ursprünglichen Status wieder her.

Wenn keine Änderung erfolgt ist, kann man die Select-Änderung „durchgehen“ lassen.