Felix Riesterer: Fader zum Bilder überblenden - ein kleiner Lehrgang

3 52

Fader zum Bilder überblenden - ein kleiner Lehrgang

Felix Riesterer
  • javascript
  1. 2

    Das Script (Teil1)

    Felix Riesterer
    1. 1

      Das Script (Teil1) - Reflektion zum Code

      Felix Riesterer
      1. 0
        bosselmann
        1. 0
          Felix Riesterer
    2. 2

      alternativer loesungsansatz (teil1): model, view, ...

      peterS.
      1. 0

        alternativer loesungsansatz (teil2): .., controller.

        peterS.
        1. 0

          alternativer loesungsansatz (teil2): code review (teil 1?)

          peterS.
          1. 0

            alternativer loesungsansatz (teil2): code review (teil 2?)

            peterS.
            1. 0

              alternativer loesungsansatz (teil2): code review (teil 3)

              peterS.
      2. 0
        Felix Riesterer
        1. 0

          konkurrierende ansaetze

          peterS.
          1. 0
            Felix Riesterer
  2. 0

    SELFHTML-Artikel statt Forumsbeitrag?

    Vinzenz Mai
    • meinung
    1. 0
      Felix Riesterer
      1. 0
        Siechfred
        1. 0
          Felix Riesterer
        2. 0

          SELFHTML-Artikel - bin schon fleißig dabei!

          Felix Riesterer
        3. 0

          Artikel eingeschickt

          Felix Riesterer
          1. 0
            Siechfred
            • menschelei
            1. 0
              dedlfix
            2. 1
              Felix Riesterer
    2. 0
      Felix Riesterer
  3. 0

    Das Script (Teil 2)

    Felix Riesterer
  4. 0

    Das Script (Teil 3)

    Felix Riesterer
  5. 0

    Das Script (Endergebnis)

    Felix Riesterer
    1. 1
      molily
      1. 0
        Felix Riesterer
        1. 0
          Struppi
          1. 0
            Felix Riesterer
            1. 0
              bosselmann
              1. 0
                Felix Riesterer
                1. 0

                  Falscher Thread-Zweig...:-/

                  Felix Riesterer
                  1. 0

                    Verständnisfragen

                    bosselmann
                    1. 0
                      Felix Riesterer
                      1. 0
                        bosselmann
                        1. 0
                          Felix Riesterer
                          1. 0
                            bosselmann
                            1. 0
                              Felix Riesterer
                              1. 0

                                Skriptergänzung

                                bosselmann
                                1. 0
                                  Felix Riesterer
                                  1. 0

                                    Skriptergänzung (finale Version)

                                    bosselmann
                                    1. 0
                                      Felix Riesterer
  6. 0
    Felix Riesterer
    1. 0
      Beat
      1. 0

        Review-Version des Lehrgangs

        Felix Riesterer
        1. 0
          Beat
          1. 0
            Felix Riesterer
        2. 0
          Struppi
          1. 0
            Felix Riesterer
            1. 0
              Struppi
              1. 0
                Felix Riesterer

Liebes Forum,

da gerade zwei Threads zum Thema "Bild überblenden" laufen (Thread1, Thread2), und sich zwei Interessenten gefunden haben, die mehr zum Schreiben eines JavaScripts lernen wollen, dachte ich mir, ich könnte das hier im Forum machen, sodass mehrere Leute die Chance haben, hier ihr Wissen auszutauschen und dazuzulernen.

Ich jedenfalls habe durch meine Beschäftigung mit diesem Thema wieder eine Menge selbst dazugelernt.

Ziel dieses "Lehrgangs": Ein JavaScript, das aus einer externen Datei in ein Dokument eingebunden werden kann, sich dort selbst initialisiert, und das ein vorhandenes Bild in eine Art Bilder-Slideshow umwandeln kann. Dabei soll es genügend modular aufgebaut sein, damit man auch Teile daraus explizit aufrufen kann, um einmalig ein Bild in ein anderes überzublenden. Zuguterletzt sollen mehrere solche Slideshows auf einer Seite möglich sein.

Nennen wir der Einfachheit halber den Slideshow-Mechanismus, den das Script bereitstellen soll, "Fader".

Um unser Ziel zu erreichen, sollten ein paar Voraussetzungen geklärt werden:

1.) Wenn JavaScript nicht verfügbar sein sollte, dann darf im Dokument keine "Lücke" sein. Daher setzten wir ein Bild voraus, welches sinnvollerweise mit einer ID versehen sein muss, damit wir unseren Fader für dieses Bild mit den dafür benötigten (individuellen!) Einstellungen einrichten können.

2.) Das Script muss "unobtrusive" (zu deutsch etwa "dezent", oder "unaufdringlich") werden, sodass also im HTML-Dokument (zumindest im <body>) kein JavaScript-Code notiert wird. Das bedeutet, dass Der Aufruf zum Beispiel so geschehen könnte:

~~~javascript FaderFramework.init({
        id: "fader_test_1",                            // ID des vorhandenen <img />-Elements
        images: ["images/pic1.jpg", "images/pic2.jpg"] // Array der Bilder, in die übergeblendet werden soll
    });

  
    Dieser Code könnte natürlich auch in einer externen JavaScript-Datei stehen, die natürlich nach dem eigentlichen Fader-Script eingebunden werden müsste, oder er könnte dynamisch aus irgendeinem anderen Script generiert werden, oder oder oder.  
  
3\.) Das Script muss für jeden gewünschten Fader ein eigenes Objekt anlegen, das sowohl das Manipulieren des/der <img />-Elemente handhabt, als auch die Funktionen bereitstellt, die das manuelle Aufrufen für einmalige (eventuell auf Userklick hin ausgelöste?) Überblendungen ermöglichen.  
  
4\.) Für die Überblendungen wird es notwendig sein, dass die Bilder sich alle überlagern, damit der Wechsel möglich wird. Dazu ist es sinnvoll, eine externe CSS-Datei mit den notwendigen Klassen zu definieren, in denen die Styles für diesen Zweck definiert werden. Der Hintergrund ist der, dass das dynamische Zuweisen von CSS-Eigenschaften in JavaScript in der Menge immer mühsamer wird, während das dynamische Zuweisen von Klassen deutlich einfacher (und auch schneller) geht.  
    Eine solche CSS-Datei müsste unser Script dann selbst in das HTML-Dokument nachladen, falls JavaScript nicht verfügbar sein sollte.  
  
So, jetzt kann es losgehen.  
  
Ich lege zum Arbeiten einen neuen Ordner ("Testordner") an. In diesem Ordner erstelle ich zwei Unterordner: "fader-framework" und "images".  
In den Unterordner "images" speichere ich ein paar Bilder, die in einem Fader nacheinander angezeigt werden sollen. Die von mir verwendeten Bilder darf sich gerne jeder, der an diesem Lehrgang interessiert ist, bei mir herungerladen: [fader-images.zip](http://www.felix-riesterer.de/self/fader-images.zip) (469KB)  
Im Unterordner "fader-framework" lege ich zwei neue Textdateien an: "fader-framework.js" und "fader-framework.css"  
  
Nun schreibe ich ein kleines HTML-Dokument, welches ich in unserem Arbeitsordner speichere und welches das JavaScript dann aus dem Unterordner "fader-framework" einbinden wird. Ich greife hier schon etwas vor und notiere meine fertige Test-Datei, mit der ich hier im weiteren Verlauf mein Script testen werde.  
  
(Datei "Testordner/index.html")  
~~~html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">  
    <head>  
        <title>Fader-Test</title>  
        <script type="text/javascript" src="fader-framework/fader-framework.js"></script>  
        <script type="text/javascript">
            // ersten Fader einrichten  
            FaderFramework.init({  
                id: "fader_test_1",  
                images: ["images/biggrin.gif","images/blink.gif","images/cool.gif","images/dry.gif","images/huh.gif","images/lol.gif","images/rolleyes.gif","images/tongue.gif"],  
                fadeStep: 1,  
                random: true  
            });  
  
            // zweiten Fader einrichten  
            FaderFramework.init({  
                id: "fader_test_2",  
                images: ["images/sonne1.jpg", "images/sonne2.jpg", "images/sonne3.jpg", "images/sonne4.jpg"],  
                viewTime: 6000,  
                fadeStep: 0.25  
            });
        </script>  
    </head>  
    <body>  
        <h1>Fader-Framework-Test</h1>  
        <p>Bei dieser Lösung muss ein Bild <img src="images/biggrin.gif" alt="" id="fader_test_1" /> mit ID als Platzhalter verwendet werden, damit es zu einem Fader umgebaut werden kann.</p>  
        <p><img src="images/sonne1.jpg" alt="" id="fader_test_2" /></p>  
        <p>Wie man sieht, gelingen mehrere Fader auf derselben Seite.</p>  
    </body>  
</html>

So. Nun widme ich mich der CSS-Datei, die ich im Unterordner "fader-framework" angelegt habe.

Was muss in diese CSS-Datei hinein? Dazu ein paar kurze Überlegungen:

1.) Das ursprüngliche Bild wird ersetzt werden müssen, denn damit mein Script sinnvoll zu realisieren ist, sollte es ein eigenes Element (hier ein <span>-Element) benutzen, in welches es alle Bilder des Faders hineinschreibt. Dieses Element erhält von uns dann eine Klasse, in meinem Beispiel "fader".

2.) In unserem <span>-Element werden sich beliebig viele Bilder tummeln, die alle übereinandergestapelt positioniert sein müssen, damit ein Überblenden an Ort und Stelle geschehen kann, denn sonst werden diese Bilder nebeneinander, oder bei zu wenig Platz auch untereinander angeordnet. Deshalb müssen alle Bilder per CSS übereinander gelegt werden.

3.) Wenn in meinem <span>-Element ein zweites Bild über mein erstes Bild soll, dann muss ich es absolut positionieren, damit es aus dem Elementfluss genommen wird und keinen weiteren Platz beansprucht. Alle weiteren Bilder ebenso. Das erste Bild muss aber im Elementfluss bleiben, da sonst unser <span>-Element keine Ausmaße hätte (es wäre ja vom Elementfluss her betrachtet ansonsten leer). Daher verwenden wir eine Klasse namens "next", um zu zeigen, dass dieses spezielle Bild nicht das erste Bild im <span>-Element ist.
    Eigentlich wäre das nicht notwendig, wenn alle Browser die Pseudo-Eigenschaft "http://de.selfhtml.org/css/eigenschaften/pseudoformate.htm#first_line_letter_child@title=:first-child" zufriedenstellend interpretieren könnten, daher ist diese Klasse, die unser Script dann an die entsprechenden Bilder vergeben muss, ein Workaround.

4.) Absolut positionierte Elemente beziehen sich immer auf das <body>-Element, wenn keines ihrer Vorfahren irgendwie anders positioniert ist (z.B. durch float oder position:relative/absolute), sodass unser <span>-Element künstlich in seiner Positionierung verändert werden muss. Wir setzen es deshalb auf position:relative. Und wenn wir für die Eigenschaften "top", "right", bottom" und "left" keine Werte vergeben, dann bleibt unser relativ positioniertes <span>-Element genau da, wo es auch sonst, wäre - jedoch mit dem Vorteil, dass sich unsere absolut positionierten  Bilder innerhalb desselben, genau an seiner obersten linken Ecke ausrichten und von daher passgenau über unser erstes Bild zu liegen kommen. - Denkweise klar geworden?

Nun also unser CSS-Code (Datei "Testordner/fader-framework/fader-framework.css"):

.fader {  
    position: relative;  
}  
  
.fader img {  
    vertical-align: top;  
}  
  
.fader img.next {  
    position: absolute;  
    top: 0;  
    left: 0;  
}

Für den JavaScript-Teil findet mich die Forensoftware "etwas geschwätzig", sodass dieser im nächsten Posting stehen muss.

Diskussionen und Kommentare (insbesondere Verbesserungen) sind sehr willkommen.

Liebe Grüße aus Ellwangen,

Felix Riesterer.

