Zur Browserverbreitung, gibt es ja Einiges im Web, aber diese Darstellung ist eine der Besten, die zu finden war, sie berücksichtigt nicht nur die absolute Menge von Browsern, sondern enthält auch die einzelnen Browserversionen in einer Übersicht.

(Das Bild anklicken um sie als Interaktive Statistik zu öffnen.)

Basis für die Statistik sind die monatlichen zahlen, der W3 School. Leider gilt sie nur für Europa, weltweit sieht das vermutlich anders aus, so ist z.B. in Südamerika Google Chrom mittlerweilen bereits auf Platz1 in der Statistik für Marktanteile. Die Fachwelt prognostiziert Dieses auch für alle anderen Kontinente bis auf Asien, bis Ende 2012.

 
tt013

In dem Post vom 27.2.2012, habe ich einen Flashplayer vorgestellt, mit dem man auch Cuepoints ansteuern kann die Bestandteil einer Flash .flv-Dateien sind. Man kann die Punkte nicht nur direkt ansteuern, sondern es können auch Daten, die mit den Punkten verbunden sind angezeigt werden, sobald der Film einen Cuepoint überläuft. Diese Cuepoints sind eine Flash-spezifische Eigenheit, die in anderen Videoformaten nicht vorhanden sind. Da unser Kunde seine Videos aber auch auf iPads anschaun möchte, brauchten wir

Cuepoints für einen HTML5-Player.

Hier gehts zu unserer Beispielanwendung

Unser Beispiel verwendet zwar keine echten Flash Cuepoints sondern eine Javascript Ersatz für Cuepoints, funktioniert aber tatsächlich genauso gut. Sie hat gegenüber der Flash Version, sogar den Vorteil, das die Punkte nicht Bestandteil des Videos sein müssen sondern auch noch nachträglich beim Aufruf der Seite gesetzt werden können, was diese HTML5 Variante sogar flexibler macht als die Flash Version und sie läuft natürlich, wie alle HTML5 Player, auch auf dem iPad.

Und so sieht der Scriptcode aus:

(function() {
   var Cuepoint, Utils, utils;
    Utils = (function() {
        function Utils() {}
        Utils.prototype.log = function(args) {
            this.args = args;
            if (window.console) {
                return console.log(Array.prototype.slice.call(this, arguments));
            }
        };
        return Utils;
    })();
    Cuepoint = (function() {
        function Cuepoint() {
            this.nativeKeys = Object.keys;
        }
        Cuepoint.prototype.init = function(slides) {
            var key, value, _results;
            this.slides = slides;
            this.subtitles = document.getElementById("subtitles");
            this.video = document.getElementById("video");
            _results = [];
            for (key in slides) {
                value = slides[key];
                this.addSlide(key, value);
                _results.push(this.events.call);
            }
            return _results;
        };
        Cuepoint.prototype.events = function() {};
        Cuepoint.prototype.currentTime = function() {
            return this.video.currentTime;
        };
        Cuepoint.prototype.update = function(html) {
            this.html = html;
            return this.subtitles.innerHTML = this.html;
        };
        Cuepoint.prototype.setTime = function(time) {
            this.time = time;
            this.video.currentTime = time;
            return this.video.play();
        };
        Cuepoint.prototype.addSlide = function(time, html) {
            var self;
            this.time = time;
            this.html = html;
            self = this;
            return this.video.addEventListener("timeupdate", function() {
                if (this.currentTime >= time && this.currentTime <= time + 0.3) {
                    return self.update(html);
                }
            },
            false);
        };
        Cuepoint.prototype.play = function() {
            return this.video.play();
        };
        Cuepoint.prototype.pause = function() {
            if (!this.video.paused) {
                return this.video.pause();
            }
        };
        return Cuepoint;
    })();
    utils = new Utils;
    window.cuepoint = new Cuepoint;
}).call(this);

Dann brauchen wir noch die Ready Funktion, die das Javascript aus der HTML Seite aufruft:

Dieses Script wird im Header der .html-Datei eingefügt, die den HTML5 Player enthält.

<script>
$(document).ready(function(){
//Slides object mit time (integer) und html string
var slides = {
15: "Etno",
25: "Kurierstyle",
36: "Madona",
47: "Moskau",
60: "Nostalgie",
71: "Bikerstyle",
79: "kitzbühl",
85: "Vienna",
89: "Firenze",
94: "Davos",
102: "Firenze",
110: "Sorbet",
122: "Las Vegas",
128: "Schuhe",
137: "Beautycase"
}
//cuepoints starten und die Subtitles übergeben.
cuepoint.init(slides);

//Hier sind die Aufruffunktionen die natürlich auf der Seite platziert sein müssen cuepoint.setTime(seconds) function
$('#1').click(function(){ cuepoint.setTime(15)});
$('#2').click(function(){ cuepoint.setTime(25)});
$('#3').click(function(){ cuepoint.setTime(36)});
$('#4').click(function(){ cuepoint.setTime(47)});
$('#5').click(function(){ cuepoint.setTime(60)});
$('#6').click(function(){ cuepoint.setTime(71)});
$('#7').click(function(){ cuepoint.setTime(79)});
$('#8').click(function(){ cuepoint.setTime(85)});
$('#9').click(function(){ cuepoint.setTime(89)});
$('#10').click(function(){ cuepoint.setTime(94)});
$('#11').click(function(){ cuepoint.setTime(102)});
$('#12').click(function(){ cuepoint.setTime(110)});
$('#13').click(function(){ cuepoint.setTime(122)});
$('#14').click(function(){ cuepoint.setTime(128)});
$('#15').click(function(){ cuepoint.setTime(137)});
});
</script>

Und natürlich der HTML5 Player, der innerhalb des <body> Tags, wo auch immer platziert wird:

<section id='cuePlayer'>
        <video id='video' width="100%" preload="auto" controls="controls" poster="http://addit-media.net/new/uploads/francoroma/VideoJukebox/p0000005673_2.jpg" autoplay="autoplay">
            <source src='http://addit-media.net/new/uploads/francoroma/VideoJukebox/Sources/liquides-desktop.mp4' type="video/mp4" />
            <source src='http://addit-media.net/new/uploads/francoroma/VideoJukebox/Sources/liquides-desktop.ogg' type="video/ogg" />
        </video>
    <div id='subtitles'></div>
 </section>

Ebenso, wie die Links, zum Aufruf der Cuepoints natürlich irgendwo innerhalb des HTML Codes stattfinden müssen, etwa so:

<ul>
    <li><h3><a id="1" href="#">play Etno</a></h3></li>
    <li><h3><a id="2" href="#">play Kurierstyle</a></h3></li>
    <li><h3><a id="3" href="#">play Madona</a></h3></li>
    <li><h3><a id="4" href="#">play Moskau</a></h3></li>
    <li><h3><a id="5" href="#">play Nostalgie</a></h3></li>
    <li><h3><a id="6" href="#">play Bikerstyle</a></h3></li>
    <li><h3><a id="7" href="#">play Kitzbühl</a></h3></li>
    <li><h3><a id="8" href="#">play Vienna</a></h3></li>
    <li><h3><a id="9" href="#">play Firenze</a></h3></li>
    <li><h3><a id="10" href="#">play Davos</a></h3></li>
    <li><h3><a id="11" href="#">play Firenze</a></h3></li>
    <li><h3><a id="12" href="#">play Sorbet</a></h3></li>
    <li><h3><a id="13" href="#">play Las Vegas</a></h3></li>
    <li><h3><a id="14" href="#">play Schuhe</a></h3></li>
    <li><h3><a id="15" href="#">play Beautycase</a></h3></li>
    </ul>

Was gibt's noch? ach ja, das DIV, mit der Id = 'subtitles', wird in unserem Beispiel natürlich mit display='absolute' angezeigt, damit es über dem Video liegt.

 

 
tt012

Die Jquery Komponente für Steve Rowland ist für Fotos schon sehr gut, aber da ich mehr und mehr Videos zu produzieren habe, mußte das Steve Rowland Photography Frontend noch um die Möglichkeit erweitert werden, Videos abzuspielen. Da ich ein Frontend haben möchte das auf jedem Endgerät läuft, habe ich den

Player als HTML5-Mediaelement Jquery-Erweiterung,

in das bestehende Jquery-Frontend integriert. Wie das geht und wie man das Ganze mit Gallery2, als Assetmanagement adminstriertbar macht, ist Thema dieses Posts. Das Video veranschaulicht, wie das Handling des Frontends arbeiten muß: 1. Video wird ausgewählt. 2. Das <img> wird durch einen <video> Element ersetzt. 3. Das Video wird abgespielt, sobald der Ladezustand soweit fortgeschritten ist, das der Film ohne Pause durchlaufen kann 4. Ein anderes Video wird ausgewählt. 5. Die <source> Elemente des <Video> Elements, werden durch die neuen <source> Elemente ersetzt und neu geladen. 6. wie 3. 7. Wird ein Thumbnail ausgewählt, das ein Foto referenziert, wird das <video> Element wieder durch das <img> Element ersetzt.

