Wabern / Schweben-Effekt in jQuery

Ein kleines PlugIn zum Wabern / Wackeln / Schweben eines DIVs in jQuery: Das Ergebnis kann man auch bei jsfiddle anschauen und bearbeiten.

// (c) 99°, David Bascom 2013
// You may use this plugIn as you like, free of charge, but don't remove the (c)
(function(e){e.fn.extend({wabern:function(t){t=e.extend({centerX:false,centerY:false,speedX:3,speedY:5,distX:10,distY:10},t);this.each(function(){var n=e(this);var r=t.centerX?t.centerX:n.position().left;var i=t.centerY?t.centerY:n.position().top;var s=Math.random()*360;var o=Math.random()*360;var u=180/Math.PI;setInterval(function(){s=(s+t.speedX)%360;o=(o+t.speedY)%360;var e=r+t.distX*Math.sin(s/u);var a=i+t.distY*Math.cos(o/u);n.css({left:e,top:a})},40)})}})})(jQuery)

Das PlugIn kann dann so verwendet werden:

$(function () {
	$('.box').wabern({speedX:3, speedY:5, distX:10, distY:10});
});

Beispiel HTML-Code dazu:


   
%MINIFYHTML0ccaf290ea1f6413117f4a40afe7fc791%

Und das CSS:

.box {
	position: absolute;
	top: 200px;
	left: 200px;
	width: 50px;
	height: 20px;
	background-color: #ff6600;
}

Die unkomprimierte Version des PlugIns zum „Spicken“:

// (c) 99°, David Bascom 2013
// You may use this plugIn as you like, free of charge, but don't remove the (c)
(function($){
  $.fn.extend({
    'wabern': function (opt) {
      opt = $.extend( {
        'centerX':  false,
        'centerY':  false,
        'speedX':   3,
        'speedY':   5,
        'distX':   10,
        'distY':   10
      },opt );
      
      this.each( function () {
        var _me = $(this);
        var cX = opt.centerX ? opt.centerX : _me.position().left; 
        var cY = opt.centerY ? opt.centerY : _me.position().top;
        var sX = Math.random()*360;
        var sY = Math.random()*360;
        var wm = 180/Math.PI;
        
        setInterval( function () {
          sX = (sX + opt.speedX)%360;
          sY = (sY + opt.speedY)%360;          
          var x = cX + opt.distX * Math.sin( sX/wm );
          var y = cY + opt.distY * Math.cos( sY/wm );
          _me.css({left:x, top:y});
        }, 40);
      });
    }
  });
  
})(jQuery);

Firefox ruckelt bei Skalierung eines Bilder mit jQuery

Großes Problem mit einfacher Lösung: Ich hatte versucht mit Hilfe des Monkey Patches für jQuery eine einfache Bildanimation zu machen. Das Bild sollte langsam größer skaliert werden:

var _time = new Date().getTime();
var iv = setInterval( function () {
   var f = (1 / 10000 * Math.min(10000, (new Date().getTime() - _time)));
   var s = 1.2 - 0.2 * f;
   $('.bild').scale( s );										
}, 30);

Sieht in Safari perfekt aus – aber Firefox, der sonst bei allen CSS3 Dingen eher pflegeleicht ist, skaliert das Bild katastrophal: Es ruckelt und wackelt unschön.

Die Lösung ist dämlich, aber zuverlässig: Zusätzlich zu der scale()-Anweisung auch das Bild leicht rotieren lassen mit rotate() – es reicht ein „unsichtbarer“ Wert von 0.1 damit das Bild sauber in Firefox skaliert wird:

var _time = new Date().getTime();
var iv = setInterval( function () {
   var f = (1 / 10000 * Math.min(10000, (new Date().getTime() - _time)));
   var s = 1.2 - 0.2 * f;
   $('.bild').scale( s );
   $('.bild').rotate( 0.1 * f );										
}, 30);

Nach AJAX-Response mit jQuery können Formular-Daten nicht mehr gelesen werden

Klasse Phänomen mal wieder: Ich habe ein DIV gebaut, dass ein Formular mit einer SELECT-Box enthält. Bei Auswahl einer Option in der SELECT-Box wird per jQuery.ajax(); das DIV neu geladen und dynamisch im Inhalt ersetzt. Klappt bei allen Browsern super – nur der IE8 hat mich den Vormittag gekostet, bis ich mir den Response mal genau angeschaut hatte.