--
ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  1. Es fehlt noch unsere eigentliche Baustelle: Unsere JavaScript-Datei mit unserem eigentlichen Script.

    Für diesen ersten Teil möchte ich nur ein sehr rudimentäres Script anbieten, welches im nächsten Teil weiter ausgebaut werden wird.

    Auch hier wieder ein paar Überlegungen:

    1.) Das Script sollte als ein großes Objekt definiert werden, damit wir alle unsere Variablen nicht als globale Einzelvariablen im Dokument "herumliegen" haben, sondern damit alles, was mit unserem Script zu tun hat, auch unter dessen Namen zu finden ist. Deshalb definieren wir eine globale Variable, nämlich unser großes Objekt. Nennen wir es "FaderFramework", denn es ist ja eine Rahmenapplikation, die uns individuelle Fader herstellen und bereitstellen kann.
        An dieser Stelle empfehle ich sehr dringlich, im Firefox mit dem Firebug-Plugin zu arbeiten. Mit dem Firebug kann man sich sehr bequem anschauen, welche Variablen und Funktionen im Dokument definiert worden sind.

    2.) Das Script soll sich nach dem Einbinden über ein <script>-Element selbst initialisieren. Das darf nicht dadurch geschehen, indem wir <body onload="FaderFramework.onload()"> notieren, da damit unser Ziel mit dem "unobtrusive" nicht erreicht wäre. Außerdem könnten andere Scripte, die sich ähnlich nach dem Laden selbst starten sollen, ebendieses nicht (mehr). Also lösen wir das anders, nämlich über das window-Objekt und dessen onload-Eigenschaft bzw. -Methode.

    3.) Falls in window.onload bereits eine Funktion abgelegt worden sein sollte, dann müssen wir sicherstellen, dass diese Funktion weiterhin nach dem Laden des Dokuments ausgeführt wird. Aber es soll ja auch unsere Funktion dazu ausgeführt werden! Das lösen wir, indem wir einfach eine neue Funktion definieren, in der wir zuerst die alte Funktion aufrufen, um dann unsere Funktion ausführen zu lassen.
        Damit sich das Ganze nicht in die Quere kommt, müssen wir erst den Inhalt von window.onload in einer Variablen abspeichern. Dazu benutzen wir unser großes FaderFramework-Objekt, dem wir einfach eine Eigenschaft "oldWinOnLoad" verpassen, in die wir den gegenwärtigen Inhalt von window.onload abspeichern. Später können wir dann wieder darauf zurückgreifen (siehe unten).

    Hier eine erste Version unseres FaderFrameworks (Datei "Testordner/fader-framework/fader-framework.js"):

    var FaderFramework = {  
        oldWinOnLoad: false,        // hier steht später vielleicht eine abgespeicherte Funktion  
      
        // Initialisier-Funktion - startet das FaderFramework indem sie das onload-Verhalten im Dokument regelt (wird noch während des Ladens der Seite ausgeführt)  
        start: function () {  
            // "this" bezieht sich auf "FaderFramework"  
            this.oldWinOnLoad = window.onload; // alte onload-Funktion abspeichern (falls vorhanden)  
      
            // neue (anonyme!) onload-Funktion erstellen um eventuelle alte Funktion(en) zu kapseln  
            window.onload = function () {  
                // War bereits eine Funktion in window.onload abgelegt worden?  
                if (typeof(FaderFramework.oldWinOnLoad) == "function") {  
                    // hier kann man nicht "this" benutzen, da diese Funktion nicht zu einem größeren Objekt gehört!  
                    FaderFramework.oldWinOnLoad(); // gespeicherte onload-Funktion ausführen  
                }  
      
                FaderFramework.onload(); // unsere onload-Funktion ausführen  
            };  
        },  
      
      
        // onload-Funktion wird unmittelbar nach dem vollständigen Laden des Dokuments ausgeführt  
        onload: function () {  
            alert("Script geladen!");  
        },  
      
     // Funktion zum Einrichten eines Faders (wird noch während des Ladens der Seite ausgeführt - eventuell mehrmals)  
        init: function (einstellungen) {  
            alert("Noch kann kein Fader eingerichtet werden...");  
        }  
    }  
      
    FaderFramework.start();
    

    Liebe Grüße aus Ellwangen,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Für diejenigen, denen dieser erste Teil des Codes sehr fremd vorkommt, möchte ich hier ein paar Reflektionen anbieten.

      Zuerst möchte ich auf Mathias' (alias "mollily"s) SELFHTML-Artikel "Organisation von JavaScripten" verweisen, in dem sehr vieles zur Syntax und zur Logik hinter dem Aufbau eines JavaScripts nachzulesen ist. Diesen "Lehrgang" könnte man als eine konkrete Anwendung vieler der dort genannten Aspekte verstehen.

      Nun zu Teilen des Codes im Einzelnen:

      var FaderFramework = {

      Mit dieser Syntax (einem sogenannten Objekt-Literal) starten wir die Definition unseres großen Objektes. Dabei ist sehr zu beachten, dass am Ende kein Komma steht. Kommata werden benutzt, um innerhalb des Objektes dessen Eigenschaften (oder auch Funktionen/Methoden) voneinander zu trennen - jedoch darf nach der letzten Eigenschaft/Funktion/Methode eben _kein_ Komma mehr stehen, da sonst z.B. im Internet Explorer der JavaScript-Interpreter nach einer weiteren Eigenschaft sucht, diese aber nicht finden kann und deshalb mit einer Fehlermeldung abbricht - was wiederum zur Folge hat, dass unser Objekt dann nicht existiert.

      oldWinOnLoad: false, // hier steht später vielleicht eine abgespeicherte Funktion

      Hier definiere ich eine Eigenschaft namens "oldWinOnLoad" innerhalb des FaderFramework-Objektes (also "FaderFramework.oldWinOnLoad"), die den Wert false erhält. Da ich mich innerhalb der geschweiften Klammern des Objektliterals befinde, muss ich "FaderFramework." nicht (genauer: darf ich nicht!) davor notieren. Man beachte das Komma am Ende und den Doppelpunkt nach dem Namen der Eigenschaft! Diese beiden Details haben mit der JSON-Syntax zu tun, die hier bei einem Objektliteral zum Einsatz kommt.

      Dass ich diese Eigenschaft an dieser Stelle definiere, ist im Grunde unnötig, denn ich definiere diese Eigenschaft später erneut (was diese Definition überschreiben wird), führe sie hier der Übersichtlichkeit wegen aber explizit auf.

      Nun kommt der für Anfänger eher verwirrende Teil mit dem "Umbiegen" des "Autostarts" - dem "window.onload". In dieser Eigenschaft des http://de.selfhtml.org/javascript/objekte/window.htm@title=window-Objektes kann eine Funktion (besser: eine Referenz auf eine solche) abgelegt sein, die nach dem vollständigen Laden einer Seite (sprich: wenn alle Bild-, CSS- und sonstige Dateien geladen wurden) ausgeführt wird. Da wir unser Script dort eintragen wollen, dabei aber bereits eingetragene Funktionen nicht überschreiben wollen, müssen wir irgendwie diese Funktion (besser: die Referenz auf sie) speichern, um sie später wieder aufrufen zu können.

      ~~~javascript

      start: function () {

      // "this" bezieht sich auf "FaderFramework"
              this.oldWinOnLoad = window.onload; // alte onload-Funktion abspeichern (falls vorhanden)

        
      So. Nun haben wir die Referenz auf die eventuell bereits vorhandene Funktion in unserem FaderFramework-Objekt unter der Eigenschaft "oldWinOnLoad" gespeichert. Man beachte, dass oben bei window.onload kein Klammernpaar steht! Das bedeutet, dass wir die Referenz auf die Funktion in window.onload speichern (also die Funktion selbst), nicht etwa deren Rückgabewert. Hätten wir stattdessen  
              `FaderFramework.oldWinOnLoad = window.onload();`{:.language-javascript}  
      notiert, wäre in window.onload nur das abgelegt worden, was uns diese Funktion quasi als Ergebnis zurückliefern würde.  
        
      Anstatt nun window.onload() aufzurufen (mit dem Klammernpaar!), könnten wir nun auch mit  
              `FaderFramework.oldWinOnLoad()`{:.language-javascript}  
      denselben Effekt erreichen. Das ist auch genau das, was wir wollen: Eine Möglichkeit, die ursprünglich in window.onload vorhandene Funktion \_anders\_ aufrufen zu können.  
        
      Da wir nun die bisherige Funktion aus window.onload "gerettet" haben, können wir window.onload neu befüllen, ohne dass uns jetzt etwas verloren ginge. Und genau das machen wir jetzt. Mittels einer simplen Zuweisung speichern wir in window.onload eine neue Funktion ab. Da wir ihr aber keinen Namen geben (wozu auch?), unter dem sie irgendwo abgelegt wäre (wie z.B. FaderFramework.init oder window.alert), nennt man sie eine anonyme Funktion.  
        
      
      >         ~~~javascript
      
      // neue (anonyme!) onload-Funktion erstellen um eventuelle alte Funktion(en) zu kapseln  
      
      >         window.onload = function () {  
      >             // War bereits eine Funktion in window.onload abgelegt worden?  
      >             if (typeof(FaderFramework.oldWinOnLoad) == "function") {  
      >                 // hier kann man nicht "this" benutzen, da diese Funktion nicht zu einem größeren Objekt gehört!  
      >                 FaderFramework.oldWinOnLoad(); // gespeicherte onload-Funktion ausführen  
      >             }  
      >   
      >             FaderFramework.onload(); // unsere onload-Funktion ausführen  
      >         };  
      >     },
      
      

      Jetzt haben wir sichergestellt, dass nach dem Laden der Seite andere "Autostart-Funktionen" ausgeführt werden, und zwar _vor_ unserem "Autostart". Das ist "unobtrusive", sprich unaufdringlich.

      Die restlichen Funktionen (besser "Methoden") unseres Objektes sind in diesem ersten Teil nur Platzhalter, um zu zeigen, wie es weitergehen wird.

      Bitte unbedingt hier Posten, wenn es Verbesserungen gibt, die hier berücksichtigt werden sollten! Selbstverständlich sind ebenso Verständnisfragen sehr willkommen.

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Sehr schön, wann kommt Teil 2?

        1. Lieber bosselmann,

          Sehr schön, wann kommt Teil 2?

          konntest Du denn alles nachvollziehen? Ich vermisse Verständnisfragen... aber vielleicht kommen die erst noch. Teil 2 kommt heute im Verlauf des Tages.

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    2. gruss Felix,

      Dein angagement verdient unterstuetzung, und weil Du ausdruecklich darum
      bittest, folgen nun meinereinige hinweise und kritiken:

      1.) Das Script sollte als ein großes Objekt definiert werden, damit
      wir alle unsere Variablen nicht als globale Einzelvariablen im Dokument
      "herumliegen" haben, ... Deshalb definieren wir eine globale Variable,
      nämlich unser großes Objekt. Nennen wir es "FaderFramework", denn es ist
      ja eine Rahmenapplikation, die uns individuelle Fader herstellen und
      bereitstellen kann.

      dem ansatz nach sollen ja eine bis mehrere *eierlegende wollmilch*-slideshows
      ueber eine komfortable (moeglichst generische) initialisierung erstellt werden.
      eine unter vielen eigenschaften, die eine solche slideshow auszeichnen werden,
      ist der fade-effekt beim ueberblendenden bildwechsel. deswegen wuerde ich einen
      [SlideshowGenerator] bauen, der instanzen eines [[Slideshow]]-konstruktors
      erzeugt. eine *sichtbarkeit* aller objekte in den globalen [window]-namensraum
      ist keineswegs notwendig, weshalb ich die gesamte anwendung in eine umgehend
      aufzurufende anonyme funktion packen wuerde, die einmalig eine oeffentliche
      methode zum importieren von slideshow-daten zur verfuegung stellt, welche sich
      wiederum sofort nach ihrem aufruf selbst entsorgt.

      2.) Das Script soll sich nach dem Einbinden über ein <script>-Element
      selbst initialisieren. Das darf nicht dadurch geschehen, indem wir
      <body onload="FaderFramework.onload()"> notieren, ...
      lösen wir das anders, nämlich über das window-Objekt und dessen onload-
      Eigenschaft bzw. -Methode.

      das ist keineswegs optimal und fuehrt zum unnoetigen aufwand in 3) ...

      3.) ... ff.

      .., dessen grundproblem sich auch mit bordmitteln noch kurz genug loesen
      laesst, falls man zur umsetzung des gesamten projekts auf bibliotheken wie
      »jquery« oder frameworks wie die »YUI-lib« vezichten will/muss, wozu ich
      bei umfangreicheren *dom-scripting-tasks* aber nicht raten wuerde.

      mein loesungsansatz saehe folgendermassen aus:

      html-slideshow-substruktur:

      <div class="slideshow">  
        <img class="slide" src="img/slide02.jpg" alt="bla" title="blub" />  
        <span class="control" title="Please click yourself through.">  
          <a class="previous" href = "javascript://" ><span>previous picture</span></a>  
          <a class="next" href="javascript://"><span>next picture</span></a>  
        </span>  
      </div><!-- class="slideshow" //--><!--  
        
      ...  
      ...  
        
      //-->  
      <div class="slideshow">  
        <img class="slide" src="img/slide05.jpg" alt="bla" title="blub" />  
        <span class="control" title="Please click yourself through.">  
          <a class="previous" href = "javascript://" ><span>previous picture</span></a>  
          <a class="next" href="javascript://"><span>next picture</span></a>  
        </span>  
      </div><!-- class="slideshow" //-->
      

      dazugehoerige css-regeln:

      div.slideshow {  
        position: absolute;  
        left: 0;  
        top: 0;  
      }  
        div.slideshow img.slide {  
          display: block;  
          width: 175px;  
          height: 103px;  
          background-color: #cf0;  
        }  
        div.slideshow img.slide.blend {  
          position: relative;  
          left: 0;  
          top: -103px;  
        }  
        div.slideshow span.control {  
          position: absolute;  
          display: none; /* "block" needs to be set by js-controller \*/  
          left: 59px;  
          top: 83px;  
          width: 60px;  
          height: 15px;  
          color: #8898a8;  
          text-align: center;  
          background: transparent url(../img/elements/elm-slideshow-control.png) scroll no-repeat left top;  
        }  
        * html div.slideshow span.control { /* msie 6.x css filter \*/  
          background-image: url(../img/elements/elm-slideshow-control.gif);  
        }  
          div.slideshow span.control span {  
            position: relative;  
            top: -2px;  
            font-size: 80%;  
            line-height: 96%;  
          }  
          div.slideshow span.control a {  
            position: absolute;  
            display: block;  
            top: 0;  
            width: 19px;  
            height: 100%; /* 15px \*/  
          }  
          div.slideshow span.control a.previous {  
            left: 0;  
          }  
          div.slideshow span.control a.next {  
            right: 0;  
          }  
            div.slideshow span.control a span {  
              display: none;  
            }
      

      ... to be continued ...

      so long - peterS. - pseliger@gmx.net

      --
      »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
      Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
      ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
      1. hallo again Felix,

        ...
        die alles steuernde applikation auf basis von JavaScript 1.6 bis 1.8 bzw.
        auf basis selbstgetrickter erweiterungen, die unter anderem auch einige
        dieser features nach-/abbilden (die YUI-lib basis wurde auskommentiert):

        //  [Array.generics.iterators.accessors]      - [http://www.pseliger.de/jsExtendedApi/jsApi.Array.mozGenerics.dev.js] september 23-2006:  
        Array.forEach = (function (obj, fct) {if(typeof fct=="function"){var i,l=(((obj instanceof Array)||((typeof obj.length=="number")&&((typeof obj.item=="function")||(typeof obj.item=="object")||(typeof obj.item=="string")||(obj instanceof window.NodeList)||(obj instanceof window.HTMLCollection))))?(obj.length):(0));for(i=0;i<l;++i){fct.call(null,(obj[i]||obj.item(i)),i,obj);}}}); // generic.  
          
        String.prototype.toRegExpString = (function () {return this.replace(/([\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}])/g,"\\$1");}); // prototypical.  
        //RegExp.toSearchString = (function (str) {return (new String(str)).replace(/([\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}])/g,"\\$1");}); // generic.  
          
          
        //to be used whilst state of development only:  
        if (typeof Object.prototype.toSource != "function") {Object.prototype.toSource = Object.prototype.toString;}  
          
          
          
        (function () { // anonymus application context.  
          
          
          
        //var Application = YAHOO.namespace("SlideshowGenerator");  
          (window || this)["SlideshowPlugin"] = {}; // generate global namespace [SlideshowPlugin].  
          var Application = SlideshowPlugin;  
          
          
        //var Lang, Dom, Evt, Elm, Anim, Easing, Slct; // shortcuts referencing !YAHOO User Interface Library modules.  
          
          var elmBody;  
          
          
        //to be used whilst state of development only:  
          console = (((typeof console != "undefined") && console.log) ? (console) : ({log:(function(msg){/*alert(msg);*/})}));  
          
          
          
          var SlideshowGenerator = (function () { // [SlideshowGenerator] Singleton.  
          
          
            var slideshowData, slideshowList = [], counterDivider = " / ";  
          
          
            var Slideshow = (function (elm, idxOfSlideshowElm) { // [Slideshow] Constructor (no public properties at all).  
          
          
              var slideList, amountOfSlides, idxSlide = -1;  
          
              var elmSlide = elm.getElementsByTagName("img")[0];  
              var elmControl = elm.getElementsByTagName("span")[0];  
            //var elmPrevious = [link:http://developer.yahoo.com/yui/docs/YAHOO.util.Dom.html#method_getElementsByClassName@title=Dom.getElementsByClassName]("previous", "a", elmControl)[0]; // YUI-lib;  
            //var elmNext = Dom.getElementsByClassName("next", "a", elmControl)[0];  
            //var elmPrevious = [link:http://www.pseliger.de/jsExtendedApi/jsApi.bundles.DOM.getters.js@title=Node.getElementsByClassNames](elmControl, "previous")[0]; // [jsApi.bundles.DOM.getters.js]  
            //var elmNext = Node.getElementsByClassNames(elmControl, "next")[0];  
              var controls = elmControl.getElementsByTagName("span");  
              var elmPrevious = controls[0];  
              var elmNext = controls[1];  
              delete controls;  
          
              var elmCounterCopy = elmControl.appendChild(document.createElement("span"));  
              elmCounterCopy = elmCounterCopy.appendChild(document.createTextNode("n" + counterDivider + "m"));  
          
          
              var elmSlideBlend = elmSlide.cloneNode(true);  
            //[link:http://developer.yahoo.com/yui/docs/YAHOO.util.Dom.html#method_addClass@title=Dom.addClass](elmSlideBlend, "blend"); // YUI-lib;  
              elmSlideBlend.className = (elmSlideBlend.className + " blend");  
              elmSlide.parentNode.insertBefore(elmSlideBlend, elmControl);  
          
            //var animFadeOut = new [link:http://developer.yahoo.com/yui/docs/YAHOO.util.Anim.html@title=Anim](elmSlideBlend, {opacity: {to: 0, units: "%"}}, 0.3, [link:http://developer.yahoo.com/yui/docs/YAHOO.util.Easing.html#method_easeOut@title=Easing.easeOut]); // YUI-lib;  
          
          
              var refreshCounter = (function () {  
          
                elmCounterCopy.data = ((idxSlide + 1) + counterDivider + amountOfSlides);  
              });  
              var onNext = (function () {  
                // ...  
              });  
              var onPrevious = (function () {  
                // ...  
              });  
          
          
              (function () { // anonymus [initialize].  
          
                slideList = slideshowData[idxOfSlideshowElm];  
                amountOfSlides = slideList.length;  
          
                for (var regXDataSrc = (/\s/), src = elmSlide.src, len = slideList.length, i = 0; i<len; ++i) {/*  
          
                  console.log("i : " + i + " - regXDataSrc : " + regXDataSrc.compile(arr[i].toRegExpString(), "i"));  
                  console.log("regXDataSrc.test(\"" + src + "\") : " + regXDataSrc.compile(arr[i].toRegExpString(), "i").test(src));*/  
                  if (regXDataSrc.compile(arr[i].toRegExpString(), "i").test(src)) {  
          
                    idxSlide = i;  
                    break;  
                  }  
                }  
                idxSlide = ((idxSlide == -1) ? (0) : (idxSlide));  
          
                refreshCounter();  
          
                elmPrevious.onclick = onPrevious;  // [link:http://developer.yahoo.com/yui/docs/YAHOO.util.Event.html#method_on@title=Evt.on](elmPrevious, "click", onPrevious); // YUI-lib;  
                elmNext.onclick = onNext;          // Evt.on(elmNext, "click", onNext);  
          
              //[link:http://developer.yahoo.com/yui/docs/YAHOO.util.Dom.html#method_setStyle@title=DOM.setStyle](elmControl, "display", "block"); // YUI-lib;  
                elmControl.style.display = "block";  
          
                delete arguments.callee; // throwing away anonymus [initialize].  
              })();  
          
            }); // [Slideshow] Constructor  
          
          
            return {  
          
              importData: (function (obj) {  
          
                slideshowData = obj;  
          
              //console.log("SlideshowGenerator :: importData :: slideshowData.dump() : " + [link:http://developer.yahoo.com/yui/docs/YAHOO.lang.html#method_dump@title=Lang.dump](slideshowData)); // YUI-lib;  
                console.log("SlideshowGenerator :: importData - slideshowData.dump() : " + slideshowData.toSource());  
                console.log("SlideshowGenerator :: importData - (SlideshowGenerator.importData === arguments.callee) ? " + (SlideshowGenerator.importData === arguments.callee));  
          
                delete Application.importSlideShowData;  
                delete SlideshowGenerator.importData;  
                delete arguments.callee;  
              }),  
              initialize: (function (elm) {  
          
                Array.forEach(Dom.getElementsByClassName("slideshow", "div", elmResults), (function (elm, idx/*, arr*/) {  
          
                  slideshowList.push(new Slideshow(elm, idx));  
                }));  
                console.log("SlideshowGenerator - Application.importSlideShowData : " + Application.importSlideShowData);  
                console.log("SlideshowGenerator :: importData : " + SlideshowGenerator.importData);  
          
                delete SlideshowGenerator.initialize;  
                delete arguments.callee;  
              })  
            };  
          
          })(); // [SlideshowGenerator] Singleton.  
          
          Application.importSlideShowData = SlideshowGenerator.importData;  
          
          
          
          var initialize = (function () { // initialize application.  
          
              elmBody = (document.body || document.getElementsByTagName("body")[0]);  
          
              //  [document.getRenderEngineType] - [http://www.pseliger.de/jsExtendedApi/jsApi.bundles.DOM.getters.dev.js] as of september-07-2007:  
              document.isRenderEngineKHTML = (function () {return((typeof elmBody.style.KhtmlOpacity!=="undefined")&&(typeof elmBody.style.KhtmlOpacity==="string"));});  
          
              //  [RegExp.prototype.compile]     - [http://www.pseliger.de/jsExtendedApi/jsApi.bundles.DOM.getters.dev.js] as of september-07-2007:  
              if (((typeof RegExp.prototype.compile != "function") && (typeof RegExp.prototype.compile != "object")) || document.isRenderEngineKHTML()) {RegExp.prototype.compile = (function () {return this.constructor.apply(this, arguments);});} // due to a safari bug that does not implement the native JavaScript RegExp method [RegExp.compile] properly;  
          
          
              SlideshowGenerator.initialize();  
          
          
              delete initialize;  
              delete arguments.callee; // [arguments.callee] should be identic to [initialize], even though deletion only takes place if called directly by label instead by the more generic [arguments.callee].  
          });/*  
          
          
          [link:http://developer.yahoo.com/yui/docs/YAHOO.util.Event.html#method_onContentReady@title=Evt.onContentReady]("htmlElementId", (function () { // YUI-lib;  
            // ...  
          }));  
          [link:http://developer.yahoo.com/yui/docs/YAHOO.util.Event.html#method_onDOMReady@title=Evt.onDOMReady](function () { ... */ // YUI-lib;  
          
          (function () { // initialize application automatically.  
          
            if (window.addEventListener) {  
              window.addEventListener("load", initialize);  
            } else if (window.attachEvent) {  
              window.attachEvent("onload", initialize);  
            }  
            delete arguments.callee;  
          })();  
          
          
        })();
        

        seiten, die obigen code einbinden, muessen dann natuerlich noch die slideshow-daten
        zur verfuegung stellen - beispielsweise so:

        <script type="text/javascript" src="js/SlideshowPlugin.js"></script><!-- obiger code //-->  
        <script type="text/javascript">
        ~~~~~~javascript
          
          
        //console.log("YAHOO.AOWLB.importSlideShowData : " + YAHOO.AOWLB.importSlideShowData);  
          console.log("SlideshowPlugin.importSlideShowData : " + SlideshowPlugin.importSlideShowData);  
          
        //YAHOO.AOWLB.importSlideShowData([  
          SlideshowPlugin.importSlideShowData([  
          
              ["img/slide01.jpg", "img/slide02.jpg", "img/slide03.jpg", "img/slide04.jpg", "img/slide05.jpg", "img/slide06.jpg", "img/slide07.jpg", "img/slide08.jpg", "img/slide09.jpg"],  
              ["img/slide05.jpg", "img/slide04.jpg", "img/slide03.jpg", "img/slide02.jpg", "img/slide01.jpg"],  
              ["img/slide09.jpg", "img/slide08.jpg", "img/slide07.jpg", "img/slide06.jpg", "img/slide05.jpg", "img/slide04.jpg", "img/slide03.jpg"],  
              ["img/slide02.jpg", "img/slide04.jpg", "img/slide06.jpg", "img/slide08.jpg"],  
              ["img/slide06.jpg", "img/slide04.jpg", "img/slide02.jpg"]  
            ]);
        ~~~~~~html
          
          
        </script>
        

        so long - peterS. - pseliger@gmx.net

        --
        »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
        Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
        ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
        1. code review:

          (function () { // initialize application automatically.  
            
              if (window.addEventListener) {  
                window.addEventListener("load", initialize, false);  
              //------------------------------------------^^^^^^^  
              } else if (window.attachEvent) {  
                window.attachEvent("onload", initialize);  
              }  
              delete arguments.callee;  
            })();
          

          so long - peterS. - pseliger@gmx.net

          --
          »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
          Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
          ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
          1. hallo again in die runde,

            na sauber - ausgerechnet bei der kernfunktionalitaet des
            gesamten build-prozesses mache ich 'nen copy-paste-fehler.

              
            
            >     return {  
            >   
            >       importData: (function (obj) {  
            >   
            >         slideshowData = obj;  
            >   
            >       //console.log("SlideshowGenerator :: importData :: slideshowData.dump() : " + [link:http://developer.yahoo.com/yui/docs/YAHOO.lang.html#method_dump@title=Lang.dump](slideshowData)); // YUI-lib;  
            >         console.log("SlideshowGenerator :: importData - slideshowData.dump() : " + slideshowData.toSource());  
            >         console.log("SlideshowGenerator :: importData - (SlideshowGenerator.importData === arguments.callee) ? " + (SlideshowGenerator.importData === arguments.callee));  
            >   
            >         delete Application.importSlideShowData;  
            >         delete SlideshowGenerator.importData;  
            >         delete arguments.callee;  
            >       }),  
            >       initialize: (function (elm) {  
            >   
            
                     //falsch:  
            
            >       //Array.forEach(Dom.getElementsByClassName("slideshow", "div", elmResults), (function (elm, idx/*, arr*/) {  
              
                     //richtig:  
                     //Array.forEach(Dom.getElementsByClassName("slideshow", "div", elmBody), (function (elm, idx/*, arr*/) { // YUI-lib;  
              
                     //alternativ:  
                       Array.forEach(Node.getElementsByClassNames(elmBody, "slideshow"), (function (elm, idx/*, arr*/) { // [jsApi.bundles.DOM.getters.js]  
            
            >   
            >           slideshowList.push(new Slideshow(elm, idx));  
            >         }));  
            >         console.log("SlideshowGenerator - Application.importSlideShowData : " + Application.importSlideShowData);  
            >         console.log("SlideshowGenerator :: importData : " + SlideshowGenerator.importData);  
            >   
            >         delete SlideshowGenerator.initialize;  
            >         delete arguments.callee;  
            >       })  
            >     };  
            
            

            so long - peterS. - pseliger@gmx.net

            --
            »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
            Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
            ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
            1. ... aehm ja ... langsam wirds peinlich - hier ist noch 'nen copy-paste-massengrab:

                
              
              >       (function () { // anonymus [initialize].  
              >   
              >         slideList = slideshowData[idxOfSlideshowElm];  
              >         amountOfSlides = slideList.length;  
              >   
              
                       //falsch:  
              
              >       //for (var regXDataSrc = (/\s/), src = elmSlide.src, len = slideList.length, i = 0; i<len; ++i) {/*  
              
                       //richtig:  
                         for (var regXDataSrc = (/\s/), src = elmSlide.src, i = 0; i<amountOfSlides; ++i) {/*  
                
                         //falsch:  
              
              >           console.log("i : " + i + " - regXDataSrc : " + regXDataSrc.compile(arr[i].toRegExpString(), "i"));  
              >           console.log("regXDataSrc.test(\"" + src + "\") : " + regXDataSrc.compile(arr[i].toRegExpString(), "i").test(src));*/  
              
                         /*richtig:  
                           console.log("i : " + i + " - regXDataSrc : " + regXDataSrc.compile(slideList[i].toRegExpString(), "i"));  
                           console.log("regXDataSrc.test(\"" + src + "\") : " + regXDataSrc.compile(slideList[i].toRegExpString(), "i").test(src));*/  
                
                         //falsch:  
              
              >         //if (regXDataSrc.compile(arr[i].toRegExpString(), "i").test(src)) {  
              
                         //richtig:  
                           if (regXDataSrc.compile(slideList[i].toRegExpString(), "i").test(src)) {  
                
              
              >             idxSlide = i;  
              >             break;  
              >           }  
              >         }  
              >         idxSlide = ((idxSlide == -1) ? (0) : (idxSlide));  
              >   
              >         refreshCounter();  
              >   
              >         elmPrevious.onclick = onPrevious;  // [link:http://developer.yahoo.com/yui/docs/YAHOO.util.Event.html#method_on@title=Evt.on](elmPrevious, "click", onPrevious); // YUI-lib;  
              >         elmNext.onclick = onNext;          // Evt.on(elmNext, "click", onNext);  
              >   
              >       //[link:http://developer.yahoo.com/yui/docs/YAHOO.util.Dom.html#method_setStyle@title=DOM.setStyle](elmControl, "display", "block"); // YUI-lib;  
              >         elmControl.style.display = "block";  
              >   
              >         delete arguments.callee; // throwing away anonymus [initialize].  
              >       })();  
              
              

              bitte entschuldigt dieses *live*-debugging. ich denke damit sind jetzt alle schnitzer behoben.

              so long - peterS. - pseliger@gmx.net

              --
              »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
              Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
              ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
      2. Lieber Peter,

        vielen Dank für Deinen Input.

        Ich muss gestehen, beim ersten Überfliegen Deines Codes bin ich etwas überfordert. Offensichtlich ist Dein Ansatz wesentlich umfassender, als der meine. Außerdem richtet sich Dein Ansatz an Profis, während ich eher an den unerfahrenen JavaScript Neuling dachte, der vielleicht schon eine kleine Funktion selbst geschrieben hat, und mit den wesentlichsten Grundstrukturen (wie z.B. if-Verzweigungen und for-Schleifen) vertraut ist.

        Daher mein Vorschlag: Lass uns doch zweigleisig fahren! Ich schreibe meinen Ansatz zu Ende, damit eine sagen wir mal "einfache" Version zum Nachverfolgen und selbst wieder einsetzen entsteht. Und Deine Version baut dann (offensichtlich) darauf auf, diesen Ansatz noch wesentlich weiter zu treiben, indem sie
        a) mehr Features und
        b) raffiniertere Programmiertechniken
        bietet. Das wäre dann gerade für mich genau die Vorlage, auf der ich meinen Wissensstand wieder deutlich weiter voranbringen könnte (will sagen, ich wäre Dein bester Kunde/Schüler). So richtig damit auseinandersetzen werde ich mich aber erst können, wenn ich mit meinem Teil soweit fertig bin...

        Wäre das ein Vorschlag?

        Nochmals vielen herzlichen Dank für Deinen Input. Genau deshalb habe ich diesen Thread hier gestartet, damit genau das passiert.

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        1. gruss Felix,

          Ich muss gestehen, beim ersten Überfliegen Deines Codes bin ich
          etwas überfordert.

          schau mal auf die anzahl meiner nachtraeglich hinterhergeworfenen
          korrekturen - ich war es offensichtlich auch ... ueberfordert.

          Offensichtlich ist Dein Ansatz wesentlich umfassender, als der
          meine.

          das denke ich nicht, der abstraktionsgrad fuer die gesamtanwendung
          mag zwar hoch erscheinen, ist es aber keineswegs und zahlt sich in
          dem moment aus, wo es darum geht, alle anderen features wie "autorun",
          "random play" usw. parametrisiert zu implementieren. bei mir ist
          das ueberblenden z.b. *nur* ein abfallprodukt, welches mit maximal
          4 zeilen mehr code zu buche schlaegt (ja natuerlich nur, wenn ich
          [YAHOO.util.Anim] oder mein eigenes [DHTMLOpacityObject] verwende).

          generell halte ich Deinen ansatz zum ueberblenden fuer zu kompliziert,
          denn ein einziges zusaetzliches bild, welches als fadeout-blende vor
          dem jeweils anzuzeigenden bild liegt, ist alles, was diesen effekt
          ausmacht.
          fazit: pro slideshow wird genau ein [HTMLImageElement] benoetigt;
          mit ueberblendung braucht man genau zwei von dieser sorte.

          Außerdem richtet sich Dein Ansatz an Profis, während ich eher an
          den unerfahrenen JavaScript Neuling dachte, der vielleicht schon
          eine kleine Funktion selbst geschrieben hat, und mit den wesentlichsten
          Grundstrukturen (wie z.B. if - Verzweigungen und for - Schleifen)
          vertraut ist.

          ob es dem anfaenger am ende nun von Deiner fetten objektorientierten
          programmierung oder von meinem zugegebenermassen sehr konsequent
          durchgezogenen funktionalen konzept schummrig vor augen wird, ist
          eigentlich egal ;-)

          fuer absolute neulinge wird beides schwer verdaulich bleiben - der
          interessierten laien hingegen sollte in der lage sein, sich durch
          beide ansaetze zu arbeiten.

          Daher mein Vorschlag: Lass uns doch zweigleisig fahren ! Ich schreibe
          meinen Ansatz zu Ende, damit eine sagen wir mal "einfache" Version
          zum Nachverfolgen und selbst wieder einsetzen entsteht. Und Deine
          Version baut dann (offensichtlich) darauf auf, diesen Ansatz noch
          wesentlich weiter zu treiben ...

          mein ansatz wird die sichtbare komplexitaet der eigentlichen applikation
          hoffentlich eher reduzieren, indem er offensichtliche aufgaben/tasks durch
          geeignete abstraktionen abbildet.

          .., indem sie
          a) mehr Features und
          b) raffiniertere Programmiertechniken

          mal sehen.

          bietet. Das wäre dann gerade für mich genau die Vorlage, auf der
          ich meinen Wissensstand wieder deutlich weiter voranbringen könnte ...
          ...

          Wäre das ein Vorschlag?

          jo.

          Nochmals vielen herzlichen Dank für Deinen Input. Genau deshalb habe
          ich diesen Thread hier gestartet, damit genau das passiert.

          nur aus diesem grund, bin ich ueberhaupt darauf eingestiegen. denn
          ungeachtet aller bastelfreude halst man sich 'ne menge zusaetzliche
          arbeit auf.

          so long - peterS. - pseliger@gmx.net

          --
          »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
          Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
          ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
          1. Lieber Peter,

            zahlt sich in
            dem moment aus, wo es darum geht, alle anderen features wie "autorun",
            "random play" usw. parametrisiert zu implementieren. bei mir ist
            das ueberblenden z.b. *nur* ein abfallprodukt, welches mit maximal
            4 zeilen mehr code zu buche schlaegt (ja natuerlich nur, wenn ich
            [YAHOO.util.Anim] oder mein eigenes [DHTMLOpacityObject] verwende).

            ich verstehe "parametrisiert" nicht so ganz... und ich wollte einen Lehrgang anbieten, der das objektorientierte Schreiben vermittelt. Dabei wollte ich bewusst _keine_ externen Bibliotheken einbinden. Wenn Du Dir für Deine Arbeit selbst solche Bibliotheken geschrieben hast, dann ist das für Dich eine selbst erarbeitete Arbeitserleichterung, für einen Anfänger jedoch bleibt es sehr schwer nachzuvollziehen, was die tun. Darauf wollte ich eben _nicht_ eingehen.

            generell halte ich Deinen ansatz zum ueberblenden fuer zu kompliziert,
            denn ein einziges zusaetzliches bild, welches als fadeout-blende vor
            dem jeweils anzuzeigenden bild liegt, ist alles, was diesen effekt
            ausmacht.
            fazit: pro slideshow wird genau ein [HTMLImageElement] benoetigt;
            mit ueberblendung braucht man genau zwei von dieser sorte.

            Und genau hier streiken animierte Bilder (gif). Das wollte ich aber ermöglichen!

            ob es dem anfaenger am ende nun von Deiner fetten objektorientierten
            programmierung oder von meinem zugegebenermassen sehr konsequent
            durchgezogenen funktionalen konzept schummrig vor augen wird, ist
            eigentlich egal ;-)

            Das ist im Moment richtig. Mein Artikel muss aber nocheinmal gewaltig umgekrempelt werden, denn so, wie es in diesem Thread aufeinander aufbaut, muss ein Anfänger (noch) scheitern. Daher werde ich meinen Erstentwurf komplett umkrempeln müssen.

            mein ansatz wird die sichtbare komplexitaet der eigentlichen applikation
            hoffentlich eher reduzieren, indem er offensichtliche aufgaben/tasks durch
            geeignete abstraktionen abbildet.

            ... und dabei auf fertige Bibliotheken zurückgreifen, die es dem Neuling völlig unmöglich machen könnten, die wahren Zusammenhänge zu erkennen. Das war doch schoneinmal der Tenor im SELFHTML-Weblog, oder täuscht mich meine Erinnerung?

            ungeachtet aller bastelfreude halst man sich 'ne menge zusaetzliche
            arbeit auf.

            DAS ist wohl wahr! Trotzdem empfinde ich es als lohnend, denn auf diese Art und Weise könnte es mir gelingen, alles das, was ich durch die Hilfe von anderen hier gelernt habe, zurückzugeben.

            Liebe Grüße,

            Felix Riesterer.

            --
            ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  2. Hallo Felix,

    meinst Du nicht, so etwas wäre unter "SELFHTML-Artikel" besser aufgehoben?

    Freundliche Grüße

    Vinzenz

    1. Lieber Vinzenz,

      meinst Du nicht, so etwas wäre unter "SELFHTML-Artikel" besser aufgehoben?

      ich verstehe, wie Du denkst. Diese Idee hatte ich auch schon. Aber...

      Mit diesem "Lehrgang" schaffe ich eine Basis, auf der diskutiert werden kann. Insbesondere interessiert mich dabei, wo meine Ansätze eventuell noch verfeinert werden könnten (z.B. durch closures etc.), denn auch ich bin in dieser Materie ein Amateur.

      Bei einem Feature-Artikel kann man nicht diskutieren - ja nicht einmal Kommentare abgeben wie beispielsweise im Blog.

      Wenn diese Diskussion fruchtbar verläuft, dann sehe ich durchaus einen Sinn darin, das Ergebnis in einem Artikel zusammenzufassen (mit Link zu diesem Thread).

      Was meinst Du?

      Liebe Grüße aus Ellwangen,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Was meinst Du?

        Die Artikel werden vor der Veröffentlichung innerhalb der Redaktion auch diskutiert, an Know-How sollte es dort ebenso wenig fehlen wie hier im Forum. Im Gegenteil, es besteht die Gefahr, dass Dein Beitrag im Wust des Forumsarchivs untergeht, wenn er erstmal dort gelandet ist, und das wäre wirklich schade.

        Deshalb bitte ich Dich, einfach Deine Postings in diesem Thread in Artikelform niederzuschreiben und einzureichen, wenn alles Deiner Meinung nach veröffentlichungsreif ist.

        Siechfred

        --
        Obacht, hinter jedem noch so kleinen Busch könnte ein Indianer sitzen!
        1. Lieber Siechfred,

          vielen Dank für Deinen Standpunkt.

          Die Artikel werden vor der Veröffentlichung innerhalb der Redaktion auch diskutiert, an Know-How sollte es dort ebenso wenig fehlen wie hier im Forum.

          Um Himmels Willen! Selbstverständlich fehlt es der Redaktion nicht an Fachwissen! Das hätte ich nie auch nur vermutet.

          Im Gegenteil, es besteht die Gefahr, dass Dein Beitrag im Wust des Forumsarchivs untergeht, wenn er erstmal dort gelandet ist, und das wäre wirklich schade.

          Ich habe definitiv vor, eine Artikel-Version aus diesem Thread zu machen. Sozusagen zusätzlich. Aber gerade weil ich nur Amateur bin, möchte ich eine Diskussion drumherum haben, die mir beim weiteren Verfassen (und vor allem für den späteren Artikel) Anhaltspunkte liefern soll, wo ich wie tief in Erklärungen einsteigen muss, damit es auch relative JavaScript-Anfänger begreifen und eventuell sogar umsetzen können, was hier an Programmierung geschieht.

          Deshalb bitte ich Dich, einfach Deine Postings in diesem Thread in Artikelform niederzuschreiben und einzureichen, wenn alles Deiner Meinung nach veröffentlichungsreif ist.

          Ihr bekommt einen Artikel von mir - versprochen. Den Link bezüglich des Einreichens werde ich mir auch zu Gemüte führen. Danke dafür.

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        2. Lieber Siechfred,

          bin schon fleißig am Schreiben meines Artikels. Er ist schon zu einem Viertel fertig - hoffe ich. Ich werde ihn einschicken, sobald ich soweit bin.

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        3. Lieber Siechfred,

          jetzt isser wech - ich hab ihn eingeschickt. Bin mal gespannt, was die Redaktion sagt...

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
          1. jetzt isser wech - ich hab ihn eingeschickt. Bin mal gespannt, was die Redaktion sagt...

            "Don't call us, we call you." ;)

            Siechfred

            --
            Obacht, hinter jedem noch so kleinen Busch könnte ein Indianer sitzen!
            1. echo $begrüßung;

              "Don't call us, we call you." ;)

              Woher habt ihr™ unsere™ Nummern? Hab ihr euch eine dieser Daten-CDs von den Spendengeldern gekauft?
              :-)

              echo "$verabschiedung $name";

            2. Lieber Siechfred,

              "Don't call us, we call you." ;)

              längst passiert. ;-)

              Liebe Grüße,

              Felix Riesterer.

              --
              ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    2. Lieber Vinzenz,

      meinst Du nicht, so etwas wäre unter "SELFHTML-Artikel" besser aufgehoben?

      die überarbeitete Version des Erstentwurfs schreitet voran, sodass wir bald über eine Review-Version des Artikels diskutieren können - bis dahin versuche ich so fleißig wie möglich zu sein. Dann bekommst Du den Artikel für die Artikelsammlung.

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  3. Nun der zweite Teil des JavaScripts.

    Wir haben bereits unser FaderFramework-Objekt erstellt und auch schon initialisiert. Außerdem haben wir uns schon festgelegt, wie wir das Einrichten eines Faders gerne gestalten möchten. Dazu schauen wir nocheinmal in unsere HTML-Datei:

    FaderFramework.init({
        id: "fader_test_2",
        images: ["images/sonne1.jpg", "images/sonne2.jpg", "images/sonne3.jpg", "images/sonne4.jpg"]
    });
    

    Wir brauchen also eine Funktion "init", die unsere Einstellungen als Objekt (man beachte die geschweiften Klammern innerhalb des Funktionsaufrufs - Objektliteral!) entgegennimmt. In diesem Objekt (es ist im Prinzip ein anonymes Objekt) vergeben wir Eigenschaften (z.B. "id" oder "images"), die wir mit unseren Werten füllen. "id" nennt dabei die ID des <img />-Elements und "images" enthält ein Array mit Zeichenketten, die (von unserer HTML-Datei aus, es wären aber auch absolute Angaben möglich) den Pfad zu den Bilddateien darstellen.

    Unsere init-Funktion wird aber schon während des Ladevorgangs ausgeführt, also zu einem Zeitpunkt, zu dem entweder noch kein <body>-Element existiert, oder aber irgendwie das HTML-Dokument noch unvollständig ist. Daher kann unsere init-Funktion keinen Fader einrichten! Sie kann aber diese Aufgabe zumindest vermerken, und das tut sie, indem sie alle Aufrufe in einer weiteren Eigenschaft unseres FaderFramework-Objektes ablegt: "inits".

    Um etwas Komfort in unser Script zu bringen, bieten wir einige Einstellungen an, die später unser Script dann umsetzen wird. Details dazu folgen in einem anderen Teil.

    
    init: function (einstellungen) {
        /* "einstellungen" ist ein Objekt, das folgende Struktur haben muss:
            {
                id: "id_des_HTML_Elements",                   // muss einmalig sein!!
                images: ["pfad/bild1.jpg", "pfad/bild2.jpg"], // mindestens zwei Bilder, da ansonsten sinnlos!
                viewTime: 20000,                              // optional -> Voreinstellung ist 5000
                fadeStep: 1,                                  // optional -> Voreinstellung ist 0.5
                random: true,                                 // optional -> Voreinstellung ist "false"
                autostart: false                              // optional -> Voreinstellung ist "true"
            }
        */
        this.inits[this.inits.length] = einstellungen; // für später abspeichern
    },
    

    Nun müssen wir uns der onload-Funktion widmen, denn es warten einige Aufgaben auf sie.

    1.) spezielle CSS-Datei einbinden 2.) die "bestellten" (also per init() eingerichteten) Fader tatsächlich erstellen und ausrüsten

    Zu diesen Aufgaben ein paar Gedanken:

    Um weitere zu diesem Projekt gehörende Dateien einbinden (oder irgendwie referenzieren) zu können, müssen wir wissen, in welchem Verzeichnis sich unser Script befindet. Wenn wir diese Information ermittelt haben, sollten wir sie zentral speichern. Zu diesem Zweck benutzen wir daher eine weitere Eigenschaft des FaderFramework-Objektes namens "baseURL", die das Verzeichnis unserer JavaScript-Datei enthalten soll. Damit können wir dann auch unsere CSS-Datei aus demselben Verzeichnis einbinden.

    Bei anderen Projekten kann es sinnvoll sein, die CSS-Datei(en) in einem extra Unterordner (sinnigerweise namens "css") bereitzuhalten, vor allem dann, wenn zu der JavaScript-Applikation noch weitere Dateien (z.B. Bilder, HTML-Dokumente etc.) gehören sollten.

    Um Fader zu erstellen, entwickeln wir eine Art Schablone, die in diesem Teil aber noch nicht besprochen wird. Wichtig ist nur, dass diese Funktion (genauer: Konstruktorfunktion) uns entweder ein Objekt mit dem Fader zurückgibt, oder aber den Wert false (wenn die Erstellung scheitert).

    Da jeder Fader anhand eines <img />-Elements mit einer einmaligen ID erstellt wird, benutzen wir diese ID einfach, um diesen Fader dann in unserem Framework abzulegen. Auch dazu brauchen wir wieder eine weitere Eigenschaft unseres FaderFramework-Objektes - nennen wir sie "faders" - zum Ablegen. Diesmal ist es aber kein Array, da die Unterobjekte in dieser Eigenschaft ja "benannt" werden sollen. Warum sie das sollen, wird in einem nächsten Teil behandelt werden.

    Nun zum Code unserer onload-Funktion:

    onload: function () {
        /* "this" verweist auf unser FaderFramework-Objekt! */
    
        var scripts, i, fader, css;
    
        // baseURL herausfinden, um weitere Komponenten dieses Scripts nachladen zu können
        scripts = document.getElementsByTagName("script");
        for (i = 0; i < scripts.length; i++) {
            // alle <script>-Elemente durchsuchen, ob sie ein passendes src-Attribut haben
            if (scripts[i].src && scripts[i].src.match(/fader-framework\.js$/)) {
                fader = scripts[i];
            }
        }
    
        // fader muss eigentlich gefunden worden sein, es sei denn der Dateiname wurde geändert...
        if (fader) {
            this.baseURL = fader.src.replace(/(.*)\/[^\/]+$/, "$1");
        }
    
        // weitere Komponenten einbinden wenn baseURL ermittelt wurde
        if (this.baseURL) {
            // unsere CSS-Datei einbinden (also <link rel="stylesheet" type="text/css" href="..." /> erzeugen)
            css = document.createElement("link");
            css.rel = "stylesheet";
            css.type = "text/css";
            css.href = this.baseURL + "/fader-framework.css";
            // <link />-Element im <head> hinten anfügen
            document.getElementsByTagName("head")[0].appendChild(css);
        }
    
        // zu initialisierende Fader einrichten
        for (i = 0; i < this.inits.length; i++) {
            // Fader erstellen lassen
            fader = new this.Fader(this.inits[i]); // this.Fader ist eine Konstruktor-Funktion!
    
            // abspeichern wenn Fader erfolgreich erstellt wurde
            if (fader) {
                this.faders[fader.id] = fader;
    
                if (fader.autostart) {
                    // Fader autostarten
                    fader.start(); // start() wird dem Fader in der Konstruktor-Funktion verliehen
                }
            }
        }
    },
    

    Mit allen unseren Überlegungen und Funktionen sieht unser FaderFramework nun so aus:

    var FaderFramework = {
    
        // "Einstellungen"
        className: "fader",         // die Klasse, die unser Element trägt, in dem die Bilder sitzen sollen
    
        // Voreinstellungen für einen Fader
        viewTime: 5000,             // Zeit, die ein Bild angezeigt wird (in Millisekunden)
        fadeStep: 0.5,              // Prozent-Schritt beim Überblenden
        random: false,              // Zufällige Reihenfolge der Bilder (true|false)
        autostart: true,            // sofort mit dem Fading starten (true|false)
    
        // automatische Einstellungen
        baseURL: "",                // hier steht später der Pfad zum Verzeichnis, in dem sich dieses Script befindet.
        oldWinOnLoad: false,        // hier steht später vielleicht eine abgespeicherte Funktion
        inits: new Array(),         // hier stehen später auszuführende Initialisierungen
        faders: new Object(),       // hier werden die Fader stehen
    
    
        // Initialisier-Funktion - startet das FaderFramework indem sie das onload-Verhalten im Dokument regelt (wird noch während des Ladens der Seite ausgeführt)
        start: function () {
            this.oldWinOnLoad = window.onload; // alte onload-Funktion abspeichern (falls vorhanden)
    
            // neue (anonyme!) onload-Funktion erstellen um eventuelle alte Funktion(en) zu kapseln
            window.onload = function () {
                // War bereits eine Funktion in window.onload abgelegt worden?
                if (typeof(FaderFramework.oldWinOnLoad) == "function") {
                    // hier kann man nicht "this" benutzen, da diese Funktion nicht zu einem größeren Objekt gehört!
                    FaderFramework.oldWinOnLoad(); // gespeicherte onload-Funktion ausführen
                }
    
                FaderFramework.onload(); // unsere onload-Funktion ausführen
            };
        },
    
    
        // onload-Funktion wird unmittelbar nach dem vollständigen Laden des Dokuments ausgeführt
        onload: function () {
            /* "this" verweist auf unser FaderFramework-Objekt! */
    
            var scripts, i, fader, css;
    
            // baseURL herausfinden, um weitere Komponenten dieses Scripts nachladen zu können
            scripts = document.getElementsByTagName("script");
            for (i = 0; i < scripts.length; i++) {
                if (scripts[i].src && scripts[i].src.match(/fader-framework\.js$/)) {
                    fader = scripts[i];
                }
            }
    
            // fader muss eigentlich gefunden worden sein, es sei denn der Dateiname wurde geändert...
            if (fader) {
                this.baseURL = fader.src.replace(/(.*)\/[^\/]+$/, "$1");
            }
    
            // weitere Komponenten einbinden wenn baseURL ermittelt wurde
            if (this.baseURL) {
                // unsere CSS-Datei einbinden (also <link rel="stylesheet" type="text/css" href="..." /> erzeugen)
                css = document.createElement("link");
                css.rel = "stylesheet";
                css.type = "text/css";
                css.href = this.baseURL + "/fader-framework.css";
                // <link />-Element im <head> hinten anfügen
                document.getElementsByTagName("head")[0].appendChild(css);
            }
    
            // zu initialisierende Fader einrichten
            for (i = 0; i < this.inits.length; i++) {
                // Fader erstellen lassen
                fader = new this.Fader(this.inits[i]); // this.Fader ist eine Konstruktor-Funktion!
    
                // abspeichern wenn Fader erfolgreich erstellt wurde
                if (fader) {
                    this.faders[fader.id] = fader;
    
                    if (fader.autostart) {
                        // Fader autostarten
                        fader.start(); // start() wird dem Fader in der Konstruktor-Funktion verliehen
                    }
                }
            }
        },
    
    
        // Funktion zum Einrichten eines Faders (wird noch während des Ladens der Seite ausgeführt - eventuell mehrmals)
        init: function (einstellungen) {
            /* "einstellungen" ist ein Objekt, das folgende Struktur haben muss:
                {
                    id: "id-des-HTML-Elements",                   // muss einmalig sein!!
                    images: ["pfad/bild1.jpg", "pfad/bild2.jpg"], // weitere Bilder möglich
                    viewTime: 20000,                              // optional -> Voreinstellung ist 5000
                    fadeStep: 1,                                  // optional -> Voreinstellung ist 0.5
                    random: true,                                 // optional -> Voreinstellung ist "false"
                    autostart: false                              // optional -> Voreinstellung ist "true"
                }
            */
            this.inits[this.inits.length] = einstellungen; // für später abspeichern
        }
    }
    
    FaderFramework.start();
    

    Jetzt fehlt uns noch der eigentlich komplexeste Brocken: Die Konstruktor-Funktion für einen Fader. Die gibt es aber erst im nächsten Teil.

    War dieser Teil nachvollziehbar? Verständlich? Vom Konzept her logisch aufgebaut?

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  4. Im dritten Teil folgt nun die Konstruktor-Funktion, die das Kernstück unseres ganzen Scripts bildet, denn das Framework ist - wie der Name schon sagt - nur der Rahmen drumherum, der die einzelnen Fader verwaltet, dier Konstruktor-Funktion dagegen ist jedoch die "Fabrik", in der einzelne Fader-Objekte hergestellt werden.

    Wieder ein paar Überlegungen, bevor wir unsere Konstruktor-Funktion aufbauen:

    1.) Eigenschaften:     a) Alle unsere über die init()-Funktion übergebenen Eigenschaften müssen verarbeitet werden.     b) Sollten manche Eigenschaften nicht übergeben worden sein, dann gelten die Voreinstellungen aus unserem FaderFramework-Objekt (wie z.B. "viewTime", "fadeStep", "autostart" oder "random").     c) Unser Fader benötigt eine Playlist (ein Array - Eigenschaft "playList"), denn die Bilder sollen ja auch zufällig wiedergegeben werden.     d) Wenn eine Playlist abläuft, dann brauchen wir einen Zeiger auf das aktuell angezeigte Bild, damit wir das vorhergehende ausblenden können: "counter".     e) Bei einer zufälligen Wiedergabe sollten wir nach einem Durchlauf eine neue Playlist erstellen, da sonst der Zufall sehr regelmäßig würde.     f) Wenn wir eine neue Playlist erstellen, dann fehlt uns die Möglichkeit, das "alte Bild" auszublenden, da wir in der neuen Playlist nicht mehr wissen, welches das alte Bild war. Daher brauchen wir auch die alte Playlist: "oldPlayList".     g) Wir wollen unsere Slideshow anhalten können. Dazu brauchen wir eine Eigenschaft "stopped", die von unseren Funktionen berücksichtigt wird.     h) Unser Fader läuft in einem <span>-Element ab. Dieses Element speichern wir unter der Eigenschaft "element".

    2.) Funktionen (Methoden):     a) fade() wird unsere Überblendungsfunktion werden. Sie blendet das aktuelle Bild (auf das unser Zähler zeigt) ein und blendet das alte Bild (also das, worauf der Zähler vorher gezeigt hat) aus.     b) next() wird unsere Funktion, um einen Bilderwechsel anzustoßen.         Sie erhöht den Zeiger (oder veranlasst, dass eine neue Playlist erzeugt wird, mit dem Zeiger wieder auf Null) und ruft fade() auf.         Bei angehaltenem Fader darf diese Funktion aber kein nächstes Bild anzeigen lassen. Es sei denn wir möchten das sozusagen "gewaltsam" für einen einzelnen Schritt. Dazu benötigt sie einen zu übergebenden Parameter der "true" sein muss. Fehlt er, dann ist das im Prinzip dasselbe, als hätten wir "false" übergeben.     c) stop() wird eine Funktion, die die Eigenschaft "stopped" auf "true" setzt. Dadurch wird die Funktion next() ausgebremst. Eine bereits angefangene Überblendung soll aber zu Ende ablaufen. Daher wird fade() diese Eigenschaft ignorieren.     d) start() ist das Gegenstück zu stop() und setzt die Eigenschaft "stopped" auf "false". Außerdem startet sie die Slideshow, indem sie auch next() aufruft.     e) createPlaylist() verwenden wir, um eine Playlist zu generieren.

    3.) Die Herstellung eines Faders     a) Ein Fader wird ja mit seiner ID unter FaderFramework.faders abgelegt werden. Das darf nur erfolgen, wenn folgende Bedingungen erfüllt sind:         - Es wurde eine ID übermittelt.         - Es existiert ein HTML-Element mit der angegebenen ID im Dokument.         - Es existiert noch kein Fader mit dieser ID.         - Es sind mindestens zwei Bilder zum Überblenden vorhanden.     b) Bei der erfolgreichen Herstellung eines Faders muss das originale <img />-Element im Dokument durch ein <span>-Element ersetzt werden, welches wir ja unter "element" als Eigenschaft des Faders abspeichern.

    Diese Überlegungen setzen wir in den einzelnen Funktionen um. Beginnen wir mit der einfachsten, mit stop():

    this.stop = function () {
        this.stopped = true;
    };
    

    Das war ja einfach. Schauen wir uns die nächst kompliziertere an, start():

    this.start = function () {
        this.stopped = false;
        this.next();
    };
    

    Aha. Jetzt bezieht sich start() irgendwie auf next(). Schauen wir uns next() an:

    this.next = function (single) {
        // "single" ist true oder false und dient dazu, einen einmaligen Wechsel zu ermöglichen, ohne eine Slideshow zu starten. Wird kein Parameter übergeben, dann wird single nicht als true interpretiert.
        if (single) {
            this.stopped = true;
        }
    
        // wurde der Fader angehalten?
        if (this.stopped && !single) {
            return; // Ja -> keinen Bildwechsel durchführen!
        }
    
        // Counter weiterzählen (oder zurücksetzen)
        this.counter = (this.counter < this.playList.length -1) ? this.counter +1 : 0;
    
        // Neue Playlist fällig?
        if  (this.counter == 0) {
            // neue Playlist generieren
            this.oldPlayList = this.playList; // aktuelle Playlist speichern
            this.createPlayList(); // neue aktuelle Playlist erstellen
        }
    
        // Fading einleiten
        this.fade();
    };
    

    Bevor wir zum Interessantesten kommen, hier die Funktion zum Generieren einer Playlist:

    // Playlist generieren (enthält nur die Nummern der Bilder)
    this.createPlayList = function () {
        this.playList = new Array();
    
        if (this.random) {
            // zufällige Reihenfolge
            while (this.playList.length < this.images.length) {
                vorhanden = false; // Zufallszahl bereits vorhanden?
                r = Math.floor(Math.random() * (this.images.length));
                for (i = 0; i < this.playList.length; i++) {
                    if (r == this.playList[i]) {
                        vorhanden = true;
                    }
                }
    
                if (!vorhanden) {
                    this.playList[this.playList.length] = r;
                }
            }
    
        } else {
            // geordnete Reihenfolge
            for (i = 0; i < this.images.length; i++) {
                this.playList[i] = i;
            }
        }
    };
    

    Und jetzt kommt der Fading-Vorgang:

    // Fade-Funktion für den Bilderwechsel (jeder Aufruf entspricht einem Fading-Schritt)
    this.fade = function (step) {
        var imgs = new Array(), v;
    
        // Wenn kein Wert übertragen wurde, dann muss das Fading von vorne durchgeführt werden
        step = (!step) ? 0 : step;
    
        // Das letzte Bild steht in der Liste vor dem aktuellen (falls dieses ganz am Anfang steht, gilt das letzte der alten Playlist)
        imgs[0] = (this.counter == 0) ? this.images[this.oldPlayList[this.oldPlayList.length -1]] : this.images[this.playList[this.counter -1]];
    
        // Das neue Bild ist das, auf welches der Counter zeigt
        imgs[1] = this.images[this.playList[this.counter]];
    
        for (i = 0; i < imgs.length; i++) {
            v = (i == 0) ? (100 - step) : step;
            imgs[i].style.opacity = v/100;
            // IE?
            if (imgs[i].style.filter != "undefined") {
                imgs[i].style.filter = "alpha(opacity=" + v + ")";
            }
        }
    
        step += this.fadeStep;
    
        if (step <= 100) {
            // nächsten Fade-Schritt ausführen
            window.setTimeout(""
                + "FaderFramework.faders."
                + this.id
                + ".fade("
                + step
                + ");",
            1);
        } else {
            // Bildübergang abgeschlossen -> nach der Pause nächstes Bild
            window.setTimeout(""
                + "FaderFramework.faders."
                + this.id
                + ".next();",
            this.viewTime);
        }
    };
    

    Jetzt brauchen wir im Konstruktor nur noch regeln, dass das originale HTML-Element mit der übertragenen ID (das <img />-Element) mit unserem <span>-Element ersetzt wird.

    Fader: function (einstellungen) {
        /*
            In diesem Konstruktor verweist "this" immer auf das zu erzeugende Objekt - vorausgesetzt,
            dieser Konstruktor wird mit dem Schlüsselwort "new" aufgerufen, z.B. var a = new this.Fader()
        */
    
        // wie "einstellungen" aussehen muss, siehe Funktion "init"!
        var className, imgs, i, r, vorhanden;
    
        // Darf eventuell kein Fader eingerichtet werden?
        if (
            // keine ID (oder ein Leerstring) übergeben
            !einstellungen.id
            ||
            // kein HTML-Element mit dieser ID vorhanden
            !document.getElementById(einstellungen.id)
            ||
            // für diese ID ist bereits ein Fader eingerichtet
            FaderFramework.faders[einstellungen.id]
            ||
            // weniger als zwei Bilder angegeben
            einstellungen.images.length < 2
        ) {
            // also gibt es keinen Fader für diesen init-Aufruf
            return false;
        }
    
    
        // Einstellungen des Faders vornehmen
        this.id = einstellungen.id;
        this.images = new Array(); // Bilder werden hier nicht als Zeichenketten, sondern später als HTML-Elementobjekte abgelegt...
        this.random = einstellungen.random ? einstellungen.random : FaderFramework.random;
        this.autostart = (typeof(einstellungen.autostart) != "undefined") ? einstellungen.autostart : FaderFramework.autostart;
        this.viewTime = einstellungen.viewTime ? einstellungen.viewTime : FaderFramework.viewTime;
        this.fadeStep = einstellungen.fadeStep ? einstellungen.fadeStep : FaderFramework.fadeStep;
        this.stopped = false; // hiermit kann später der Fader angehalten werden
        this.playList = new Array(); // Wiedergabeliste
        this.oldPlayList = [0]; // vorherige Wiedergabeliste (besteht aus einem einzigen Bild)
        this.counter = 0; // aktuell angezeigtes Bild (Zähler für Playlist)
    
    
        // DOM-Baum des HTML-Dokumentes auf den Fader vorbereiten
    
        // <span>-Element als Container erzeugen und mit der Fader-Klasse ausrüsten
        this.element = document.createElement("span");
        this.element.className = FaderFramework.className;
    
        // vor das ursprüngliche Bild setzen
        i = document.getElementById(this.id); // ursprüngliches Bild
        i.parentNode.insertBefore(this.element, i);
    
        // ursprüngliches Bild entfernen
        i.parentNode.removeChild(i);
    
        // Bilder aus der Liste zu echten Bildobjekten machen und ins <span>-Element einhängen
        for (i = 0; i < einstellungen.images.length; i++) {
            this.images[i] = document.createElement("img");
            this.images[i].src = einstellungen.images[i];
            this.images[i].alt = "";
    
            // Alle Bilder, außer dem ersten, müssen positioniert werden, damit sie nicht neben oder unter dem ersten angezeigt werden.
            if (i > 0) {
                this.images[i].className = "next";
    
                // Volle Durchsichtigkeit einstellen (erstes Bild soll ja gleich angezeigt werden
                this.images[i].style.opacity = 0;
                // IE?
                if (this.images[i].style.filter != "undefined") {
                    this.images[i].style.filter = "alpha(opacity=0)";
                }
            }
    
            // einhängen
            this.element.appendChild(this.images[i]);
        }
    
    
        /*
            Funktionen (Methoden) des Faders definieren!
        */
        // wurde oben bereits behandelt
    
        // Playlist erzeugen
        this.createPlayList();
    
        // fertigen Fader zurückgeben
        return this;
    }
    

    Damit ist unser Fader-Bauplan im Prinzip fertig und unsere onload-Funktion kann ihn benutzen, um die mit init()-Angeforderten Fader auch zu erstellen.

    Unser fertiges JavaScript kommt im nächsten Post, denn ich bin der Forensoftware wieder etwas zu geschwätzig. ;-)

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  5. Hier nun das fertige JavaScript - allerdings ohne manche Kommentare, da ich sonst der Forensoftware wieder zu geschwätzig war:

    var FaderFramework = {
    
        // "Einstellungen"
        className: "fader",
    
        // Voreinstellungen für einen Fader
        viewTime: 5000,
        fadeStep: 0.5,
        random: false,
        autostart: true,
    
        // automatische Einstellungen
        baseURL: "",
        oldWinOnLoad: false,
        inits: new Array(),
        faders: new Object(),
    
        start: function () {
            this.oldWinOnLoad = window.onload;
    
            window.onload = function () {
                if (typeof(FaderFramework.oldWinOnLoad) == "function") {
                    FaderFramework.oldWinOnLoad();
                }
    
                FaderFramework.onload();
            };
        },
    
    
        // wird unmittelbar nach dem vollständigen Laden des Dokuments ausgeführt
        onload: function () {
            /* "this" verweist auf unser FaderFramework-Objekt! */
    
            var scripts, i, fader, css;
    
            // baseURL herausfinden, um weitere Komponenten dieses Scripts nachladen zu können
            scripts = document.getElementsByTagName("script");
            for (i = 0; i < scripts.length; i++) {
                if (scripts[i].src && scripts[i].src.match(/fader-framework\.js$/)) {
                    fader = scripts[i];
                }
            }
    
            // fader muss eigentlich gefunden worden sein, es sei denn der Dateiname wurde geändert...
            if (fader) {
                this.baseURL = fader.src.replace(/(.*)\/[^\/]+$/, "$1");
            }
    
            // weitere Komponenten einbinden wenn baseURL ermittelt wurde
            if (this.baseURL) {
                // unsere CSS-Datei einbinden
                css = document.createElement("link");
                css.rel = "stylesheet";
                css.type = "text/css";
                css.href = this.baseURL + "/fader-framework.css";
                // <link />-Element im <head> hinten anfügen
                document.getElementsByTagName("head")[0].appendChild(css);
            }
    
            // zu initialisierende Fader einrichten
            for (i = 0; i < this.inits.length; i++) {
                // Fader erstellen lassen
                fader = new this.Fader(this.inits[i]); // this.Fader ist eine Konstruktor-Funktion!
    
                // abspeichern wenn Fader erfolgreich erstellt wurde
                if (fader) {
                    this.faders[fader.id] = fader;
    
                    if (fader.autostart) {
                        // Fader autostarten
                        fader.start(); // start() wird dem Fader in der Konstruktor-Funktion verliehen
                    }
                }
            }
        },
    
    
        // Funktion zum Einrichten eines Faders (wird noch während des Ladens der Seite ausgeführt - eventuell mehrmals)
        init: function (einstellungen) {
            /* "einstellungen" ist ein Objekt, das folgende Struktur haben muss:
                {
                    id: "id-des-HTML-Elements",
                    images: ["pfad/bild1.jpg", "pfad/bild2.jpg"], // weitere Bilder möglich
                    // optionale Einstellungen
                    viewTime: 20000,
                    fadeStep: 1,
                    random: true,
                    autostart: false
                }
            */
            this.inits[this.inits.length] = einstellungen; // für später abspeichern
        },
    
    
        // Bauplan eines Faders
        Fader: function (einstellungen) {
        /*
            In diesem Konstruktor verweist "this" immer auf das zu erzeugende Objekt - vorausgesetzt,
            dieser Konstruktor wird mit dem Schlüsselwort "new" aufgerufen, z.B. var a = new this.Fader()
        */
    
            // wie "einstellungen" aussehen muss, siehe Funktion "init"!
            var className, imgs, i, r, vorhanden;
    
            // Darf eventuell kein Fader eingerichtet werden?
            if (
                // keine ID (oder ein Leerstring) übergeben
                !einstellungen.id
                ||
                // kein HTML-Element mit dieser ID vorhanden
                !document.getElementById(einstellungen.id)
                ||
                // für diese ID ist bereits ein Fader eingerichtet
                FaderFramework.faders[einstellungen.id]
                ||
                // weniger als zwei Bilder angegeben
                einstellungen.images.length < 2
            ) {
                // also gibt es keinen Fader für diesen init-Aufruf
                return false;
            }
    
    
            // Einstellungen des Faders vornehmen
            this.id = einstellungen.id;
            this.images = new Array(); // Bilder werden hier nicht als Zeichenketten, sondern später als HTML-Elementobjekte abgelegt...
            this.random = einstellungen.random ? einstellungen.random : FaderFramework.random;
            this.autostart = (typeof(einstellungen.autostart) != "undefined") ? einstellungen.autostart : FaderFramework.autostart;
            this.viewTime = einstellungen.viewTime ? einstellungen.viewTime : FaderFramework.viewTime;
            this.fadeStep = einstellungen.fadeStep ? einstellungen.fadeStep : FaderFramework.fadeStep;
            this.stopped = false; // hiermit kann später der Fader angehalten werden
            this.playList = new Array(); // Wiedergabeliste
            this.oldPlayList = [0]; // vorherige Wiedergabeliste (besteht aus einem einzigen Bild)
            this.counter = 0; // aktuell angezeigtes Bild (Zähler für Playlist)
    
    
            // DOM-Baum des HTML-Dokumentes auf den Fader vorbereiten
    
            // <span>-Element als Container erzeugen und mit der Fader-Klasse ausrüsten
            this.element = document.createElement("span");
            this.element.className = FaderFramework.className;
    
            // vor das ursprüngliche Bild setzen
            i = document.getElementById(this.id); // ursprüngliches Bild
            i.parentNode.insertBefore(this.element, i);
    
            // ursprüngliches Bild entfernen
            i.parentNode.removeChild(i);
    
            // Bilder aus der Liste zu echten Bildobjekten machen und ins <span>-Element einhängen
            for (i = 0; i < einstellungen.images.length; i++) {
                this.images[i] = document.createElement("img");
                this.images[i].src = einstellungen.images[i];
                this.images[i].alt = "";
    
                // Alle Bilder, außer dem ersten, müssen positioniert werden, damit sie nicht neben oder unter dem ersten angezeigt werden.
                if (i > 0) {
                    this.images[i].className = "next";
    
                    // Volle Durchsichtigkeit einstellen (erstes Bild soll ja gleich angezeigt werden
                    this.images[i].style.opacity = 0;
                    // IE?
                    if (this.images[i].style.filter != "undefined") {
                        this.images[i].style.filter = "alpha(opacity=0)";
                    }
                }
    
                // einhängen
                this.element.appendChild(this.images[i]);
            }
    
    
            /*
                Funktionen (Methoden) des Faders definieren!
            */
    
    
            // Playlist generieren (enthält nur die Nummern der Bilder)
            this.createPlayList = function () {
                this.playList = new Array();
    
                if (this.random) {
                    // zufällige Reihenfolge
                    while (this.playList.length < this.images.length) {
                        vorhanden = false; // Zufallszahl bereits vorhanden?
                        r = Math.floor(Math.random() * (this.images.length));
                        for (i = 0; i < this.playList.length; i++) {
                            if (r == this.playList[i]) {
                                vorhanden = true;
                            }
                        }
    
                        if (!vorhanden) {
                            this.playList[this.playList.length] = r;
                        }
                    }
    
                } else {
                    // geordnete Reihenfolge
                    for (i = 0; i < this.images.length; i++) {
                        this.playList[i] = i;
                    }
                }
            };
    
    
            // Funktion zum Starten des Faders
            this.start = function () {
                this.stopped = false;
                this.next();
            };
    
            // Funktion zum Stoppen des Faders
            this.stop = function () {
                this.stopped = true; // verhindert, dass weitere window.setTimeout-Funktionen gestartet werden
            };
    
    
            // Funktion zum Anzeigen des nächsten Bildes
            this.next = function (single) {
                // "single" ist true oder false und dient dazu, bei angehaltenem Fader einen einmaligen Wechsel zu ermöglichen. Wird kein Parameter übergeben, dann wird single nicht als true interpretiert.
                if (single) {
                    this.stopped = true;
                }
    
                // wurde der Fader angehalten?
                if (this.stopped && !single) {
                    return; // Ja -> keinen Bildwechsel durchführen!
                }
    
                // Counter weiterzählen (oder zurücksetzen)
                this.counter = (this.counter < this.playList.length -1) ? this.counter +1 : 0;
    
                // Neue Playlist fällig (nur bei zufälliger Wiedergabe)?
                if  (this.counter == 0) {
                    // neue Zufalls-Playlist generieren
                    this.oldPlayList = this.playList; // aktuelle Playlist speichern
                    this.createPlayList(); // neue aktuelle Playlist erstellen
                }
    
                // Fading einleiten
                this.fade();
            };
    
    
            // Fade-Funktion für den Bilderwechsel (jeder Aufruf entspricht einem Fading-Schritt)
            this.fade = function (step) {
                var imgs = new Array(), v;
    
                // Wenn kein Wert übertragen wurde, dann muss das Fading von vorne durchgeführt werden
                step = (!step) ? 0 : step;
    
                // Das letzte Bild steht in der Liste vor dem aktuellen (falls dieses ganz am Anfang steht, gilt das letzte der alten Playlist)
                imgs[0] = (this.counter == 0) ? this.images[this.oldPlayList[this.oldPlayList.length -1]] : this.images[this.playList[this.counter -1]];
    
                // Das neue Bild ist das, auf welches der Counter zeigt
                imgs[1] = this.images[this.playList[this.counter]];
    
                for (i = 0; i < imgs.length; i++) {
                    v = (i == 0) ? (100 - step) : step;
                    imgs[i].style.opacity = v/100;
                    // IE?
                    if (imgs[i].style.filter != "undefined") {
                        imgs[i].style.filter = "alpha(opacity=" + v + ")";
                    }
                }
    
                step += this.fadeStep;
    
                if (step <= 100) {
                    // nächsten Fade-Schritt ausführen
                    window.setTimeout(""
                        + "FaderFramework.faders."
                        + this.id
                        + ".fade("
                        + step
                        + ");",
                    1);
                } else {
                    // Bildübergang abgeschlossen -> nach der Pause nächstes Bild
                    window.setTimeout(""
                        + "FaderFramework.faders."
                        + this.id
                        + ".next();",
                    this.viewTime);
                }
            };
    
            // Playlist erzeugen
            this.createPlayList();
    
            // fertigen Fader zurückgeben
            return this;
        }
    }
    
    FaderFramework.start();
    

    Viel Spaß beim Einsetzen des Scripts, und noch viel mehr Spaß beim Studieren seiner Funktionalitäten!

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Hallo,

      // IE?
                      if (imgs[i].style.filter != "undefined") {

      typeof?

      imgs[i].style.filter = "alpha(opacity=" + v + ")";
                      }
                  }

      step += this.fadeStep;

      if (step <= 100) {
                      // nächsten Fade-Schritt ausführen
                      window.setTimeout(""
                          + "FaderFramework.faders."
                          + this.id
                          + ".fade("
                          + step
                          + ");",
                      1);

      Ich habe mir das nicht im Detail angeschaut, aber dieses Gefrickel mit als String zusammengesetztem JavaScript-Code ist immer langsam, unübersichtlich und führt u.U. dazu, dass die Architektur unsauber wird.

      Ich habe es in einem anderen Thread ja schon gesagt:
      1. setTimeout nimmt Funktionsreferenzen an, was i.d.R. dem String vorzuziehen ist,
      2. Verschachtelte Funktionen bzw. Closures helfen immer weiter, um in dieser Funktion, die eigentlich in einem anderen Kontext ausgeführt wird, wieder zurück zum Instanzobjekt oder sonstigen benötigten Daten zu kommen. Globale Variablen und global zugängliche Listen mit allen Instanzen wie FaderFramework.faders sind zumindest dafür nicht nötig.

      this.step = function (step) {  
        ...  
        step += this.fadeStep;  
        var instanz = this;  
        setTimeout(function () {  
          instanz.step(step);  
        }, 1);  
      };
      

      window.setTimeout(""
                          + "FaderFramework.faders."
                          + this.id
                          + ".next();",
                      this.viewTime);

      Wie oben, nur
      instanz.next()

      Mathias

      1. Lieber Mathias,

        vielen herzlichen Dank für Deine Anmerkungen!

        this.step = function (step) {

        ...
          step += this.fadeStep;
          var instanz = this;
          setTimeout(function () {
            instanz.step(step);
          }, 1);
        };

          
        Das nehme ich in meinen Artikel auf! Dort wird es dann so aussehen:  
          
        ~~~javascript
        this.fade = function (step) {  
            var ..., instanz = this;  
        ...  
            step += this.fadeStep;  
          
            if (step <= 100) {  
                // nächsten Fade-Schritt ausführen  
                window.setTimeout(function () { instanz.fade(step); }, 1);  
            } else {  
                // Bildübergang abgeschlossen -> nach der Pause nächstes Bild  
                window.setTimeout(function () { instanz.next(); }, this.viewTime);  
            }  
        };
        

        Anlässe wie dieser waren der Grund, warum ich hier im Forum damit angefangen habe, da ich als interessierter Laie eben viele Dinge nicht weiß, bzw. nicht genau kenne. Du hast da einen wesentlich fundierteren Ansatz als ich...

        Noch eine Anmerkung: Wenn ich im setTimeout-Aufruf die Funktionsaufrufe instanz.fade(step) oder instanz.next() nicht in einer anonymen Funktion gekapselt hätte, dann hätte mir der FF "too much incursion" vorgeworfen. Das muss ich jetzt aber nicht verstehen, oder?

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        1. Noch eine Anmerkung: Wenn ich im setTimeout-Aufruf die Funktionsaufrufe instanz.fade(step) oder instanz.next() nicht in einer anonymen Funktion gekapselt hätte, dann hätte mir der FF "too much incursion" vorgeworfen. Das muss ich jetzt aber nicht verstehen, oder?

          Wenn du die Funktion direkt aufrufst, dann wird die Funktion aufgerufen und da der Timeraufruf auch in dieser Funktion stattfindet, hast du: too much recursion.

          Der Timer erwartet, wie Events, eine Referenz einer Funktion oder einen string, der nach Ablauf dann evaluiert wird.

          Struppi.

          1. Lieber Struppi,

            Wenn du die Funktion direkt aufrufst, dann wird die Funktion aufgerufen und da der Timeraufruf auch in dieser Funktion stattfindet, hast du: too much recursion.

            Der Timer erwartet, wie Events, eine Referenz einer Funktion oder einen string, der nach Ablauf dann evaluiert wird.

            vielen herzlichen Dank! Ich saß gerade auf der Leitung, denn eigentlich ist es ja offensichtlich... :-/

            Liebe Grüße,

            Felix Riesterer.

            --
            ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
            1. Also ich weiß ja nicht ob ich zu blöd zum kopieren bin, aber als ich das Skript testen wollte, sind die Bilder untereinander erschienen?!?

              Dominik

              1. Lieber Dominik,

                als ich das Skript testen wollte

                von welchem Script _genau_ sprichst Du? Dieser Zweig des Threads behandelt gerade meinen Artikel in seiner gegenwärtigen Review-Version...

                Liebe Grüße,

                Felix Riesterer.

                --
                ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
                1. Dieser Zweig des Threads behandelt gerade meinen Artikel in seiner gegenwärtigen Review-Version...

                  Ooops, vertan. Aber egal. Schau mal in den Artikel rein. Auch wenn er noch überarbeitet werden wird, sollte er Dir doch schon weiterhelfen.

                  Liebe Grüße,

                  Felix Riesterer.

                  --
                  ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
                  1. Also es lag an mir, ich hab mich vertippt. Jetzt hab ich noch kleine Verständnisfragen:

                    1.

                    for (i = 0; i < this.inits.length; i++) {  
                                // Fader erstellen lassen  
                                fader = new this.Fader(this.inits[i]); // this.Fader ist eine Konstruktor-Funktion!  
                      
                                // abspeichern wenn Fader erfolgreich erstellt wurde  
                                if (fader) {  
                                    this.faders[fader.id] = fader;  
                      
                                    if (fader.autostart) {  
                                        // Fader autostarten  
                                        fader.start(); // start() wird dem Fader in der Konstruktor-Funktion verliehen  
                                    }  
                                }  
                            }
                    

                    Was passiert denn, wenn mehrer Fader eingerichtet werden?

                    2.

                    i = document.getElementById(this.id); // ursprüngliches Bild  
                            i.parentNode.insertBefore(this.element, i);  
                      
                            // ursprüngliches Bild entfernen  
                            i.parentNode.removeChild(i);  
                      
                    ...  
                      
                    this.element.appendChild(this.images[i]);
                    

                    Die Struktur mit node versteh ich gar nicht. Kannst du mir das mal erklären?

                    3.

                    imgs[0] = (this.counter == 0) ? this.images[this.oldPlayList[this.oldPlayList.length -1]] : this.images[this.playList[this.counter -1]];  
                      
                                // Das neue Bild ist das, auf welches der Counter zeigt  
                                imgs[1] = this.images[this.playList[this.counter]];
                    

                    Auch hier schwirrt mir der Kopf.

                    Ansonsten habe ich alles verstanden. Danke für die Arbeit!!

                    Grüße Dominik

                    1. Lieber Domink,

                      Jetzt hab ich noch kleine Verständnisfragen:

                      Schön! Hast Du auch schon in den Artikel geschaut? Da dort die Beispiele von einfach bis komplexer aufgebaut werden, sollte Dir das ein oder andere klarer werden.

                      Was passiert denn, wenn mehrer Fader eingerichtet werden?

                      Da jeder Fader als ein Objekt erzeugt wird, das alle "Variablen" in seinen Eigenschaften speichert, entstehen einfach für jeden init-Aufruf ein neues Fader-Objekt. Wo ist Dein Verständnis-Problem? Gerade hier solltest Du in den Artikel schauen!

                      Die Struktur mit node versteh ich gar nicht. Kannst du mir das mal erklären?

                      Dazu lohnt es sich, in SELFHTML selbst über http://de.selfhtml.org/javascript/objekte/node.htm@title=node nachzulesen. Du interessierst Dich für das "Document Object Model", das den hierarchischen Aufbau eines HTML-Dokuments als Objekt-Hierarchie nachbildet. Jedes HTML-Element ist darin ein (ziemlich umfangreiches) Objekt, das als Unterobjekt (hier kommts: "node") eines übergeordneten HTML-Element(-objektes, auch eine "node") definiert ist. Durch diesen Objektbaum (daher spricht man ja auch vom "DOM tree") kann man sich nun hangeln, indem man sich von Knoten ("node") zu Knoten bewegt.

                      imgs[0] = (this.counter == 0) ? this.images[this.oldPlayList[this.oldPlayList.length -1]] : this.images[this.playList[this.counter -1]];

                      // Das neue Bild ist das, auf welches der Counter zeigt
                                  imgs[1] = this.images[this.playList[this.counter]];

                      
                      >   
                      > Auch hier schwirrt mir der Kopf.  
                        
                      Wieso? Hast Du die Erklärung im Artikel nicht verstanden? Die verschachtelte Struktur der Array-Schreibweise wird dort aufgeschlüsselt.  
                        
                      Hier muss man nur wissen, dass es im Grunde zwei Arrays gibt, die miteinander verglichen werden. Das eine "Array" (genauer ist das eine HTMLCollection) enthält die Bildelemente (also die echten <img>-HTML-Elemente) des Faders, und das zweite Array (die Playlist) enthält Zahlen. Die Zahlen gehen von null bis zur Anzahl der Bilder (natürlich minus eins), wobei diese Zahlen nicht sortiert sein müssen. Daher wird nun ein Bild aus der HTMLCollection mit Hilfe einer Zahl aus der Playlist referenziert.  
                        
                      ~~~javascript
                      this.images[?] // ein Bild aus der Collection  
                      this.playList[?] // eine Zahl aus der Playlist  
                      this.images[ this.playList[?] ] // ein Bild mit der Nummer aus der PlayList  
                      this.images[this.playList[this.counter]] // das aktuelle Bild
                      

                      Klar? Und wenn man nun den "Vorgänger" ermitteln will, dann braucht man das Bild, auf das der Counter vorher gezeigt hatte. Wenn der Counter aber gerade null ist, dann muss man das letzte Bild aus der _alten_ Playlist ermitteln. Daher ist der Code oben so komplex.

                      Kennst Du schon <http://de.selfhtml.org/javascript/sprache/bedingt.htm#entweder_oder@title=einfache entweder-oder-Abfrage>n in JavaScript?

                      Liebe Grüße,

                      Felix Riesterer.

                      --
                      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
                      1. Ok, soweit habe ich alles verstanden. Jetzt hab ich nur noch eine letze Frage zum Skripte und eine zum CSS:

                        for (i = 0; i < this.inits.length; i++) {  
                                    // Fader erstellen lassen  
                                    fader = new this.Fader(this.inits[i]);
                        

                        this.inits ist doch leer oder nicht? Es wird ja nur am Anfang mit New Array() definiert. Also müsste das Skript den Fader gar nicht erstellen? Oder bezieht sich this.inits auf das init?

                        Und nun noch zum CSS:

                        Ich hab auf meiner Seite verschiedene Bilder mit unterschiedlicher Größe.
                        Seite Jetzt will ich aber alle Bilder in der Mitte des divs "akg" haben. Wie ist das mit CSS möglich (steh grad total auf dem Schlauch)?

                        Danke Dominik

                        1. Lieber Dominik,

                          Ok, soweit habe ich alles verstanden.

                          sehr gut!

                          this.inits ist doch leer oder nicht? Es wird ja nur am Anfang mit New Array() definiert.

                          Jein. "this.inits" wird zwar als leeres Array neu angelegt, wird aber dann mit "FaderFramework.init()" befüllt. Wenn es solche Aufrufe auf Deiner Seite gibt, dann wird "this.inits" damit "vorbeladen", damit nach dem vollständigen Laden der Seite diese vor-eingetragenen Fader-Anforderungen auch umgesetzt werden können, was dann "onload" erledigt.

                          Auf Deiner Seite existiert ein <script>-Bereich, in dem genau ein Fader eingerichtet wird. In diesem Moment enthält "this.inits" einen Array-Eintrag.

                          Also müsste das Skript den Fader gar nicht erstellen? Oder bezieht sich this.inits auf das init?

                          "this.inits" ist ein Array. "init" ist eine Methode des Framework-Objektes. "init" befüllt "inits". Nicht verwechseln! ;-)

                          Ich hab auf meiner Seite verschiedene Bilder mit unterschiedlicher Größe.

                          Mit dem gegenwärtigen Konzept wird das nicht unterstützt. Du müsstest Dir irgendwie mit Tricks behelfen. Das bisherige Konzept geht von identischen Maßen aus...

                          Jetzt will ich aber alle Bilder in der Mitte des divs "akg" haben. Wie ist das mit CSS möglich (steh grad total auf dem Schlauch)?

                          Dazu müsste auch ich das hiesige Archiv befragen... um vielleicht festzustellen, dass das mit CSS nicht in allen Browsern zufriedenstellend klappt. Aber schau mal nach! Das könnte hier weiterhelfen! Wenn Du nämlich eine gute Lösung findest, dann könnte man die in den Fader einbauen.

                          Liebe Grüße,

                          Felix Riesterer.

                          --
                          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
                          1. Ok jetzt ist mir alles klar. Aber wie bei php will ich auch hier learning by doing: Ich will das Skript so erweitern, dass manche Bilder verlinkt sind. Mein Ansatz:

                            // werbung verlinken  
                                    this.link[0] = document.createElement("a");  
                                    this.link[0].href = "http://schwarzwald-logistik.de/";  
                                    this.link[0].title = "SL-Logistik";  
                              
                                    this.link[1] = document.createElement("a");  
                                    this.link[1].href = "http://unimall.de/";  
                                    this.link[1].title = "Unimall";  
                              
                                    // Bilder aus der Liste zu echten Bildobjekten machen und ins <span>-Element einhängen  
                                    for (i = 0; i < einstellungen.images.length; i++) {  
                                        this.images[i] = document.createElement("img");  
                                        this.images[i].src = einstellungen.images[i];  
                                        this.images[i].alt = "";  
                              
                                        // Alle Bilder, außer dem ersten, müssen positioniert werden, damit sie nicht neben oder unter dem ersten angezeigt werden.  
                                        if (i > 0) {  
                                            this.images[i].className = "next";  
                              
                                            // Volle Durchsichtigkeit einstellen (erstes Bild soll ja gleich angezeigt werden  
                                            this.images[i].style.opacity = 0;  
                                            // IE?  
                                            if (this.images[i].style.filter != "undefined") {  
                                                this.images[i].style.filter = "alpha(opacity=0)";  
                                            }  
                                        }  
                              
                                        // einhängen  
                                        if (typeof(this.images[i]) != "undefined")  
                                             {  
                                             this.element.appendChild(this.link[i]); //link element wird in span eingehängt  
                                             this.link[i].appendChild(this.images[i]); // bilder werden in link eingehängt  
                                             }  
                              
                                        this.element.appendChild(this.images[i]);  
                                    }
                            

                            Wieso klappt das jetzt nicht? Was hab ich falsch gemacht? Firefox gibt eine kryptische Fehlermeldung zurück und bricht das Skript ab.

                            Grüße Dominik

                            1. Lieber Dominik,

                              will ich auch hier learning by doing: Ich will das Skript so erweitern, dass manche Bilder verlinkt sind.

                              sehr ehrenwert!

                              Mein Ansatz:

                              // werbung verlinken

                              this.link[0] = document.createElement("a");
                                      this.link[0].href = "http://schwarzwald-logistik.de/";
                                      this.link[0].title = "SL-Logistik";

                              Ich denke da eher an einen init-Aufruf dieser Art:

                              [code lang=javascript]FaderFramework.init({
                                  id: ...,
                                  images: ["erstesBild.jpg", "zweitesBild.jpg"],
                                  hrefs: ["http://erste-werbung.example.org", "http://zweite-werbung.example.org"],
                                  titles: ["Werbung1", "Werbung2"],
                                  random: true
                              });

                                
                              Damit hast Du dann in jedem this.inits[?] ein Objekt mit den üblichen Zutaten PLUS eben Deiner Linkziele samt Titel.  
                                
                              ~~~javascript
                              var a;  
                              for (i = 0; i < einstellungen.images.length; i++) {  
                                  a = document.createElement("a");  
                                  a.href = einstellungen.hrefs[i];  
                                  a.title = einstellungen.titles[i];  
                                
                                  img = document.createElement("img");  
                                  img.src = einstellungen.images[i];  
                                  img.alt = einstellungen.titles[i];  
                                
                                  if (i > 0) {  
                                      img.className = "next";  
                                      img.style.opacity = "0";  
                                      // IE?  
                                      img.style.filter = "alpha(opacity=0)";  
                                  }  
                                
                                  a.appendChild(img);  
                                  this.element.appendChild(a);  
                              }
                              

                              Da wäre dann eigentlich eine andere Objektverschachtelung sinnvoller (weil übersichtlicher und robuster):

                              FaderFramework.init({  
                                  id: ...,  
                                  ads : [  
                                      {  
                                          image: "erstes-bild.jpg",  
                                          href: "http://erste-werbung.example.org/",  
                                          title: "Erstes Werbebanner"  
                                      },  
                                
                                      {  
                                          image: "zweites-bild.jpg",  
                                          href: "http://zweite-werbung.example.org/",  
                                          title: "Zweites Werbebanner"  
                                      }  
                                  ],  
                                  random: true  
                              });
                              

                              Jedoch müsste man dann den Konstruktor wesentlich umbauen, denn es wird jede Werbung als ein eigenes Objekt (bestehend aus Bild-URL, Link-URL und Titel) übertragen. Das wäre dann so:

                              var a;  
                              for (i = 0; i < einstellungen.ads.length; i++) {  
                                  a = document.createElement("a");  
                                  a.href = einstellungen.ads[i].href;  
                                  a.title = einstellungen.ads[i].title;  
                                
                                  img = document.createElement("img");  
                                  img.src = einstellungen.ads[i].image;  
                                  img.alt = einstellungen.ads[i].title;  
                                
                                  if (i > 0) {  
                                      img.className = "next";  
                                      img.style.opacity = "0";  
                                      // IE?  
                                      img.style.filter = "alpha(opacity=0)";  
                                  }  
                                
                                  a.appendChild(img);  
                                  this.element.appendChild(a);  
                              }
                              

                              Firefox gibt eine kryptische Fehlermeldung zurück und bricht das Skript ab.

                              <sarkasmus>Gewöhne Dir bitte garnicht erst an, solche wichtigen Fehlermeldungen zu beachten, und poste sie um Himmels Willen hier auf garkeinen Fall! Das nervt und hilft nicht weiter!</sarkasmus>

                              ;-)

                              Liebe Grüße,

                              Felix Riesterer.

                              --
                              ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
                              1. Hi Felix,

                                Danke für den Ansatz, hat mir sehr geholfen und konnte daher das Skript entsprechend überarbeiten. Es werden jetzt die Links entgegengenommen und in den DOM-Baum eingefügt. Leider wird aber beim Überblenden der Link nicht gewechselt, sondern nur der letzte Link angezeigt. Woran liegt das? Der DOM-Inspektor zeigt an, dass alle <a>-Tags gesetzt sind.
                                Hier der Code:

                                var a, img;  
                                        // Bilder aus der Liste zu echten Bildobjekten machen und ins <span>-Element einhängen  
                                        for (i = 0; i < einstellungen.ads.length; i++) {  
                                  
                                            this.ads[i].a = document.createElement("a");  
                                            this.ads[i].a.href = einstellungen.ads[i].href;  
                                            this.ads[i].a.title = einstellungen.ads[i].title;  
                                  
                                            this.ads[i].img = document.createElement("img");  
                                            this.ads[i].img.src = einstellungen.ads[i].image;  
                                            this.ads[i].img.alt = einstellungen.ads[i].title;  
                                  
                                            if (i > 0) {  
                                            this.ads[i].img.className = "next";  
                                            }  
                                            this.ads[i].img.style.opacity = "0";  
                                            // IE?  
                                            this.ads[i].img.style.filter = "alpha(opacity=0)";  
                                  
                                    this.ads[i].a.appendChild(this.ads[i].img);  
                                    this.element.appendChild(this.ads[i].a);  
                                }  
                                  
                                [...]  
                                  
                                //faden  
                                  
                                imgs[0] = (this.counter == 0) ? this.ads[this.oldPlayList[this.oldPlayList.length -1]].img : this.ads[this.playList[this.counter -1]].img;  
                                            // Das neue Bild ist das, auf welches der Counter zeigt  
                                            imgs[1] = this.ads[this.playList[this.counter]].img;  
                                            for (i = 0; i < imgs.length; i++) {  
                                                v = (i == 0) ? (100 - step) : step;  
                                                imgs[i].style.opacity = v/100;  
                                                // IE?  
                                                if (imgs[i].style.filter != "undefined") {  
                                                    imgs[i].style.filter = "alpha(opacity=" + v + ")";  
                                                }  
                                            }
                                

                                Grüße Dominik

                                1. Lieber Dominik,

                                  Leider wird aber beim Überblenden der Link nicht gewechselt, sondern nur der letzte Link angezeigt. Woran liegt das?

                                  das liegt daran, dass die Links wie ein Stapel Postkarten alle übereinander liegen, sodass der Klick nur auf den obersten Link entgegengenommen wird. Man sieht zwar durch die die Bilder hindurch, da sie vollkommen transparent dargestellt werden (bis auf das aktuell anzuzeigende Bild), jedoch werden die Klicks nicht durch transparente Bilder "hindurchklickbar".

                                  Ich muss meinen Lösungsvorschlag wohl dahingehend ändern, dass zu jedem Bild-Objekt der Titel und der Linkpfad als neue Eigenschaften angehängt werden müssen (damit man später leichter darauf zugreifen kann), und dass der Fader nicht in ein <span>-Element, sondern für Dich in ein <a>-Element gesetzt werden muss, welches dann bei jedem Bilderwechsel sein href-Attribut aktualisiert bekommt.

                                  Kriegst Du das jetzt auch alleine hin?

                                  Liebe Grüße,

                                  Felix Riesterer.

                                  --
                                  ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
                                  1. Also ich habs gelöst. Für interessierte der geänderte Code:

                                    FaderFramework.init({  
                                                    id: "fader",  
                                                    ads: [  
                                                             {  
                                                             image: "bild1",  
                                                             href: "http://link1.com/",  
                                                             title: "Titel von bild1"  
                                                             }  
                                      
                                                             ,  
                                      
                                                             {  
                                                             image: "bild2",  
                                                             href: "http://link2.com/",  
                                                             title: "Titel von bild2"  
                                                             }  
                                      
                                                             [...]  
                                                         ],  
                                                    fadeStep: 2,  
                                                    random: false,  
                                                    viewTime: 10000  
                                                });
                                    

                                    Und das geänderte Framework:

                                    Fader: function (einstellungen) {  
                                        /*  
                                            In diesem Konstruktor verweist "this" immer auf das zu erzeugende Objekt - vorausgesetzt,  
                                            dieser Konstruktor wird mit dem Schlüsselwort "new" aufgerufen, z.B. var a = new this.Fader()  
                                        */  
                                      
                                            // wie "einstellungen" aussehen muss, siehe Funktion "init"!  
                                            var className, imgs, i, r, vorhanden;  
                                      
                                            // Darf eventuell kein Fader eingerichtet werden?  
                                            if (  
                                                // keine ID (oder ein Leerstring) übergeben  
                                                !einstellungen.id  
                                                ||  
                                                // kein HTML-Element mit dieser ID vorhanden  
                                                !document.getElementById(einstellungen.id)  
                                                ||  
                                                // für diese ID ist bereits ein Fader eingerichtet  
                                                FaderFramework.faders[einstellungen.id]  
                                                ||  
                                                // weniger als zwei Bilder angegeben  
                                                einstellungen.ads.length < 2  
                                            ) {  
                                                // also gibt es keinen Fader für diesen init-Aufruf  
                                                return false;  
                                            }  
                                      
                                      
                                            // Einstellungen des Faders vornehmen  
                                            this.id = einstellungen.id;  
                                            this.ads = einstellungen.ads;  
                                            this.images = new Array(); // Bilder werden hier nicht als Zeichenketten, sondern später als HTML-Elementobjekte abgelegt...  
                                            this.random = einstellungen.random ? einstellungen.random : FaderFramework.random;  
                                            this.autostart = (typeof(einstellungen.autostart) != "undefined") ? einstellungen.autostart : FaderFramework.autostart;  
                                            this.viewTime = einstellungen.viewTime ? einstellungen.viewTime : FaderFramework.viewTime;  
                                            this.fadeStep = einstellungen.fadeStep ? einstellungen.fadeStep : FaderFramework.fadeStep;  
                                            this.stopped = false; // hiermit kann später der Fader angehalten werden  
                                            this.playList = new Array(); // Wiedergabeliste  
                                            this.oldPlayList = [0]; // vorherige Wiedergabeliste (besteht aus einem einzigen Bild)  
                                            this.counter = 0; // aktuell angezeigtes Bild (Zähler für Playlist)  
                                      
                                      
                                            // DOM-Baum des HTML-Dokumentes auf den Fader vorbereiten  
                                      
                                            // <a>-Element als Container erzeugen und mit der Fader-Klasse ausrüsten  
                                            this.element = document.createElement("a");  
                                            this.element.className = FaderFramework.className;  
                                      
                                            // vor das ursprüngliche Bild setzen  
                                            i = document.getElementById(this.id); // ursprüngliches Bild  
                                            i.parentNode.insertBefore(this.element, i);  
                                      
                                            // ursprüngliches Bild entfernen  
                                            i.parentNode.removeChild(i);  
                                      
                                            var a, img;  
                                            // Bilder aus der Liste zu echten Bildobjekten machen und ins <span>-Element einhängen  
                                            for (i = 0; i < einstellungen.ads.length; i++) {  
                                      
                                                this.ads[i].img = document.createElement("img");  
                                                this.ads[i].img.src = einstellungen.ads[i].image;  
                                                this.ads[i].img.alt = einstellungen.ads[i].title;  
                                      
                                                if (i > 0) {  
                                                this.ads[i].img.className = "next";  
                                                }  
                                                this.ads[i].img.style.opacity = "0";  
                                                // IE?  
                                                this.ads[i].img.style.filter = "alpha(opacity=0)";  
                                                this.ads[i].img.style.border = "0";  
                                      
                                        this.element.appendChild(this.ads[i].img);  
                                    }  
                                      
                                    ##[...}##  
                                      
                                    this.fade = function (step) {  
                                                var imgs = new Array(), v;  
                                      
                                                // Wenn kein Wert übertragen wurde, dann muss das Fading von vorne durchgeführt werden  
                                                step = (!step) ? 0 : step;  
                                                if (step == 0)  
                                                     {  
                                                     this.element.removeAttribute("href");  
                                                     }  
                                                // Das letzte Bild steht in der Liste vor dem aktuellen (falls dieses ganz am Anfang steht, gilt das letzte der alten Playlist)  
                                                imgs[0] = (this.counter == 0) ? this.ads[this.oldPlayList[this.oldPlayList.length -1]].img : this.ads[this.playList[this.counter -1]].img;  
                                                // Das neue Bild ist das, auf welches der Counter zeigt  
                                                imgs[1] = this.ads[this.playList[this.counter]].img;  
                                                for (i = 0; i < imgs.length; i++) {  
                                                    v = (i == 0) ? (100 - step) : step;  
                                                    imgs[i].style.opacity = v/100;  
                                                    // IE?  
                                                    if (imgs[i].style.filter != "undefined") {  
                                                        imgs[i].style.filter = "alpha(opacity=" + v + ")";  
                                                    }  
                                                }  
                                      
                                                step += this.fadeStep;  
                                      
                                                if (step <= 100) {  
                                                    // nächsten Fade-Schritt ausführen  
                                                    window.setTimeout(""  
                                                        + "FaderFramework.faders."  
                                                        + this.id  
                                                        + ".fade("  
                                                        + step  
                                                        + ");",  
                                                    1);  
                                                } else {  
                                                    // Bildübergang abgeschlossen -> nach der Pause nächstes Bild  
                                                    this.element.href = einstellungen.ads[this.playList[this.counter]].href;  
                                                    this.element.title = einstellungen.ads[this.playList[this.counter]].title;  
                                                    window.setTimeout(""  
                                                        + "FaderFramework.faders."  
                                                        + this.id  
                                                        + ".next();",  
                                                    this.viewTime);  
                                                }  
                                            };
                                    

                                    Außerdem müssen alle this.images.length durch this.ads.length ersetzt werden.

                                    Grüße Dominik

                                    1. Lieber Dominik,

                                      Also ich habs gelöst.

                                      Du hast ne Menge dazugelernt! Bin stolz auf Dich!

                                      Liebe Grüße,

                                      Felix Riesterer.

                                      --
                                      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  6. Da ich das Thema jetzt über eine Woche lang ausgearbeitet und inzwischen meine zweite Version meines Artikels eingeschickt habe, denke ich doch, dass man irgendwann unter http://aktuell.de.selfhtml.org/artikel/javascript/fader-framework/ das Endergebnis finden wird.

    Bin schon mächtig auf das Feedback der Redaktion diesmal gespannt.

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. http://aktuell.de.selfhtml.org/artikel/javascript/fader-framework/ >

      Bin schon mächtig auf das Feedback der Redaktion diesmal gespannt.

      Hallo Felix.
      Leider bekomme ich (noch) einen 404 Status. Aber ich werde gewiss das lesen, sobald der Artikel richtig online ist.

      mfg Beat

      --
      Woran ich arbeite:
      X-Torah
      ><o(((°>    -  ><o(((°>
         <°)))o><                      ><o(((°>o
      1. Liebe(r) Beat,

        http://aktuell.de.selfhtml.org/artikel/javascript/fader-framework/

        Leider bekomme ich (noch) einen 404 Status.

        die Review-Version (beta-Status) findest Du momentan hier:
        http://aktuell.de.selfhtml.org/artikel/review/fader-framework/

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        1. die Review-Version (beta-Status) findest Du momentan hier:
          http://aktuell.de.selfhtml.org/artikel/review/fader-framework/

          Meine belanglosen Kommentare (1.Hälfte)

          Abschnitt: Eine einfache Animation: Ladebalken
          im Beispiel:
          besser dem Ladebalken ein border: 1px solid black verpassen

          Codebeispiel:
          Aus didaktischen Gründen wäre ein Doctype empfehlenswert.

          Unterabschnitt
          "Zwei Fader auf derselben Seite"
          Im Beispiel kann ich die gleiche Slideshow mehrfach starten. Das sollte nicht möglich sein.

          mfg Beat

          --
          Woran ich arbeite:
          X-Torah
          ><o(((°>        ><o(((°>
             <°)))o><                      ><o(((°>o
          1. Liebe(r) Beat,

            Abschnitt: Eine einfache Animation: Ladebalken
            im Beispiel:
            besser dem Ladebalken ein border: 1px solid black verpassen

            ist für das Nachverfolgen des Beispiels für Anfänger unerheblich. Aber ich denke darüber nach.

            Codebeispiel:
            Aus didaktischen Gründen wäre ein Doctype empfehlenswert.

            Ja, der wird im weiteren Verlauf durchaus unersetzlich...

            "Zwei Fader auf derselben Seite"
            Im Beispiel kann ich die gleiche Slideshow mehrfach starten. Das sollte nicht möglich sein.

            Das ist eine Design-Schwäche des Scripts, die aber unter "Beachten Sie" angesprochen wird. Erst im weiteren Verlauf des Lehrgangs wird dieser Designfehler in Angriff genommen - immerhin soll der Lehrgang von einfachen zu komplexen Strukturen führen.

            Was ich mir aber gedacht habe: Die Methode "slideShow" könnte ich ebenso entsorgen, wie ich sie auch im Komfort-Fader nicht mehr habe. Die ist unnötiger Ballast und macht den Design-Fehler nur noch schwerer erkennbar.

            Eventuell sollte ich "fading" schon in den früheren Beispielen einbringen, um diesen Designfehler früher im Lehrgang zu korrigieren...?  Was meinst Du dazu?

            Liebe Grüße,

            Felix Riesterer.

            --
            ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        2. die Review-Version (beta-Status) findest Du momentan hier:
          http://aktuell.de.selfhtml.org/artikel/review/fader-framework/

          Einige Anmerkungen.

          Ein Konstruktor ist keine Fabrikmethode, im gegenteil eine Factory ersetzt den Kontruktor.

          Bei den Beispielen solltest du deutlich unterscheidbarere Bilder nehmen, ich hab Schwierigkeiten den Effekt überhaupt wahrzunehmen.

          Die Zeilen hat Mathias schon moniert:

                              if (this.images[i].style.filter != "undefined") {  
                                  this.images[i].style.opacity = v/100;  
                                  this.images[i].style.filter = "alpha(opacity=" + v + ")";  
                              }  
          
          

          Das Skript funktioniert im FF nur, weil dein Test auf die filter Eigenschaft falsch ist. Wenn müßte es heißen:

            
          if (typeof this.images[i].style.filter != "undefined")  
             this.images[i].style.filter = "alpha(opacity=" + v + ")";  
            
          this.images[i].style.opacity = v/100;  
          
          

          Aber du kannst die Prüfung auch komplett weglassen, die Browser stört es nicht, wenn du dem style Objekt eine unbekannte Eigenschaft zuweist.

          Ich würde das FaderFramework Objekt mit new function() {...} erstellen, das hat den Vorteil, dass du in dem Konstruktor immer this bzw. deren Kopie verwenden kannst (falls du FaderFramework mal umbenennst, ist das hilfreich) und das du in der Funktion lokale Variabeln benutzen kannst.

          Und eine klein Kleinigkeit:
          oldWinOnLoad: false,
          Das gegenteil von einer Funktionsreferenz ist meiner Meinung null, nicht false, kommt zwar auf's gleiche raus, aber mich stört sowas ;-)

          Struppi.

          1. Lieber Struppi,

            vielen Dank für Deine hilfreichen Anmerkungen! Ich werde sie einarbeiten.

            Ein Konstruktor ist keine Fabrikmethode, im gegenteil eine Factory ersetzt den Kontruktor.

            Dann habe ich den Wikipedia-Artikel wohl falsch verstanden. Aber das macht nichts, ich werde die entsprechende Bemerkung einfach entfernen. Der Hinweis nützt einem Anfänger an dieser Stelle sowieso nicht weiter.

            Bei den Beispielen solltest du deutlich unterscheidbarere Bilder nehmen, ich hab Schwierigkeiten den Effekt überhaupt wahrzunehmen.

            Zugegeben, die Überblendung ist bei manchen Überblendgeschwindigkeiten nicht besonders gut sichtbar. Ich hatte die Bilder ausgesucht, da man den Lauf der Sonne beobachten kann, um so die regelmäßige, oder die zufällige Bilderreihenfolge zu erkennen. Ich werde mir wohl über eine Alternative Gedanken machen müssen...

            Die Zeilen hat Mathias schon moniert:

            if (this.images[i].style.filter != "undefined") {

            [...]
            Aber du kannst die Prüfung auch komplett weglassen, die Browser stört es nicht, wenn du dem style Objekt eine unbekannte Eigenschaft zuweist.

            Hmm. Davor hatte ich bisher immer zurückgeschreckt, da ich zumindest in der Fehlerkonsole des Firefox diese CSS-Warnungen erwartet hätte. Aber den Scriptablauf als solches stören solche Zuweisungen sicherlich nicht, da sie keine JavaScript-Fehler erzeugen. Hmm... überredet.

            Ich würde das FaderFramework Objekt mit new function() {...} erstellen, das hat den Vorteil, dass du in dem Konstruktor immer this bzw. deren Kopie verwenden kannst (falls du FaderFramework mal umbenennst, ist das hilfreich) und das du in der Funktion lokale Variabeln benutzen kannst.

            Das ist jetzt genau der nächste Schritt, den ich bei meinem bisherigen Wissensstand zu objektorientierter Programmierung noch nicht gegangen bin. Die Formulierung "dass du in dem Konstruktor immer this bzw. deren Kopie verwenden kannst" habe ich deshalb noch nicht völlig begriffen. Meinst Du "this" außerhalb des Konstruktors "Fader" ist dann immernoch nicht das Gleiche, wie "this" innerhalb des Konstruktors "Fader"? Und verstehe ich Dich richtig, dass Du die Objektinstanziierung (heißt das so?) in einem "anonymen Konstruktor" vornimmst? Und wo genau meinst Du, ich könne "in der Funktion lokale Variablen benutzen"?

            [code lang=javascript] oldWinOnLoad: false,

            
            > Das gegenteil von einer Funktionsreferenz ist meiner Meinung null, nicht false, kommt zwar auf's gleiche raus, aber mich stört sowas ;-)  
              
            Naja, `typeof false`{:.language-javascript} ergibt "Boolean", während bei `typeof null`{:.language-javascript} "object" herauskommt. Beides ist `!= "function"`{:.language-javascript}, auch wenn eine Funktion eher ein Objekt, denn ein Bool'scher Wert ist - da hast Du sicherlich Recht.  
              
            Du hast mir wieder einmal wertvolle Hinweise gegeben, die mich weiter bringen. Vielen Dank dafür!  
              
            Liebe Grüße,  
              
            Felix Riesterer.
            
            -- 
            ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
            
            1. Ich würde das FaderFramework Objekt mit new function() {...} erstellen, das hat den Vorteil, dass du in dem Konstruktor immer this bzw. deren Kopie verwenden kannst (falls du FaderFramework mal umbenennst, ist das hilfreich) und das du in der Funktion lokale Variabeln benutzen kannst.

              Das ist jetzt genau der nächste Schritt, den ich bei meinem bisherigen Wissensstand zu objektorientierter Programmierung noch nicht gegangen bin. Die Formulierung "dass du in dem Konstruktor immer this bzw. deren Kopie verwenden kannst" habe ich deshalb noch nicht völlig begriffen. Meinst Du "this" außerhalb des Konstruktors "Fader" ist dann immernoch nicht das Gleiche, wie "this" innerhalb des Konstruktors "Fader"? Und verstehe ich Dich richtig, dass Du die Objektinstanziierung (heißt das so?) in einem "anonymen Konstruktor" vornimmst? Und wo genau meinst Du, ich könne "in der Funktion lokale Variablen benutzen"?

              zu 1.)  Ich meine damit, dass du überalll wo FaderFramework verwendest entweder this oder eine Referenz darauf verwenden kannst.

              zu 2.) joh, kann man so nennen. das ist übrigens ein Entwurfsmuster ;-)

              zu 3.) Hier mal ein code Beispiel mit einer privaten Variabel, Funktion und einer Referenz auf this, die du brauchst z.b. für die Eventhandler

              var myObj = new function() {  
              var myPrivateVar = '';  
              var self = this; // Die Referenz auf this  
              function myPrivateFunc() {  
              /* ... */  
              }  
              };  
              
              

              Struppi.

              1. Lieber Struppi,

                var myObj = new function() {

                var myPrivateVar = '';
                var self = this; // Die Referenz auf this
                function myPrivateFunc() {
                /* ... */
                }
                };

                  
                da müsste ich jetzt einmal ausprobieren, ob ich mit "self" (in diesem Beispiel) aus dem Konstruktor heraus auf die Voreinstellungen im Framework zugreifen kann.  
                  
                Mann, das wird immer komplexer! O\_o  
                  
                Liebe Grüße,  
                  
                Felix Riesterer.
                
                -- 
                ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)