Wer das ganze mit seiner eigenen Gallery durchexerzieren möchten, muss natürlich die URL: http://www.steverowland.net/gallery2, durch seine eigene Gallery2 Installations-URL ersetzen. Wer keine Gallery2 als Assetmanagement verwenden möchte, kann das Frontend auch in einer Standalone-Version, ganz am Ende des Posts herunterladen, und ohne Gallery2 verwenden. Der Post beschreibt aber die Variante, wie ich sie auf der Steverowland.net installiert habe, also mit Gallery2 Assetmanagement.

1. Gallery2

Die letzte stabile Version 2.3.1, am Besten gleich die Developer Version(mit Alles), von Gallery2, hier herunterladen. und auf dem Server instalieren. Es gibt auch Gallery3, was aber keine neue Version von Gallery2, sondern eine andere Bildergallerie, die mit einer anderen Programmarchitektur programmiert wurde darstellt, die eher geeignet ist, wenn man schnell eine Bildergallery ins Netz stellen will. Wir benötigen die wesentlich umfangreichere API von Gallery2, um das als Admininterface für das Jquery umstricken zu können. Die installation ist eigentlich selbsterklärend, wer Schwierigkeiten hat, hier gibts die ausgezeichnete Dokumentation für Gallery2. Welches Thema man wählt ist eigentlich egal, denn der User wird die Gallery ohnehin nicht betreten, man sollte also ein Thema wählen, mit dem man selbst eine gute Übersicht behält. Im Gegensatz dazu, werden ALLE verfügbaren Plugins(Module), incl. URL-Rewrite installiert (sind unter der gleichen URL gelistet, wie die Core, aber alle Bestandteil der Developer Version) und richtig konfiguriert.  Um Gallery2 wirklich perfekt zum laufen zu kriegen, wären folgende Server Applications zu empfehlen: GD-Library(stellt Bildbearbeitung funktionen zur Verfügung), ImageMagick(Ist sozusagen die "Platin-Edition" zu GD), Jpegtran (Kann Jpegs verlustfrei umrechnen). Da auch die Adminstration von Filmen vorgesehen ist, wäre auch die ffmpeg-Extension zu empfehlen, dafür sollte zusätzlich 'ffmpeg' auf dem Server installiert sein. Alle Pfade zu den Binaries der gelisteten Server-Apps, müssen als Ressource-Pfade, PHP zur Verfügung stehen.(Wird in der php_ini gesetzt), Wer keine Root Zugang zum Server hat, muss seinen Serveradmin entsprechend instruieren. Gallery2 würde auch ohne das Alles grunsätzlich funktionieren und Standarts bieten, aber mit diesen Tools, ist es ein echtes 'Bildbearbeitungs-Brett', von herrausragender Qualität und Performance, das auch für hochprofessionelles Assetmanagement, keine Wünsche offen lässt.

2. Simpleviewer Source Extension

Es gibt eine Gallery2 Extension, die eigntlich zu einem Flash Imageslider gehört, die SimpleviewerSource. Diese ist nicht Bestandteil der Offiziellen Repository und müsste man sich aus den Community-Extensions besorgen. Allerdings ist eine größeres PHP-Workaround notwendig, wenn man die Original-Erweiterung verwendet, deshalb kann man sich meine, bereits umgenbaute Version herunterladen und diese installieren. Diese kann allerdings nicht im "normalen" Plugin installationsprozess von Gallery2 installiert werden, sondern wird Gallery2, wie folgt zugeführt.

Instalation: 1. zip Datei hier herunterladen 2.zip auspacken und Ordner in das Verzeichnis [Gallery installationspfad]/modules auspacken, oder zip hochladen und im Verzeichnis auspacken. 3. In der Site-administration, Module auswählen. Jetzt ist die Erweiterung SimpleviewerSource unter 'Exportieren', verfügbar und kann aktiviert werden.

VORSICHT!!! Die Nummer funktioniert nur, weil Simpleviewer Source eine "offizielle Extension" ist, der wir ein Kuckuks-Ei unterschieben, in der GalleryFactory wird Simpleviewer Source als ordentlich Extension in Gallery2 registriert, man kann also nicht einfach irgendeinen Ordner anlegen, der dann von Gallery2 als Extension wahrgenommen wird. Wahlweise, kann man natürlich auch die Extension übers Backend installieren und anschliessend die Moduldateien, per ftp-Upload mit den modifizierten überschreiben.

Man kann auch ein eigenes Modul für Gallery2 schreiben, aber SimpleviewerSource, hat bereits fast alles was wir brauchen, Was, Wie, Warum genau diese Extension bietet, würde hier den Rahmen sprengen und eher Thema für einen eigenen Post, aber SimpleviewerSource erstellt eine XML-struckturierte Ausgabe, der kompletten Gallery, die eigentlich als URL für  den HTTP-Request dier Flash Datei gedacht ist und genau DIESE, bietet auch das perfekte Datenmodel für den View, den wir dem Modul hinzufügen. Man muss keinen der SimpleviewerSource Konfigurationsparameter ausfüllen oder setzen, da diese von der überarbeiteten Version schlicht übergangen werden!

3. Die Views

Gallery2 ist in MVC Architektur programmiert. Das Model sowie Controller, sind schon im Modul vorhanden, wir müssen dem Modul nur einen View hinzufügen, analog zum XMLOut View hab ich ihn HTMLOut genannt und er erweitert die GalleryView Class, die Datei die ihn beinhaltet, heisst dann nach Gallery2-API HTMLOut.inc. Der einzige Parameter der an den Controller übergeben wird, ist die Id, des Album Elements für den wir den View haben mölchten. Im Gegensatz zur XMLOut, die ein Album und deren Fotoelemente darstellt, habe ich den HTMLView um eine Hirarchie erweitert, es wird also eine Album mit dessen Unteralben und die Bilder in den Unteralben ausgelesen werden, um das Datenmodel, wie es für die JQuery-Ausgabe benötigt wird, zu erhalten. Eine Möglichkeit das neu Frontend anzuzeigen besteht nun darin, den View direkt mit der ItenId des Portfolios (in diesem Fall ist das die 1051) aufzurufen. Die Gallery2-API setzt noch Prefix davor, also g2_view und g2_itemId, wodurch der komplette Aufruf so aussieht:

http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.HTMLOut&g2_itemId=1051

Ausserdem brauchen wir, für die Thumbnailnavigation einen View, der die Thumbnails der Bilder in den Subalben zeigt, z.B. so:

http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&g2_itemId=3561

dieser wird in das jeweilige img.src attribut eingetragen.

Beim Click auf das Thumbnail, soll das Hintergrund Bild geladen werden, das Jquery verwendet dazu den Wert im img.alt Attribut des jeweiligen Thumbnails. Wir brauchen also noch einen weiteren View, nämlich den, der das große Bild zeigt. Bestandteil der SimpleviewerSource, wäre der View, downloadMax View, wobei dieser dem DownloadItem View der Core, um die beiden Parameter g2_maxImageHeight und g2_maxImageWidth erweitert entspricht. Da diesen hier keine Bedeutung zukommt, da die Bildgröße nicht von Gallery2, sondern durch das Jquery an die jeweilige Screengröße angepasst wird, kann man genausogut den View der Core verwenden.

http://www.steverowland.net/gallery2/main.php?g2_view=core.DownloadItem&g2_itemId=3561

Da der Aufruf innerhalb des Gallery Root Pfades erfolgt, würden auch die relative Pfade genügen, hier aus dem Blog müssen wir natürlich absolut verlinken. Auch ganz ohne Views, wäre es theoretisch möglich, auf die Items zuzugreifen, ein paar Beispiele:

Dieser Code etwa: <a href="http://www.steverowland.net/gallery2/v/show/crist/1967_ORDER03.jpg.html" ><img src="http://www.steverowland.net/gallery2/d/4314-2/1967_ORDER03.jpg" alt="1967_ORDER03" /></a>, das kleine v steht für view, show/ ist das oberste Album, crist/ ist das subalbum, 1967_ORDER03.jpg ist der Bildname und .html, zeigt, das nicht das Bild sondern die Fotoseite des Bildes angezeigt wird. Im src attribut des angezeigten Bildes steht das d/ für "download", was immer ein Bild zeigt, wärend v/ den g2_view des Bildes zeigt. In HTML ausgeführt, wird hier ein clickbares Thumbnail gezeigt, das auf die Photoseite des Items verlinkt und sieht so aus:

1967_ORDER03

Oder dieser Code: <a href="http://www.steverowland.net/gallery2/d/4313-1/1967_ORDER03.jpg"><img src="http://www.steverowland.net/gallery2/d/4316-2/1967_ORDER03.jpg" alt="1967_ORDER03" /></a>. Sowohl das href als auch das src zeigen ein Bild(d/). In diesem Fall, die erste Zwischengrösse, clickbar, mit Verweis zur Originaldatei. was in HTML so aussieht:

1967_ORDER03