Das Formular bestand – vereinfacht dargestellt – aus folgendem Code:

Der jQuery-AJAX-Code sah ungefähr so aus:

var formular = $('.mein_formular form');
formular.find('select').change( function () {
   $.ajax( { url: formular.attr('action')+'?'+formular.serialize(), 
		 success: function ( data ) {
			$('.mein_formular').html( $('.mein_formular', data).html() );
                 }
   });

Im Internet Explorer 8 konnte ich den Ajax-Befehl genau ein Mal aufrufen, danach kam ich nicht mehr an die Daten von formular.serialize() heran. Erst ein genauer Blick in den Response brachte es heraus:
Der Befehl $(‚.mein_formular‘, data).html(); bringt in allen Browsern – außer IE8 – dieses richtige Ergebnis:

...
...
...

Also: Alles korrekt. Im IE8 aber entfernt jQuery.html(); aus irgendeinem irrsinnigen Grund die Anführungszeichen der Tag-Attribute und macht daraus:

...
...
...

Und das wiederum interpretiert IE8 durch den Slash am Ende von ziel/ als Schliessen des Tags! Also so:

...
...

Konsequenz: Keine Chance, an die Daten eines leeren Formulars zu kommen. Vielen Dank, Microsoft!
Und die Lösung dazu? jQuery.html() nicht verwenden, sondern .contents() – mal wieder ein paar Buchstaben, die einem den halben Tag Nerven geraubt haben:

$('.mein_formular').html( $('.mein_formular', data).contents() );

Oder – alternativ – einfach das .html() weglassen – allerdings wird dann evtl. das umschliessende DIV gedoppelt.

$('.mein_formular').html( $('.mein_formular', data) );

jQuery: Nach Ajax-Response script-Tags in bestimmten DIVs ausführen

Beim Laden über die schöne jQuery.ajax()-Funktion wollten wir nicht nur die Inhalte eines bestimmten DIVs austauschen, sondern auch alle JavaScripte im neuen DIV ausühren. Leider werden alle Script-Tags automatisch „bereinigt“ bevor man sie in das DOM einfügen kann. Nach einigen Versuchen kamen wir dann auf folgende Lösung.

$.ajax({
   url: "http://....",
   success: function ( data ) {
     
      // Dieses DIV soll ersetzt werden - und alle script-Tags innerhalb des DIVs ausgeführt werden
      var target=".testdiv";	

      // Erst mal den Inhalt des DIVs mit dem neuen Inhalt ersetzen
      $(target).html( $(target, data).contents() );

      // Jetzt über ein paar Umwege die gewünschten Script-Tags innerhalb des DIVs finden und ausführen
      var div = document.createElement('div');
      div.innerHTML = data;
      var ref = $($(div).find(target).html());
      ref.filter('script').each(function () {
         $.globalEval(this.text || this.textContent || this.innerHTML || '');
      });
   }
});

Für Suchmaschinen: „jQuery Ajax Script-Tag“ „execute script tags jquery ajax response“ „script tags ajax response“ „script in div ajax response“ „einzelne script-Tags ausführen jquery ajax“ „jquery script clean“ „ajax javascript script ausführen“

Flash Reload Problem jQuery IE Internet Explorer

Eine Stunde Kopfschmerzen: Ich lade per jQuery-Ajax den Inhalt einer neue Seite und füge ihn nach dem Laden über diese Zeile ins DOM ein. Das Problem: Alles JavaScripte des neuen, geladenen Dokumentes werden im IE8 automatisch ausgeführt, sobald er den Befehl $(‚.content‘, data) ausführt.
Bei unserem Projekt führte das zu Problemen, da über swfobject ein Flash-Film im DOM eingefügt wurde und so bei jedem Nachladen eines Inhaltes über AJAX auch der Flash-Film neu eingebettet wurde und von vorne startete:

// Laden des Inhalts per jQuery AJAX
$.ajax({  url: 'http://www.meineurl.de', success: function (data) {
      $('.content').html( $('.content', data).html() );
}});

Damit es keinen Reload des Flash-Films gibt, bestand die Lösung darin, über eine RegEx alle Script-Tags aus der Ajax-Rückgabe zu entfernen und dann erst zu parsen bzw. ins DOM einzufügen:

 // Laden des Inhalts per jQuery AJAX
$.ajax({  url: 'http://www.meineurl.de', success: function (data) {
 data = data.replace(/]*?>[\s\S]*?<\/script>/gi, '');
      $('.content').html( $('.content', data).html() );
}});

Zweites Phänomen: Der Flash-Film war in ein DIV eingebettet und das DIV wurde über jQuery dynamisch skaliert. Die Skalierung des DIVs führte in bestimmten Browsern ebenfalls zu einem Reload / Refresh des Flash-Films. Dieses Problem ließ sich relativ leicht über eine Anpassung im CSS des DIVs lösen:

.container_um_das_swf {
     height: 200px;
     overflow: hidden !important;
}

Pfad zum aktuellen JavaScript ermitteln

Problem: Ich will den Pfad zu dem aktuellen Javascript ermitteln. Nehmen wir an, ich habe ein Javascript unter dem Pfad /fileadmin/templates/js/script.js liegen und möchte über ein Script darin den Pfad „fileadmin/templates/js/“ ermitteln. In PHP ist das ja relativ leicht über den Befehl $_SERVER[’SCRIPT_NAME’] bzw. die magische Konstante dirname(__FILE__) zu lösen. Leider gibt es keinen vergleichbaren Befehl in JavaScript.

Ein kleiner Workaround macht es zumindest dann möglich, wenn das Script über einen <script>-Tag eingebunden wurde, also an irgendeiner Stelle im HTML-Quelltext steht. Dazu hilft ein kleiner jQuery-Einzeiler von 99°:

// Pfad zu einem JS zurückgeben
(function($){$.extend({'getJSPath': function ( file ) {return $('script[src$="'+file+'"]').attr('src').replace(file, '');}});})(jQuery);

Die Funktion kann dann so aufgerufen werden:

var path = $.getJSPath('script.js');
alert( path );

In dem Beispiel würde sich ein Fenster öffnen mit dem Text „fileadmin/templates/js/“.

Internet Explorer IE 7 / IE 8 transparente PNGs

Beim fadeIn() oder fadeOut() mit jQuery erscheint im Internet-Explorer 7 und 8 immer noch ein schwarzer Rand um transparente 24-bit PNGs. Ich habe viele Lösungen gesehen, von denen nicht wirklich alle funktionieren.
Hier die 99°-Lösung, die sich sowohl um Hintergrundbilder als auch Bilder im IMG-Tag kümmert.

Der Trick dabei ist eine Kombination aus einem transparenten Hintergrundverlauf und zoom:1 der im IE hasLayout auslöst.

Da ich nicht weiß, wie der IE9+ mit PNGs umgeht, habe ich es auf IE7 und IE8 beschränkt. Die Zeile läßt sich aber auch schnell ändern…

Hier ist eine Online-Testseite

(function($){

	// 99° IE 7/8 fading PNG fix
	$.extend({
		'pngFix': function ( obj ) {
			var vs = parseFloat($.browser.version);
			if (!$.browser.msie || ($.browser.msie && vs < 7 || vs > 8)) return;
			var magic = ';-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF)";filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);zoom: 1;';
			var clone = ['background-image', 'background-position', 'background-repeat', 'width', 'height'];
			var arr = $('*').filter(function() {
				if (this.nodeName == 'IMG' && $(this).attr('src').indexOf('.png') > -1) return true;
				return (this.currentStyle ? this.currentStyle['backgroundImage'] !== 'none' : document.defaultView.getComputedStyle(this,null).getPropertyValue('background-image') !== 'none');
			});
			$(arr).each( function () {
				
				if (this.nodeName != 'IMG') {
					var ref = $(this);
					ref.wrapInner('
'); $(clone).each( function ( k, v ) { ref.find('.pngfix').css( v, ref.css(v) ); }); ref.css({'background-image':'none'}); ref.find('.pngfix').attr('style', (''+ref.find('.pngfix').attr('style')).split(magic).join('')+magic ); } else { $(this).attr('style', (''+$(this).attr('style')).split(magic).join('')+magic ); } }); } }); })(jQuery); $(function () { $.pngFix(); });