Dieser Code würde hier in HTML, den Blog sprengen: <img src="http://www.steverowland.net/gallery2/d/4313-1/1967_ORDER03.jpg" alt="1967_ORDER03" /> er würde direkt die Originaldatei hier anzeigen, wie am href Attribut des vorherigen Beispiels deutlich zu sehen ist. Wer's nicht glaubt, kann ja den Wert der src, direkt ins Browser Adressfenster kopieren. Die URL-Rewrite Regeln für Gallery2, lassen sich in der Siteadministration derselben auch umdefinieren.

Damit haben wir die URLs, die wir im HTML Code der jquery extension in das src und das alt atribut des jeweilegen Thumbs eintragen müssen. Ein Listenelement könnte also, in etwa so aussehen, wobei ich aus Übersichtsgründen, die cufon-wraps weggelassen habe und hier der simpleviewerSource View eingetragen ist, was wie gesagt, in diesem Fall das gleiche Resultat liefert:

<li class="album">
<span class="st_link">Cover-shooting, D&W Katalog 2002, Milano <span class="st_arrow_down"></span></span>
<div style="overflow: hidden;" class="st_wrapper st_thumbs_wrapper">
<div style="width: 1098px;" class="st_thumbs">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4791" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4791" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4796" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4796" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4800" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4800" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4804" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4804" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4812" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4812" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4816" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4816" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
</div>
</div>
</li>

Jetzt sollte auch deutlich werden, warum diese Gallery äusserst Suchmaschinen optimal ist, den auf diese Weise, sind tatsächlich alle relevanten Bild und Albumparameter, bereits in dieser einen Datei vorhanden und direkt vom Googlebot Indizierbar, ohne weitere Aktion oder einer Substitution der Calls durch Snapshots für den Googlebot, wie das für Flash notwendig wäre.

Damit sieht, der View ja schonmal aus, wie die gewünschte Ausgabe und ist es ja auch, aber…

http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.HTMLOut&g2_itemId=1051

… sie soll ja eigentlich mit der folgenden URL aufgerufen werden:

http://www.steverowland.net/gallery2/portfolio.php

Die URL sieht nicht nur besser aus, sondern hat auch den Vorteil, das es auch ausserhalb des Gallery2-Instalationspfades funktionieren würde, was mit dem View nicht geht. Aber dazu fehlt noch die Datei "portfolio.php", eine sog. Wrapper-Datei.

4. Die Wrapper Datei

Ruft man Gallery2 auf, erfolgt normalerweise ein Aufruf der Datei 'main.php'. View und Item werden als URL Parameter, an diese übergeben. Aber Gallery2 kann auch eingebettet, in einer anderen Anwendung, oder mit einer anderen Anwendung über ein event-based loose coupling verbunden, aufgerufen werden. In diesem Fall, wird Gallery2 nicht über die 'main.php', sondern über die 'embed.php' aufgerufen. Damit wird die 'bootstrap.inc' nicht zuerst eingebunden und die Gallery2 Ausgabe kann in ein andere Datei, oder eine andere Anwendung, umgeleitet werden. Diese kann in einem anderen Verzeichnis, muß aber auf der selben Domain liegen (auch keine Subdomain). Wird Gallery2 in eine andere Anwendung geleitet, läuft Gallery2 'eingebettet". Wird Gallery2 über ein coupling verbunden findet die Ausgabe von Gallery2 und die der verbundenen Anwenndung, in einer weiteren Datei statt. Diese Datei nennt man Wrapper Datei.

Die Datei muss folgendes enthalten:

<?php

// der relative Pfad zum Gallery-Root Verzeichnis (in diesem Fall befinden sich die wrapper-Datei im Gallery-Root Verzeichnis)

$g2_Config['path'] = dirname(__FILE__) . '/';  

// Den Rootpath der Gallery2 installation, allso von der Domain-Root zum Gallery-Root Verzeichnis.

$g2_Config['g2Uri'] = '/gallery2/';

// und den embed Pfad, also von der Domain-root zur wrapper Datei, damit lassen sich alle anderen Relation herstellen.

$g2_Config['embedUri'] = '/gallery2/portfolio.php'; 

// Dann wird die embed.php eingebunden.

require_once( $g2_Config['path'] . 'embed.php');

// Wir schicken einen HTML Header

if (!headers_sent()) {
    header('Content-Type: text/html; charset=UTF-8');
}

// Durch die init, wird ein Status in der Gallery erzeugt, der aufrufe verarbeiten kann und

$ret = GalleryEmbed::init(array('fullInit' => true));
check($ret);
GalleryCapabilities::set('login',true);

// Eine Instanz der Gallerie laden und autifizieren.

/* Grab the authToken */
global $gallery;
$session =& $gallery->getSession();
$authToken = $session->getAuthToken();

// die Request Varialblen direkt an den entsprechenden view übergeben.

GalleryUtilities::putRequestVariable('view', 'simpleviewersource.HTMLOut');
GalleryUtilities::putRequestVariable('itemId', '1051');

// Und die Anfragen von den definierten Controllern bearbeiten lassen

$data = GalleryEmbed::handleRequest();

// Die $data, enthält jetzt die Daten unserer Ausgabegallerie, bis auf das Thema. Da hier MVC, konsequent durchgezogen wurde, besteht eine 100% Trennung, zwischen Form und Inhalt. Wobei $data['headHtml'] die Headerdaten und $data['bodyHtml'] die Bodydaten enthält.

// Da wir wegen einer möglichen Video Ausgabe eine HTML5 Ausgabe möchten, Gallerie aber ein HTML4 Ausgabe schicken würde, haben wir das komplette HTML im View integriert und geben diesen auch wieder komplett als HTML aus.

function check($ret) {
    if ($ret) die($ret->getAsHtml());
}

?>

5. Das Javascript

Auch diese Datei ist Bestandteil, der umgebauten SimpleviewerSource-Erweiterung und zwar hier:  js/HTML5JqueryMediaelement.1.1.js. Die Datei enthält bereits Teile, für die Version 2, die hier noch garnicht zum Einsatz kommen, wie z.B. die Verwendung von Canvas zum zeichnen von Standbildern aus dem Video. Diese hab ich hier weggelassen.

$(function() {

 // einzige konfigurierbare Variable. Wo liegen die Filmdateien?

var $videoPath = 'http://addit-media.net/new/uploads/stevemovies/';

 // Variablen, die sich auf die verwendete Index Datei beziehen
// the loading image

var $loader    = $('#st_loading');

// the ul element

var $list        = $('#st_nav');

// the current image being shown

var $currImage = $('#st_main').children('img:first');
var windowWidth = $(window).width(),
windowHeight = $(window).height();

// Aktuellen Bild….
// und die Navigation mit den Thumbs laden

$('<img>').load(function(){
$loader.hide();
$currImage.fadeIn(3000);

setTimeout(function(){
$list.animate({'left':'0px'},500);
},
1000);
}).attr('src',$currImage.attr('src'));

// Breite des div elements, für die Thumbnailnavi berechnen
// um festzustellen, wo die einzelnen thumbs agezeigt werden müssen

buildThumbs();
function buildThumbs() {
$list.children('li.album').each(function(){
var $elem = $(this);
var $thumbs_wrapper = $elem.find('.st_thumbs_wrapper');
var $thumbs = $thumbs_wrapper.children(':first');

//180px pro thumb + 3 für margin

var finalW = $thumbs.find('img').length * 183;
$thumbs.css('width',finalW + 'px');

//element scrollbar machen, funktion siehe ganz am ende des skripts

makeScrollable($thumbs_wrapper,$thumbs)

;});

}

// ein Video laden

function loadVideo(title, from, to){

// Hier sieht man, wie 'from' und 'to' als "#" Anker übergeben werden!!
// Ich habe die Viedeos in den einzelnen Ordner _1, _2, _3 genannt, theoretisch, kann mann auch alle 3 einfach "video" nennen,
// da sie sich aufgrund der unterschiedlichen Endung ohnehin unterscheiden.

$('#video').append(createSource($videoPath + title + '/_1.mp4#t='+from+','+to, 'video/mp4'));    
$('#video').append(createSource($videoPath + title + '/_2.ogg#t='+from+','+to, 'video/ogg'));
$('#video').append(createSource($videoPath + title + '/_3.webm#t='+from+','+to, 'video/webm'));  
};

// source elemente in das Video laden

function createSource(src, type){
var source = document.createElement('source');
source.src = src;
source.type = type;
return source;
};

// einen Button herstellen

function createButton(parent, value) {
var myButton = document.createElement('input');
myButton.type  = 'button';
myButton.value = value;
parent.prepend(myButton);
return myButton;
};

// eine Debugg funktion mit der man ein Objekt, komplett durchlaufen und auslesen kann

function showObjProps(obj) {
var output = '';
for (property in obj) {
output += property + ': ' + obj[property]+'; ';
 }
alert(output);
};

// die Rollover Eigenschaften der Links definieren

$list.find('.st_link').bind('mouseenter',function(){
 $(this).stop().animate({'opacity':'1'});
 }).bind('mouseleave',function(){
 $(this).stop().animate({'opacity':'0.5'});
});

// ein menüitem anklicken (up and down arrow)
// zeigt die thumbs an ….

$list.find('.st_arrow_down').live('click',function(){
var $this = $(this);
hideThumbs();
$this.addClass('st_arrow_up').removeClass('st_arrow_down');
var $elem = $this.closest('li');
$elem.addClass('current').animate({'height':'200px'},200);
var $thumbs_wrapper = $this.parent().next();
var pos = $this.position();
$thumbs_wrapper.show(200);
if($thumbs_wrapper.is('.desc_wrapper') ) {
$thumbs_wrapper.next().show(200);
$thumbs_wrapper.animate({'left': (pos.left + 120) + 'px'},200);
 }
 });

// …oder versteckt sie wieder

$list.find('.st_arrow_up').live('click',function(){
var $this = $(this);
$this.addClass('st_arrow_down').removeClass('st_arrow_up');
hideThumbs();
 });

// live() oder bind()?
// in diesem Fall wird der click event mit live an die thumbnails gebunden
// beide Funktionen sind ähnlich, aber bind(), bindet den Event, an dieses
// eine Objekt, während live(), den Event an dieses eine und alle noch
// folgenden gleichen Objekte, also auch wenn man ein thumbnail löschen würde
// und dafür eine anderes ersetzt, bleibt die Bindung erhalten, was hier ja auf jedenfall
// gewünscht ist.

$list.find('.st_thumbs img').live('click',function(){
var $this = $(this);

// loading anzeigen….

$loader.show();

// enthält das title attribut, die zeichenfolge irgendwas .jpg, und zwar am ende?

var search = $this.attr('title').search(/.+\.jpg/);

// wird kein treffer gefunden, gibt die funktion search() -1 zurück.

if( search != -1 ) {

// ist search() nicht -1, brauchen wir ein <img>, es könnte aber noch ein video geladen sein.

var $currImage = $('#st_main').children(':first');

//ist firstchild der Player?

if( $currImage.is('#cuePlayer') ) {

// video auswerfen!

$currImage.find('#video').stop();

// durch das img ersetzen!

$currImage.fadeOut(2000,function(){
$(this).replaceWith('<img class="st_preview"/>');
 });
 }

// image in das img laden

$('<img class="st_preview"/>').load(function(){
var $this = $(this);
$currImage = $('#st_main').children('img:first');
$this.insertBefore($currImage);
$loader.hide();
$currImage.fadeOut(2000,function(){
$(this).remove();
});
}).attr('src',$this.attr('alt'));
} else {

// gibt search() -1 zurück, ist kein Bild, demnach ein Video gefragt
// ist firstchild der Player?

if($('#st_main').children(':first').is('#cuePlayer') ) {
$video = $('#video');

// die alten sources rauswerfen….

$video.stop();
$video.empty();

// und die neuen Videos reinladen, im Gegesatz zum Photo, wird für das Video das 'title'-Attribut des Thumbnails zum bilden der Aufrauf-URL verwendet, denn das 'alt'-Attribut, wird ja für die thumbnail.src gebraucht.

loadVideo($this.attr('title'));

// das video laden

$video.load();

// ist firstchild nicht der Player?

} else { $currImage = $('#st_main').children('img:first');

// neues videoelement erstellen

var $video = document.createElement('video');

// img durch html5 video element ersetzen

$currImage.fadeOut(2000,function() {
$(this).replaceWith($video);

// die angefragten sources reinladen

loadVideo($this.attr('title'));

// den loader verstecker

$loader.hide();

//und die cuePlayer section darumwickeln

}).wrap("<section id='cuePlayer'></section>");

// Video Eigenschaften definieren.

var vState = 'Pause'
$video.id = 'video';
$video.controls=true;
$video.autoplay = true;
$video.preload='none';

// Und die Handler zu den Events, die abgehört werden sollen, laden….
//  Ich hab hier nur 3 die wichtigsten, also die minimal-config ausgeführt
//  Alle Events und API der HTML5 Viedeo Componente, sind hier zu finden,
//  http://www.w3.org/2010/05/video/mediaevents.html
//  Anhand des dort gezeigten Beispiels, lässt sich genau nachverfolgen, welcher Event, wann gefeuert wird.
// Eventlistener und Handler 'loadedmetadata'-Event ( für IE6, IE7 und IE8 müsste der Aufruf so aussehen: $video.attachEvent(…..),
// ebenso der nächste, wir haben damit also schonmal 3 Verschiedene Eventhandlings für 5 Browser, ohne Mobilgeräte).
// Erschliesst sich mir nicht so ganz, denn das Video feuert ja den Event selbst, warum muss dann ein Eventlistener,
// den eigenen Event abhören??? funktioniert aber in Chrome & Safari nicht anders. Nicht notwendig in Firefox & Opera,
// da wäre $video.onloadedmetadata direkt als Eigenschaft vorhanden, was mir auch logischer erscheint und da funktioniert auch
// der Listener nur, wenn die Callback Funktion des Handlers, anonym und direkt im Eventlistener gestartet wird, für Chrome & Safari
// könnte man auch eine seperate Funktion mit Namen aufrufen. Dieser Event ist minimales MUST HAVE, denn es ist der Event,
// zu dem die Videodaten, wie Länge, Breite, Duration ect. im Skript bekannt werden und damit, DER PLATZ schlechthin, um CSS u. Parameter
// für Elemente zu setzen, die von der Beschaffenheit des Videos abhängen, wie Fortschritsbalken oder Laufzeitanzeige ect.

$video.addEventListener('loadedmetadata',  
function(e) {
if(!$video.autoplay) vState = 'Play';
var playpause = createButton($('#video').parent(), vState);
playpause.id = 'playpause';
 $('#playpause').bind('click',function(){    
playpause.value = $video.paused ? 'Pause' : 'Play';
if ($video.paused) {
$video.play();
} else {
$video.pause();
}
}).css({'height': '20px',
 'width' : '100px',
 'top'   :  this.offsetTop,
'left'  :  '15px',
 'border-radius':'5px'
 });
$('#cuePlayer').css({
'height': (this.videoHeight + 40)+'px',
'width': this.videoWidth + 'px'});
}, false);

// Eventlistener und Handler   'canplaythrough'-Event
// Nicht ganz so essentiell, wie der Vorher aber auch wichtig. Der Event, wird gefeuert, wenn das Video soweit vorgeladen wurde,
// Das es komplett gespielkt werden kann, ohne unterbrechen zu müssen um nachzuladen, und ist somit eigentlich der richtige Moment,
// um das Video zu starten,
// Oder einen Play-Button für den Benutzer freizugeben.

$video.addEventListener('canplaythrough',  
function(e) {
$video.play();
$loader.hide();
}, false);

// Die Mousehandler an den Player Binden

$('#cuePlayer').bind('mouseenter',
function(){
$('#playpause').show(200);
 }).bind('mouseleave',function(){
$('#playpause').hide(200);
 });

// Und Die Mousehandler für komplette Action

}).bind('mouseenter',function(){
$(this).stop().animate({'opacity':'1'});
}).bind('mouseleave',function(){
$(this).stop().animate({'opacity':'0.5'});
 });

// Funktion um das Momentan geöffnete Menü zu schliessen

function hideThumbs(){
$list.find('li.current')
.animate({'height':'50px'},400,function(){
$(this).removeClass('current');
})
.find('.st_thumbs_wrapper')
 .hide(200)
.andSelf()
.find('.st_link span')
.addClass('st_arrow_down')
.removeClass('st_arrow_up')
.andSelf()
.find('.desc_wrapper')
.hide(200);
 }

// die Thumbnailnavigations divs skrollbar machen
// mit on-mouse-move-Handler, um die Thumbs bei Rollover automatisch zu scrollen.

function makeScrollable($outer, $inner){
var extra             = 800;
var divWidth = $outer.width();
$outer.css({
overflow: 'hidden'
});
var lastElem = $inner.find('img:last');
$outer.scrollLeft(0);
$outer.unbind('mousemove').bind('mousemove',function(e){
extra             = 800;
divWidth = $outer.width();
var containerWidth = lastElem[0].offsetLeft + lastElem.outerWidth() + 2*extra;
var left = (e.pageX – $outer.offset().left) * (containerWidth-divWidth) / divWidth – extra;
$outer.scrollLeft(left);
});
}
});

OK, das war jetzt eine Menge Code, ist aber leider nicht Anders zu machen. Wer kein Assetmanagement verwenden möchte oder wem das zuviel Coding ist, der kann sich auch

eine Standalone Version des Jquery hier herunterladen.

 

Die neue Website für Steve Rowland Photography wurde als Javascript, Jquery realisiert. Als Assetmanagement, zur Administration der Website, dient Gallery2. Das Admin Interface ist von der Frontseite aus nicht erreichbar und kann nur durch direkte Eingabe der URL aufgerufen werden.

Suchmaschinen optimierte Ausgabe.

Bei diesem Jquery, sind alle, für Suchmaschinen relevanten Daten der Bilder, bereits Bestandteil des HTML Codes, der aufgerufenen Seite und können von Robots problemlos ausgelesen werden.

Durch Auswahl eines Photos aus der Navigationsleiste, werden die großen Bilder vom Server nachgeladen und direkt in das Seitenlayout eingebaut, ohne daß ein komplettes Update der Seite stattfinden muss. Ein "loading" Button rechts oben zeigt dabei die Ladetätigkeit an.

Die Seite verhält sich "fluid", das heißt, die Größe des Hauptphotos und die der Thumbnailnavigation passen sich der Grösse des öffnenden Fensters an, auch wenn diese erst nach dem Laden verändert wird, wodurch sich die Seite auch zur Darstellung und Navigation auf Tablet PCs gut eignet.

 

Eine Alternative zu Flash sind Jquery Komponenten für Websites eigentlich nicht, aber mehr und mehr müssen sich Entwickler mit der bitteren Wahrheit vertraut machen, das die Anzahl der User, die mit Tablets oder Smartphones unterwegs sind, zunehmen wird und den wachsenden Anteil an Jquerys gegenüber Actionscript RIAs, auf Websites rechtfertigt. Aber Jquerys haben natürlich auch Vorteile. Beispielsweise sind Jqueries als Javascript Code, direkt in HTML Seiten darstellbar und brauchen daher kein Interface zur Komunikation mit dem HTML Container.

Vor der Verwendung von Jquery Komponenten in einem CMS, sollte man generell folgendes bedenken:

  • Bei der Verwendung mehrer Jquery Komponenten, muss man darauf achten, das sich die verwendeten Variablen in den Scripten, sich nicht "behacken".
  • Man sollte ausserdem darauf achten, das von allen die selbe Version des Frameworks geladen wird. Schreibt man seine Plugins selbst, ist zu empfehlen, das Jquery Framework, nicht lokal sondern Remote, z.B. von hier: https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js zu laden/wer dem fremden Server nicht traut, kann auch eine Fallback Funktion integrieren, die bei nicht ereichen des fremden Servers auf ein lokales Skript zurückgreift). Der Vorteil der Remote ladens, liegt darin, dass man immer die neueste Version läd, ohne das man selbst ständig Updates durchführen muss. Momentan, Stand: Erscheinungstermin des Posts ist das jquery 1.7.1.
  • Auch mit Richtext Editoren, wie z.B. CKEditor, kann es Konflikte geben.

Das Feature-Carrousel, einer der "stylishten" Jquery Slider, ist auch auf iPhone und iPad lauffähig,

trotzdem fehlt ihm, im Gegensatzt zu den Flash Slidern, die gerade auf mobilen Devices so beliebte RollOver Navigation. Diese ist auch in Jquery nicht in der Perfektion zu erreichen, wie das bei einer Flash Komponente möglich ist. Eine Auswahl verschiedenster Slider sowohl in Flash als auch Jquery, haben wir in einer Typo3 Extension zusammengefasst. Diese kann man hier testen.

Slidernavigationen, werden gerne mit Bildergallerien und deren Navagitionen verwechselt, ist Diesen aber garnicht so ähnlich, wie es auf den ersten Blick scheint. Eine Navigation, ist ein ein Menü, also eine Liste im Gegensatz zu einer Gallerie, bei der die Bilder in der Regel, mit den Bilddateien verlinkt werden, führt bei einer Navigation, der Link zu einer anderen Seite, was zu eine deutlich größeren Aufwand bei der Javascript Programmierung und dem Eventhandling führt. Daher ist es auch nicht so einfach, eine Bildergallerie in ein Navigation umzustricken, auch wenn es optisch kaum Unterschiede gibt. Klickt man sich durch eine Gallerie, wird in der Regel die Seite nicht verlassen, anders bei einer Navigation, hier wird die Seite verlassen, wodurch schon mal die Zielseite, ebenfalls die Navagation enthalten muss. Für das Zusammenspiel der Navigationen auf unterschiedlichen Seiten, ist es zudem nötigt, nicht nur dorhin zu verlinken, umgekehrt muss auch die Seite der Komponente zurückgegeben, wo sie sich befindet, andernfalls könnte die Komponente keine "current" Status anzeigen und damit dem Benutzer mitteilen, wo er sich eigentlich gerade befindet. Das Handling für eine Bildergalerie ist dagegen relativ übersichtlich, denn das Bild selbst ist ja Menüitem, Linkziel und Status in Einem und ermöglicht es, alle Relationen allein über den Index des Slideritems herzustellen, was bei Navigationen so nicht funktioniert. Auch wenn bei einem Jquery kein Interface nötig ist, brauch es denoch das gleiche Datenmodel, wie der Flashslider als Grundlage. Ironischerweise ist ja der Skriptaufruf zur Darstellung einer Flash SWF-Objekts, ebenfalls ein Jqueryscript. An dem Post dazu, lässt sich daher auch der prinzipielle Aufbau der Integration einer Jquery Komponente ersehen Post zum SWF Objekt Aufruf. Sie besteht immer aus einem bis mehren Javascripten die im Header zu referenzieren sind, einer CSS Datei im Header, einem Javascript, das direkt auf der Seite ausgeführt wird und schliesslich der HTML-Code der Komponente.

Schortcode Tag zur anzeige im Post  ist carrousel

Die Schlüssel-PHP funktion des Plugins, welche den HTML Code des Sliders erstellt, sieht dann in etwa so:

function getSliderCode() {

Zunächst die möglichen Shortcode Attribute, für das carrousel Tag, mit default Werten. Ein Admin Interface für die Komponente hab ich mir geschenkt, um überschüssigen Schnick-Schnak zu sparen. Alles was es dort zu administrieren gäbe, kann man genauso gut direkt innerhalb des Posts, in Form von Shortcode Attributen übergeben. Das Array wird mit den default Werten vorgefüllt und werden verwendet, wenn man das entsprechende Attribut nicht angibt.

                   shortcode_atts(array(
                          'containerwidth' => 900,
                         'containerheight' => 450,
                                 'largewidth' => 600,
                                'largeheigth' => 350,
                                 'smalwidth' => 233,
                                'smalheight' =>133,
                                      'cspeed' => 1200,
                                       'atplay' => 3000,
                                       'cstyle' => 'default',
                                 ), $atts);

 

 

…..

 

Das Array wird  in ein Javascript geparst, das seinerseits an die Return-Variable der Funktion geparst wird.( Das Script, das hier geparst und später im body ausgegeben wird, wird uns weiter unten nocheinmal beschäftigen.)

                   $text ='';
                   $text .= '<script type="text/javascript">'."\n";
                   $text .= ' $(document).ready(function() {'."\n";
                   $text .= '    $("#carousel").featureCarousel( {'."\n";
                   $text .=    '     // include options like this:'."\n";
                   $text .= '     // (use quotes only for string values, and no trailing comma after last option)'."\n";
                   $text .=    '            containerWidth: '.$a['containerwidth'].','."\n";
                   $text .= '           containerHeight: '.$a['containerheight'].','."\n";
                   $text .= '         largeFeatureWidth: '.$a['largewidth'].','."\n";
                   $text .= '         largeFeatureHeight: '.$a['largeheigth'].','."\n";
                   $text .= '         smallFeatureWidth: '.$a['smalwidth'].','."\n";
                   $text .= '         smallFeatureHeight: '.$a['smalheight'].','."\n";
                   $text .= '             carouselSpeed: '.$a['cspeed'].','."\n";
                   $text .= '                  autoPlay: '.$a['atplay'].','."\n";
                   $text .= '                    cStyle: "'.$a['cstyle'].'"'."\n";
                   $text .= '     });'."\n";
                   $text .= ' });'."\n";
                   $text .= '</script>'."\n";

 

……….

 

Dann wird das Array $args, welches die Argumente beinhaltet, die der get_posts() funktion übergeben werden, wird ebenfalls ohne Admininterface mit dem Default Zustand vorgeladen. Z.B. So:

……….

 $args = array('numberposts'     => 5,
                'offset'          => 0,
                'category'        =>  null,
               'orderby'         => 'post_date',
               'order'           => 'DESC',
               'include'         =>  null,
                'exclude'         =>  null,
               'meta_key'        =>  null,
               'meta_value'      =>  null,
               'post_type'       => 'post',
               'post_mime_type'  =>  null,
               'post_parent'     =>  null,
               'post_status'     => 'publish' );

 

……….

Es folgt die Ausgabe, in der etwas unreifen WP-API Manier, über eine PHP foreach() Schleife, wobei der HTML Code dabei, weiter auf die $text  Variable geschrieben wird. Etwa in der Art ……:

…..

$c = 1;
foreach($posts_array as $post) {
setup_postdata($post);
$image_attributes = array(0 => plugins_url(basename(dirname(__FILE__))).'/images/image'.$c.'.jpg');
$text .= '<div>';
$attachments = get_children(array('post_parent' => $post->ID, 'post_status' => 'inherit', 'post_type' => 'attachment',
'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order'));
if (is_array($attachments)) {
foreach ($attachments as $id => $attachment) {
$image_attributes = wp_get_attachment_image_src( $id, $size );
if ($image_attributes) {
$original = wp_get_attachment_image_src($id, 'full');
}
break;

                                                                        }
$text .= ' <a href="'.get_permalink( $post->ID).'"><img alt="Image Caption '.$original.'" src="'.$image_attributes[0].'"></a>';
}

$c++;

……….

…. und die Rückgabe der $text, die jetzt den fertigen HTML-Code des Sliders enthält.

 return $text;
}

Download WP-Slider PluginZugegeben, für die $args sollte man ein Admininterface, oder zumindest eine Verlängerung der Shortcode Attribute in Betracht ziehen, wenn man das als offizielles WP-Plugin herausgeben möchte, was ich aber eigentlich garnicht vorhabe. Da die Anzahl der Kunden, für die wir so ein Spielzeug CMS am laufen haben ohnehin gegen Null konvergiert, habe ich mich hier mit der "quick&dirty" Plugin Version beschieden, was für mich aber vollkommen ausreicht um diesen einen Slider zu Posten, der ja nur der Veranschaulichung der Vorgehensweise generell dient und ein echt Navigationsaufgaben übernimmt.

Er ist Teil einer echten Jquery-Sliderextension für Typo3, die nicht nur 4-Verschieden Jquery Slider Layouttypen, den vorher geposteten Flash-Carouselslider beinhaltet, sondern auch komplettes, sozusagen "fully-featured" Admininterface, für jede in Typo3 mögliche Contentart beinhaltet, so das keine Wünsche offen bleiben, ist dafür aber leider weder umsonstdevil., noch für WordPress, sondern ausschlisslich als Teil der Typo3 Suite, die wir unseren Kunden instalieren, als kostenpflichtig, lizensierte Extension erhältlich. Ja irgend einen Haken gibt's immer, aber anschaun kostet nix.

Dafür kann sich aber Jeder, der den Slider gerne für WordPress hätte diese reduzierte Version, des Plugins, in diesem Stadium, für lau, hier rechts herunterladen und dieses selbst weiterentwickeln. Der Jquery Code ist sehr gut und die Plugin Architektur eine exzelente Ausgangsbasis, für jemanden, der sich auf WP-Entwicklung versteht. Wer die Extension zu einem hochwertigen WP-Plugin, vollenden möchte, sollte natürlich ein admin Interface dafür schreiben und die carrousel.php in eine Class packen. Hier ist ein interessanter Beitrag zu diesem Thema http://scribu.net/wordpress/optimal-script-loading.html. in dem die Möglichkeiten zur perfekten Integration eines Jquery in WordPress erörtert werden. 

Aber auch in diesem Stadium ist es durchaus vollwertig und kann auch direkt so eingesetzt werden. Das Plugin enthät Jquery1.7.1, das Sliderscript selbst, läuft aber bereits ab Jquery > 1.5. Kann also auch unter einer älteren Version des Frameworks installiert werden. Mit dem in WP beliebten "horizontal Slider", verträgt es sich offensichtlich, denn der läuft z.B. hier problemlos, wie man sieht, auch mit dem installierten Plugin.

Allerdings, gab es einige Konflikte mit CKEditor, denen ich nicht weiter auf den Grund gegangen bin, da ich den RTE ohnehin nicht unbedingt verwende. Wer Beides haben möchte, muss der Sache etwas genauer nachgehen, dazu ein paar Anmerkungen.

Meistens resultieren Konflikte mit verschiedenen Jquery Komponennten aus der doppelten Verwendung von Namen, für Variablen oder Namespaces in unterschiedlichen Scripten und lassen sich durch umbenennen einer der Variablen relativ einfach beheben oder aber es ist ein Problem der Ladereihenfolge der Skripte. Der hier oben empfohlene Blogbeitrag, bietet einige interessante Ansätze, für die in WP nicht ganz unproblematisch zu handhabende Ladereihenfolge der Scripte, aber auch nicht wircklich die Lösung, für diesen Fall. Bei diesem Slider ist es tatsächlich nötig, das die Reihenfolge der zu ladenden Javaskripüte exakt eingehalten wird und zwar in der Art, dass das externe Skript geladen sein muss, bevor das im body aufgerufene Skript ausgeführt wird, die im Blogbeitrag verwendete Methode, würde die Konfliktsituation, welche sich durch ein evetuel zweimal geladenes Jquery ergeben können dadurch lösen, das externe Skript zwar zur initialisierung des Dokuments in WP zu registrieren, was nach WP API zwingend ist, aber erst direkt vor der Einbindung des Footers an die renderqueu der Seite übergebn, was in diesem Fall dann leider zu spät wäre.

Anders als eine echte MVC Programmarchitektur wie sie für Typo3 und auch Magento existiert, kann die Programmachitektur von WordPress, meiner Ansicht nach keine absolute Ladereihenfolge für die Skripte gewährleisten, den auch die oben beschriebene Methode, ist ja genaugenommen auch kein Feature, wie der Blogbeitrag zu vermitteln versucht, sondern bestenfalls  eine Krücke, für genau dieses Problem. Das Hook und Filter System zum Einbinden von Plugins, ermöglich zwar das Laden relativ zu anderen Skripten, nicht aber das Laden an einer absolut festgelegten Position und damit ist die Ladeposition beinahe zwangsläufig immer von Anzahl und Ladeeinstellung anderer Plugins abhängig und muss daher, individuell an die Parameter der jeweiligen Instalation angepasst werden. Eine Einbindung die generell passt, egal was sonst installiert wird, ist mit WordPress aus meiner Erfahrung herraus nicht realisierbar. Würde mich aber wie gesagt von einem echten WP API Nerd eines besseren belehren lassen, wenn ich da falsch liege.

Man kann aber natürlich immer eine Möglichkeit finden, die mit möglichst vielen anderen Komponenten zusammen geht. Ausserdem, verwendet WP zum einen generell die No-Konflikt Version von Jquery und zum anderen verursacht der Ausgabe-Loop, sowieso ein mehrfaches Updates des Seitenlayouts während des Renderns durch alle Javaskripte die über ein Plugin eingebunden sind, so daß man auch  mit dem Performance Nachteil, der aus enem eventuell zweimal eingebundenem Jquery resultiert, in diesem Fall eigentlich auch gut leben kann.

Sebstredend, schliesst, die angesprochene Problematik auch Ajax oder Funktionen die AJAX verwenden, mit ein.

 

 

 

Basiswissen.

 
Um im Internet das tun zu können, was im allgemeinen Allen nachgesagt wird, dass sie dort machen, nämlich surfen, braucht man Verweise(Links), die einem ermöglichen von einer Seite zur nächsten zu springen. Zwecks der Ordnung, werden diese in nach bestimmten Eigenschaften zusammengefasst, diese Gruppen, wie auch immer sie aussehen mögen sind im Grunde Nichts anderes als Listen, was man ja auch noch ziemlich gut nachvollziehen kann, sieht man sich rechts den Sidebar an, so kann man z.B. die unter der Kategorie "Letzte Artikel" angezeigte, Gruppe von Verweisen, durchaus als Liste verstehen. Etwas komplizierter vorzustellen aber ebenfalls eine Liste, das Hauptmenü, sowie generell alle Menüs.
Vorteile von Menüs:
  • Menüs kann man schon rein optisch etwas schicker aussehen lassen, als reine Textlisten,
  • ausserdem hat ein Menü die Möglichkeit, durch entsprechende Bebilderung der Menüpunkte, dem User schon im Vorfeld einen optischen Hinweis, in Form eines Bildes zu geben, wo Ihn dieser Verweis hinführen wird, was schneller erfassbar ist, als reiner Text und ihm dadurch die Navigation erleichtert.
Menues sind auch ganz sinnvoll und brauchbar, wie z.B. das Hauptmenü, denn es bildet eine feste Klammer, die auch immer an dieser Stelle der Seite bleibt und hilft dem Benutzer enorm, die Seite zu struckturieren um zumindest "Orientierungseckdaten" feststellen zu können. Aber genau die Static, die für die Strucktur von Vorteil ist, wird eine Ebene darunter, bereits zu einem Nachteil, dieser Form der Listendarstellung, nehmen wir einfach mal fiktiv unter jedem Listenpunkt 20 Unterpunkte an, mit Vorschaubild. Da die Liste sich nicht Bewegt, muss sich der Benutzer über die ganze Liste bewegen um Alles zu erfassen und genau hier kommt eine weitere Form der Listendarstellung besser.Eine die sich bewegt und dadurch dem Benutzer auf dem Weg über die Listeneinträge entgegen kommen kann. Der Benutzer muss also nicht den ganzen Weg gehen, sondern nur einen kleinen Teil, den Rest, lässt er die Liste erledigen, indem er die Listenpunkte an sich vorbei "rutschen" lässt, was der Listenform ihren Namen gibt.

 

 

"The Slider"

Die Slidernavigation in Ihrer effektivsten, schnellsten und performantesten Ausführung, als Carrousel, verdanken wir, im übrigen … Wer weiß es? … richtig! Steve Jobs.

Eine von vielen Computerfragen, deren Antwort immer "Steve Jobs" lautet, zum aufsagen mit der Entwicklergruppe, als Mantra, so wie:. Master: Wer hat die Maus erfunden?..dieGuppe im Chor:.S…J….., aber es ist eigentlich unstrittig, dass die Slidernavigation des iPhones auch den Websitenavigationen neues Leben eingehaucht hat. Nachdem man sich jahrelang, mit der ästhetischen Spannbreite eines Mensaspeiseplans, bei der Gestalltung von Onlinemenüs zufrieden gegeben hat, sind jetzt auch direkt "anfassbare" Menüs, intuitives Handling und Event Designs auch für Webauftritte angesagt, weil das bevorzugte Endgerät zum surfen, in naher Zukunft sicher vom Desktop-PC, zum Tablet PC wechseln wird, macht das auch Sinn.

Carrousels

sind Slider, die endlos rundum laufen, nach dem letzten Eintrag, kommt also direkt wieder der Erste. Dabei ist eine kreisförmige Form nicht ausschlaggebend, auch eine Slideshow, die einfach immer das nächste Bild an Ort und Stelle einblendet, ist ein Carousell, wenn nach dem Letzten direkt wieder das Erste kommt. Die Blogversion hier ist eine auf 80% verkleinerte Ausgabe des Originals, wodurch die Steuerleiste eigentlich zu klein ist. Original, würde der Slider, als Hauptnavigation, über die komplette Seite laufen, inklusive Sitebar, da er hier aber als Post eingebunden wurde, wurde er von 1280 auf 900 pixel verkleinert.

Einbindung Flash-Objekt Remote: also von einer anderen Domain und dabei verkleinert, heisst:komplette URL und scale=showall. Man beachte die Größe des Films, wird dann nicht absolut sondern als 100% angegeben. Somit entscheidet die Größe des, dem SWF übergeordneten Block-Elements, allein über die Größe der Stage des SWF-Objekts und ist, für den Blogpost mit 900px definiert. Z.B. So.:

<object width="100%" height="100%" align="absMiddle" id="myFlashContent" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000">
<param value="http://addit-media.net/new/uploads/slider/menu.swf" name="movie"/>
<param value="best" name="quality"/>
<param value="showall" name="scale"/>
<param value="transparent" name="wmode"/>
<param value="http://addit-media.net/new/uploads/slider/menu.swf" name="src"/>
<embed width="100%" height="100%" wmode="transparent" type="application/x-shockwave-flash" src="http://addit-media.net/new/uploads/slider/menu.swf" scale="showall" quality="best" id="myFlashContent"/>
</object>

Hier kann man die swf Datei in 100% sehen.

1. Auch das ist nur eine Liste,

Zugegeben, das ist hier nicht mehr auf den ersten Blick offensichtlich, das ganze optische Spektakel vernebelt den Blick auf das Datenmodel. Aber soll es sich um ein Menü handeln, müssen der SWF Datei, irgendwie die Daten aus dem CMS übergeben werden, in den meisten Flash SWF Dateien geschieht das mit einer XML-Datei die im Stammverzeichnis liegt. Vorsicht diese Dateien sind nur bedingt geeignet für Skripaufrufen innerhalb eines CMS oder wie hier einem Blog, denn die XML-Datei müsste beim Aufruf der Seite, die das SWF enthält, im selben Verzeichnis liegen, wie die aufrufende HTML-Datei, um wieder im korrekten Verzeichnis zur SWF Datei zu liegen, wenn diese ausgeführt wird. Verwendet das CMS einen URL-Rewrite, wird es mitunter etwas komplexer, dem SWF, die XML Datei aus dem richtigen Verzeichnis, zur Verfügung stellen zu können. Deshalb werden solche Dateien, in Actionscript, um die External Interface Klasse(wie das geht? Hier ist ein ausgezeichnetes Beispiel zum nachbauen) erweitert, die dann keine XML Datei sondern die XML Daten direkt selbst vom Server abruft. Dadurch wird die XML-Datei im Stammverzeichnis nicht mehr gbraucht, kann also auch nicht im falschen Verzeichnis liegen. Wer einen Browser verwendet, der XML anzeigt, kann die Daten, welche die SWF-Datei hier abruft auch im Browser anzeigen lassen. Link zur XML Datei. Und sieht, oh Wunder, eine XML-Liste, das Datenmodell hinter dem Slider.

2. Das Interface

Neben dem ganzen Chi-Chis, die das Design des Sliders betreffen, ist vorallem der Teil, mit den <pitem> und <subitem> Tags, für die Hirarchie des Sliders verantwortlich. Dieser Slider hier ist demnach ein Menü über 2 Hrarchie Ebenen, <p(age)items> sind die Tags für die 1. Hirarchie, diese werden verwendet, um die Items in der Steuerleiste, unter dem eigentlichen Slider zu füllen. Hier oben, durch die Verkleinerung etwas zu klein, für meinen Geschmak. Ich empfehle die 100% Version in einem extra Fenster zu öffnen, dann sieht man auch den kleinen grauen Pfeil, vor dem aktuell aufgerufenem <pItem>, des aktuell aufgerufenen <subitem>s, während das aktuelle <subitem>, mit einem roten "Glow" unterlegt ist. Das wird über eine Javaskript Callback Funktion möglich, die Teil des External Interfaces ist und die beim Aufruf der Seite, der SWF Datei mitteilt, von welcher Seite sie aufgerufen wird. Bei diesem Beispiel, das an ein Typo3 CMS angebunden wurde, wird dabei der Seiten-Index und Content-Typ an den Server übertragen, sowie der Typo3 Sitetype 999, der in dieser Typo3-Extension, als XML-Sitetyp definiert ist. Hier muss von CMS zu CMS unterschiedlich, der jeweils notwendig Aufruf der Seite, als XML-Datei stehen. Übertragungsmethode ist Get, daraus ergibt sich folgende URL für den Aufruf:

http://develop.addit-media.net/new/index.php?type=999&id=188&cStyle=pages

Der selbe Aufruf, ohne den Typo3 XML-Sitetyp und cStyle Parameter, develop.addit-media.net/new/index.php?id=188, öffnet die Seite deren Navigation im Slider angezeigt wird. (Der Slider auf der Zielseite, enthält zwar das selbe Datenmodel, ist aber eine Jquery Carrousel-Slider Variante, zu der wir später noch kommen). Eine SWF-Datei, die als Navigation in ein CMS eingebunden wird, braucht so ein Interface, andernfalls könnte in der Flashkomponente kein Feedback stattfinden, das dem User anzeigt wo er sich befindet. Wie so ein Interface in einem CMS arbeitet, sieht man hier.

 

 

Natürlich braucht der Videokatalog einen eigenen Player, da in sämtliche Standart Player ein paar wesentliche Funktionen nicht integriert sind, die hier benötigt werden. Zum einen muss der Player in der Lage sein, das aktuell angezeigte Produkt auszulessen. Schon alleine um vor und zurück springen zu können. Dieser Player hier kann aber noch mehr.

Wie Beispielweise Produktplaylisten als  fortlaufenden Videos abspielen und andere Features die zur Administration des Contents notwendig und sinnvoll sind.

Dieser Player ist eine  As 3.0 Komponente. Falls das WordPress eine Ladehemmung für die Flashdatei hat, was vorkommen kann, der Originalplayer läuft HIER. Dies hier ist eine Referenz auf die Datei, die wegen der Blogbreite nur in 900px Breite angezeigt wird. Die SWF Datei ist so programmiert, dass die Größe vom übergeorneten HTML-Container bestimmt wird, dadurch ist es möglich den Player auf unterschiedlichsten Ausgabe Medien und Veröffentlichungen laufen zu lassen.

Zur Projekt Organinisation:

Gegewärtig ist davon auszugehen, das pro Saison, also alle 6 Monate, ca 400 neue Produkte in den Katalog aufgenommen werden müssen. Diese werden auf "greenscreen", teilweise in 360 Grad-Views fotografiert. Eingepflegt werden die Produkte in die Datenbank nicht als Photo sondern als Aftereffects Sequenz von ca 6 – 20 sec. länge, wobei auch mehrere Sequenzen zu einem Produkt vorhanden sein können. Diese Sequenzen enthalten die Objektanimationen und die Schrift zum jeweiligen Produkt. Gesondert als seperate Spuren werden Hintergrunde und Tonspuren angelegt. Die AE Sequenzen können zum Einen in Final Cut oder Premiere direkt als Assets importiert werden und dort zu einem fertigen Fim geschnitten werden, oder aber seperat als .flv Dateien in den Player als Produktliste importiert werden und von diesem als Video abgespielt werden. In der Regel ist eine Mischung aus beidem am Besten, man Schneidet ein Vorgabe und setzt die einzelnen Sequenzen als cuePoint in der .flv Datei, so besteht die Möglichkeit, die Vorgabe direkt als Film zu spielen oder die Fragmente anhand der cuePoints neu "zusammenzusetzen". Dieses Verfahren erlaubt es uns nicht nur z.B. individuelle, Kunden oder Themenbezogene Videos auszugeben, sondern ermöglicht auch ein kontinuierliches Update der Produktpalette.

 

Aktuelle Control Belegung:

Wenn der Player Serienreife hat, gibt es Ihn selbstverständlich hier auch zum herunterladen. Allerdings ist dies hier tatsächlich ein laufendes Projekt d.h. steckt mitten in der Entwicklung. Terminiert ist das Projekt bis Ende Mai, dann wird es ein downloadfähige Version des Players, mit allen extras geben. Bis dahin, wird sich der Player in diesem Post sicherlich noch einige Male verändern, dennwie schon erwähnt ist dies hier eine Referenz auf die Entwicklungs Datei.

 

Sind generell nicht ganz einfach unter einen Hut zu bekommen, das gilt für Photoshop ebenso wie für After Effects,

denn Texte sind Vektoren und Lichteffekte sind meistens Rendereffekte, die grundsätzlich nur auf Bitmaps anwendbar sind.

 

Will man einen Lightsweep über eine Textebene laufen lassen, das tatsächlich der Eindruck eines "Leuchtens" entsteht, ist es ratsam, den Effekt mit einem Rendereffekt, wie Blendenflecken zu verstärken. Um diesen Effekt ohne Zwischenschritt, in nur einer AfterEffects Datei zu realisieren, braucht man zwei übereinanderliegende Ebenen, eine Textebene mit dem Lightsweep und eine Bitmap Ebenen, oder wie hier eine Farbebene, welche den Rendereffekt trägt.

1. In der Momentaufnahme wird sichtbar, das hier nicht 1 Lightsweep, sondern 2 direkt hintereinanderlaufende sweeps animiert wurden.

2.In der Zeitleiste unten sieht man die synchronlaufenden Effekte über den beiden Ebenen, oben der Lightsweep über der Textebene und unten den Rendereffekt auf der Farbfläche, der die Blendenflecken in das Bild bringt. Erst das Zusammenspiel beider Effekte bringt die Schrift tatsächlich zum leuchten.

3. Würde man die Farbfläche weglassen, wären keine Blendenflecken zu sehen, da der Rendereffekt nicht auf die Textebene anwendbar ist und der Lightsweep, würde relativ dünn ausfallen. und viel von seinem "leuchtcharakter" verlieren.

Natürlich könnte man auch die Textebene als Zwischenschritt Rendern und anschliessend den Rendereffekt über das gerenderte Video laufen lassen, dann wäre aber der Text im Nachhinein nicht mehr veränderbar.

 

Ich konnte es eigentlich kaum glauben und hab mir deshalb alle Flash-Plugins für WP gegeben.  Aber das ernüchternde Ergebnis ist, es gibt unter den unzähligen, teilweise wahnsinnig kompizierten Flash-Plugins für WP kein Einziges, das die volle Punktzahl erreichen würde. Das finden wir so traurig, das wir fast geneigt wären, einen Preis für die Volle-Punktzahl-Lösung auszuloben. Wenn man sich die Codes der Plugins ansieht, muss man sich echt fragen, was sich da manche für einen Wolf coden? Das kann doch eigentlich nur aus 2 Javaskript Einbindungen im Header und 3 HTML-Code Zeilen im Body bestehen,

 

Oder ist die Geschichte von WordPress Entwicklern und Flash tatsächlich eine Geschichte voller Missvertändnisse?

Hier nochmal ganz langsam zum mitschreiben.

1. <script type="text/javascript" src="swfobject.js"></script> wer die nicht Lokal hat kann sie auch direkt remote einbinden und zwar  von hier http://code.google.com/p/swfobject/ damit wäre auch sicher gestellt das immer die neuste Vewrsion verwendet wird.

Es folgt ein Javaskript mit ganzen 5 Eigenschaften(2 x String , 3 x Objekt) und 3 Funktionsaufrufen, wobei einer 2 mal (einmal für das body-tag und einmal für das html-tag aufgerufen wird), damit können ausnahmslos alle Parameter übergeben werde, die möglich sind.

2.<script type="text/javascript">
var swfVersionStr = "10.1.52";
var xiSwfUrlStr = "";
var flashvars = {};
var params = {};
params.quality = "high";
params.bgcolor = "#ffffff";
params.play = "true";
params.loop = "true";
params.wmode = "transparent";
params.scale = "showall";
params.menu = "true";
params.devicefont = "false";
params.salign = "";
params.allowscriptaccess = "sameDomain";
var attributes = {};
attributes.id = "menu";
attributes.name = "menu";
attributes.align = "middle";
swfobject.createCSS("html", "height:100%; background-color: #ffffff;");
swfobject.createCSS("body", "margin:0; padding:0; overflow:hidden; height:100%;");
swfobject.embedSWF(
"menu.swf", "flashContent",
"100%", "100%",
swfVersionStr, xiSwfUrlStr,
flashvars, params, attributes);
</script>

Zuletzt noch ein HTML 3-Zeiler, der Container Inklusive No-Flash und Flashdetektion.

3. <div id="flashContent">
<a href="http://www.adobe.com/go/getflash">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash Player" />
</a>
<p>Für diese Seite ist Flash Player Version 10.1.52 oder höher erforderlich.</p>
</div>

Fertig, und das ist schon das Plugin mit ALLES.  Mehr kann garnicht gehn sogar eine express-SWF-Instalatitionsdatei kann man damit erstellen Ich hab keine Ahnung wie da Plugins mit 4 Dateien zu je 500 Zeilen Code zusammen kommen können, die dann am Ende vorallem eines nicht leisten. Funktion! Wieviele Zeilen Code können das in WP-API wohl werden? 500? Oder doch nur 15? Wer wissen möchte was diese 3 Code-Blöcke genau Herstellen, kann das auf dieser Seite mit unserem SWF Generator  manuell durchspielen. Dieser kann auch verwendet werden um z.B. <noscript> Inhalte Für die Javascript aufrufe herzustellen.

Und so sieht dann, bei der Lösung mit der vollen Punktzahl, der HTML Code aus, den das Plugin aus den 3 Komponenten oben erzeugt. Wer es schafft, das WP die 3 Bausteine in diesem HTML ausgibt, hat tatsächlich geschafft was vor ihm noch keiner geschafft hat,

The-One-And-Only-One-Plugin-Fits-All-Flashfiles-WP-Extension

zu schreiben. Wer auf Nummer sicher, sicher gehen möchte, kann das in <noscript> </noscript> einrahmen, für die 2% die kein Javascript haben.

<!– Die SWFObject-Methode zum dynamischen Einbetten ersetzt diesen alternativen HTML-Inhalt durch Flash-Inhalt, wenn ausreichende JavaScript- und Flash-Plug-In-Unterstützung verfügbar ist. –>
<object width="100%" height="100%" align="middle" type="application/x-shockwave-flash" id="menu" name="menu" data="menu.swf"><param name="quality" value="high"/><param name="bgcolor" value="#ffffff"/>
<param name="play" value="true"/><param name="loop" value="true"/><param name="wmode" value="transparent"/><param name="scale" value="showall"/><param name="menu" value="true"/>
<param name="devicefont" value="false"/><param name="salign" value=""/><param name="allowscriptaccess" value="sameDomain"/></object>

Ich spendier sogar die Schlüssel PHP-Funktion des Plugins ( die aus dem Admin Interface zuzuführenden Variablen sind fett markiert):

function skriptCode()    {
$swfskript='<script type="text/javascript" src="http://projekt4.addit-media.net/adm/templates/video/swfobject.js"></script>
<script type="text/javascript">
var swfVersionStr = "10.1.52";
var xiSwfUrlStr = "";
var flashvars = {};
var params = { quality:"high", bgcolor:"#acacac", play:"false", loop:"false", wmode: "transparent", scale: "showall", menu: "true", devicefont: "false", allowscriptaccess:"sameDomain"};
var attributes = {id:"project4Player", name:"project4Player", align:"middle"};
swfobject.embedSWF( "'.$this->getPLayerURL().'", "flashContent", "590", "342", swfVersionStr, xiSwfUrlStr, flashvars, params, attributes );
</script>'."\n";
return $swfskript;
}

Naaa? …Jetzt aber. Wer wird One-Plugin-Fits-All-Flashfiles-WP-Extension Master?

 

 

Die kleine After-Effects-Orgie, stammt aus einer aktuellen Produktion.

Zur Präsentation der Collection, des Taschen und Accessoires Labels “Franco Roma”, wurden mit Hilfe von After Effects, die Produkte scheinbar verflüssigt. Bei diesem Film handelt es sich um einen Produktkatalog im Videoformat. Schrift und Produktanimation, bilden zusammen ein Modul, wobei die Produkte beliebig durch andere Produktmodule austauschbar sind und das Video auf diese Weise aktualisiert werden kann. Jedes neue Produkt, wird in Form eine Videosequenz archiviert und ist dann in das aktuelle Video integrierbar. Zukünftig wird es auch Möglich sein bestimmte Produktgruppen zu separaten Videos zusammen zu fassen. Zum Konzept des Katalogs, wird es zu gegebener Zeit, einen gesonderten Post geben.

Weiter Ressourcen für den Film