In der letzten Zeit ist es nicht einfacher geworden PDF-Dokumente in einer Webseite darzustellen. Zwar beherrscht Firefox das problemlos, aber z.B. nicht die Android-Version. Auch auf verschiedenen Apfel-Geräten funktioniert das nicht von Haus aus.

Zum Glück gibt es das Projekt https://github.com/mozilla/pdf.js mit dessen Javascript die Einbindung auf sehr vielen Geräten identisch funktioniert. Ich habe mir die Software von https://mozilla.github.io/pdf.js/getting_started/ geladen und die ZIP-Datei in ein Verzeichnis /pdfjs entpackt.

Leider ist die Nutzung des Scripts etwas aufwendig. Eine einfache Lösung besteht darin die mitgelieferte Viewer-Seite aus dem Unterverzeichnis /pdfjs/web zu nutzen und über einen Iframe einzubinden:

<iframe id="pdf-js-viewer" 
        src="/pdfjs/web/viewer.html?file=/fileadmin/user_upload/netthelp.pdf" 
        title="webviewer" 
        frameborder="0" 
        width="500" 
        height="600">
</iframe>

Leider ist diese Lösung so nicht responsiv. Mit Hilfe von https://www.w3schools.com/ habe ich mir folgende Lösung erarbeitet (hier für eine Typo3 Installation):

<div style="position: relative;
            width: 100%;
            overflow: hidden;
            padding-top: 141%;
           ">
  <iframe id="pdf-js-viewer"
          src="/pdfjs/web/viewer.html?file=/fileadmin/user_upload/netthelp.pdf#zoom=auto"
          title="webviewer"
          frameborder="0"
          style="position: absolute;
                 top: 0;
                 left: 0;
                 bottom: 0;
                 right: 0;
                 width: 100%;
                 height: 100%;
                 border: none;
          ">
  </iframe>
</div>

Der Trick besteht darin ein DIV Element zu nutzen, das die ganze verfügbare Breite einnimmt und über padding-top eine darauf basierende Höhe bekommt. Bei den DIN Ax Dokumenten ist das Höhen-Breiten-Verhältnis 1,41:1 bei Portrait und 1:1,41=0,71:1 bei Landscape.

In dieses Element hinein wird dann der IFrame geladen und bekommt den vollständigen Platz zur Verfügung gestellt.

Mittels #zoom=auto wird erreicht, dass sich auch der PDF-Viewer an den zur Verfügung stehenden Platz anpasst. Hinter zoom=… könnten folgende Angaben stehen:

  •  200 (oder eine beliebige Prozentzahl)
  • page-width
  • page-height
  • page-fit
  • auto

Außer zoom gibt es noch den Parameter page=, damit kann angegeben werden, mit welcher Seite des PDFs die Darstellung startet. Weitere Möglichkeiten finden sich auf der Seite https://github.com/mozilla/pdf.js/wiki/Viewer-options.

Weitere Informationen:

Hier nun eine verbesserte Version des Bootstrap Carousels. Diese Version zeigt alle Bilder an, die in den Seiten-Eigenschaften definiert sind. Zusätzlich werden die Metainformation des jeweiligen Bildes dargestellt. Ich habe mich dabei an der Vorlage unter Blog Teamgeist-Medien orientiert.

 lib.field_headerimage = COA

 lib.field_headerimage {
  wrap (
     <div id="skiplink">
       <a class="skip" title="Direkt zur Navigation springen" href="#navigation">Zur Navigation springen</a><br>
       <a class="skip" title="Direkt zum Content springen" href="#content">Zum Content springen</a>
     </div>
     <div id="blogo">
        <a href="/"><img src="fileadmin/user_upload/Logo_trans.png" /></a>
     </div>
     <div id="hslider" class="carousel slide carousel-fade" data-ride="carousel"  data-interval="5000">|</div>
  )
  #Hier hole ich die Bilder aus den Seiteneigenschaften(Ressourcen/Media) um die Navigation zu erstellen.
  10 = FILES
  10 {
    stdWrap.wrap = <ol class="carousel-indicators">|</ol>
    references {
      data = levelmedia:-1, slide
      treatIdAsReference = 1
    }
    renderObj = TEXT
    renderObj {
      wrap = <li data-target="#hslider" data-slide-to="|" class="active"></li>|*|<li data-target="#hslider" data-slide-to="|"></li>
      value = {register:FILE_NUM_CURRENT}
      insertData = 1
    } #Ende renderObj
  } #Ende 10

  #Hier nochmal das gleiche Spiel nur mit Ausgabe der Bilder
  20 = FILES
  20 {
    stdWrap.wrap = <div class="carousel-inner">|</div>
    references {
      data = levelmedia:-1, slide
      treatIdAsReference = 1
    }
    renderObj = COA
    renderObj {
      wrap = <div class="item active">|</div>|*|<div class="item">|</div>
      3 = IMAGE
      3 {
        stdWrap.wrap = |
        stdWrap.required = 1
        file.import.data = file:current:originalUid
        # Setze den Link der im Bild eingestellt ist um das Bild
        stdWrap.typolink.parameter.data = file:current:link
        altText.data = file:current:alternative
        titleText.data = file:current:alternative
      } #Ende 3
      # Hier Titel und Beschreibung für das Bild, wird auch vom Link umgeben.
      6 = COA
      6 {
        # alles nur, wenn Titel gesetzt ist
        if.isTrue.data = file:current:title
        wrap = <div class="carousel-caption">|</div>
        stdWrap.required = 1
        stdWrap.typolink.parameter.data = file:current:link
        4 = TEXT
        4.wrap = <h3>|</h3>
        4.data = file:current:title
         
        8 = TEXT
        8.wrap = <p>|</p>
        8.data = file:current:description 

      } #Ende 6
    } #Ende renderObj
  } #Ende 20
} #Ende headerimage

Letztendlich wird hier ein Carousel genau nach Beschreibung aufgebaut. Im Wrap ein paar vorbereitende Zeilen (inclusive überlagertem Logo) und dann der Kopf des Carousels mit der Geschwindigkeitsangabe und der Klasse zum Starten.

Danach wird dann unter 10 der Carousel-Indicator aufgebaut, dabei geht Typoscript durch alle Bilder. Wenn man den Indicator nicht haben möchte, dann kann man den ganzen 10er Block einfach weglassen.

Anschließend werden unter 20 die Bilder eingebunden und ggf. mit den Metadaten versehen.

Veröffentlicht unter typo3.

Für ein aktuelle Projekt brauchte ich einen Bilder-Slider im Header. Meine sonstigen Slider sind eher als Content-Elemente gedacht. Daher habe ich mich mit dem Bootstrap Carousel beschäftigt.

Der Slider soll mit dem Bildern aus der Seiteneigenschaft Resourcen arbeiten. Zur Vereinfachung gehe ich einfach davon aus, dass er die ersten drei Bilder benutzt. Bei Gelegenheit muss ich mir dann auch einmal Gedanken über eine Schleifenstruktur durch die vorhandenen Bilder machen.

Mit einer festen Zahl ist die Lösung recht einfach:

 lib.field_headerimage = COA
   lib.field_headerimage.10 = TEXT
   lib.field_headerimage.10.value (
     <div id="skiplink">
     <a class="skip" title="Direkt zur Navigation springen" href="#navigation">Zur Navigation springen</a><br>
     <a class="skip" title="Direkt zum Content springen" href="#content">Zum Content springen</a>
     </div>

    <div id="blogo">
     <a href="/"><img src="fileadmin/user_upload/Logo_trans.png" /></a>
    </div>
    <div id="hslider" class="carousel slide carousel-fade">
    <div class="carousel-inner">
   )

   lib.field_headerimage.20 = IMG_RESOURCE
   lib.field_headerimage.20 {
    file.import.data = levelmedia:2, slide
    file.treatIdAsReference = 1
    file.import.listNum = 0
    stdWrap.wrap = <div class='item active'><a href='/'><img src='|' style='width: 100%;' /></a></div>
   }

   lib.field_headerimage.30 = IMG_RESOURCE
   lib.field_headerimage.30 {
     file.import.data = levelmedia:2, slide
     file.treatIdAsReference = 1
     file.import.listNum = 1
     stdWrap.wrap = <div class='item'><a href='/'><img src='|' style='width: 100%;' /></a></div>
   }

   lib.field_headerimage.40 < lib.field_headerimage.30 
   lib.field_headerimage.40.file.import.listNum = 2
 
   lib.field_headerimage.90 = TEXT
   lib.field_headerimage.90 {
   value = {$styles.content.hspeed}
   wrap (
     </div></div>
     <script type='text/javascript'>$(document).ready(function(){
     $("#hslider").carousel({interval: |});
    });</script>
  )
}

Im ersten Textbereich werden ein paar Standars-Zeilen generiert und dann der Kopf des Carousels definiert. Über das Javascript im letzten Block wird das Carousel aktiviert. Grundsätzlich kann man das Carousel über Javascript oder folgenden Datenblock aktivieren:

<div id="hslider" class="carousel slide carousel-fade" data-ride="carousel" data-interval="5000">

Ich habe die Version per Javascript benutzt, einfach weil sich das aus meiner Vorlage so ergab und mir nicht klar war, ob das auch mit dem Fade funktioniert. Bei Gelegenheit werde ich aber auf die andere Variante ohne Javascript umstellen.

Normalerweise scrollen die Bilder, mit dem Fade-Effekt kommt es zu einer weicheren Überblendung.

 

Veröffentlicht unter typo3.

Für meine Typo3-Erweiterung nettgrids habe ich ein Accordion-Element (Bootstrap Collapse) erstellt. Für ein Projekte wollte ich jetzt erreichen, dass über einen Link jeweils der passende Tab geöffnet wird.

Nach etwas Experimentieren mit Anregung von https://stackoverflow.com/questions/22254248/bootstrap-3-expand-accordion-from-url#answer-33444574 bin ich zu folgendem Javascript gekommen:

<script type="text/javascript"> $("a").click(function () {     
  function show_tab(){
   if(location.hash != null && location.hash != "")
   {         $('.collapse').removeClass('in');
             $(location.hash + '.collapse').collapse('show');     
   }
    }
    window.setTimeout(show_tab, 100);
  }); 
</script>

Das Script kann man einfach in ein HTML-Element vor dem Accordion packen.

Im vorliegenden Listing wird die Javascript-Funktion gestartet, wenn auf einen Link auf der Seite geklickt wird. Man könnte es auch an andere Ereignisse koppeln.

In der Funktion show_tab wird überprüft, ob ein Anker-Links vorhanden ist. Wenn ja, dann wird der aktuelle Tab geschlossen und der Zieltab geöffnet. Um die Funktion herum liegt eine Funktion zur Verzögerung. Ohne Verzögerung wäre der neun Link mit dem Anker-Ziel noch aktuell und der Aufruf käme zu früh. Die Verzögerung ist hier auf 0,1 Sekunden eingestellt.

Veröffentlicht unter typo3.

Bei einem Typo3-Projekt sollten die Seiten jeder Hauptrubrik unterschiedliche Farben bekommen. Dafür kann man mit den Conditions von Typo3 schnell eine Lösung basteln.

In der Typoscript setup habe ich am Ende die folgenden Zeilen ergänzt:
 
 # 21 = Schulprofil
 [PIDinRootline = 21]
  page.bodyTagAdd = class="schulprofil"
 [global]
 
 # 31 = Schülerinnen+Schüler
 [PIDinRootline = 31]
  page.bodyTagAdd = class="schueler"
 [global]

...

Es handelt sich hier um bedingte Anweisungen (Conditions) in Typoscript. Die Zahlen sind jeweils die Seitennummern (PID) der ersten Seite einer Rubrik.

Wenn die jeweilige (Seiten-)Nummer in der rootline auftaucht, also auch in der Brotkrumenleiste stehen würde, dann ist die aktuelle Seite eine Unterseite (oder auch die Seite selber).

Dann wird der Body-Tag der Seite um einen Klassenbezeichner erweitert. Auf diese Klasse kann man dann im CSS Bezug nehmen:

.schulprofil #footer, .schulprofil #spalte-links, .schulprofil .breadcrumb {
   background-color: #ebd1d1;
 }

Hier werden also drei Elemente anhand der bedingten Klassenzuordnung gestaltet.

 

Nützliche Links:

Bei kleinen Grafiken ist der Verwaltungsaufwand beim Laden relativ groß, verglichen mit dem Datenvolumen. Hier bietet es sich an die Grafiken in eine Data-URL umzuwandeln, die direkt im Seitenquelltext angegeben wird.

Gegeben sei die folgende Grafik <img src=“sidebar_more.png“>


Ihre Größe beträgt hier 627 Bytes, was schon relativ viel ist. Mittels:

php -r "echo base64_encode(file_get_contents('sidebar_more.png'));"

wird daraus eine Zeichenkette aus 836 Zeichen, die direkt per Copy&Paste in den Link integriert werden kann (der Teil nach dem Komma):

 <img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAMgAAAAaCAIAAAEKy7R7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhVJREFUeNpi1IqewEAlwPLz2yeqmfXt01uqmZWqdYBaZgEEEOOgCy8erh9fvnFQJ7zA7vlKzfACCCBG9fAuhsEHWL5/fj94XNORZ1kx6TgotERt0gZhaAEEEDUTPTUj8e+fX4PRWX9+/RgkTrmzrlYlqBnqrN8/vw+eQOJg+fD5KzsobUk65w/KSBxMoYVwVqbhyUHoLIAAYtSM7GMYBcQmrd8/RkNhaOfDAQf3NjUByaqp01bsfIEIrN8/v40GDSawSy6+/4QRPWX9Hk1Z2MCtu4O7TTP4AUAADdLm8iAt4P//+zcaCsQG1r9/f0ZDgejA+jsaWKOBRQFoyzbZefzywXM/MQLrz+/R0EEDf//8nVtT9u/fP5WABpTA+juasrCA/0BsHFv69y87StNBxq14NGzQgLUR9+Vb7z99YUPPhqMpCxMcOv2RgYGJgeHPaJk1WhuOBtagC6xsk7OjoUAkAAgwFs2o/tFQGAW0GHT4OxoKo4AGdeHoAM0ooEnC+jOasEYBUcBQneH5m+9fvjN8+cY52nofBVQDgQ7GkW4+QMbxK6eL+9d9+8Hw+SsHzoT19+/ogMMoIA78/w+hLXVMd0/RLOyfuuv4ZzxV4WjCGgVEAWYmpp+/foSWN9978g1zABkNMEq7FI4G2SigfuN9tCocBbTpFY423kfB6HDDKBgyCSvL+PRoKIwCqgOm">

Und hier als Data-Image eingebunden:

Damit entfällt das zusätzliche Laden der Datei.

Bei vielen Typo3-Seiten gibt es Einträge der Art

config.baseURL= http://<domain>/

im root-Template. Will man dem Benutzer die Wahl lassen zwischen http und https ist das ein Problem, weil dann bei einer sicheren Verbindung Inhalte unsicher nachgeladen werden. Firefox blockt diese Inhalte. Da das  dann oft CSS-Dateien oder ähnliches sind wird die Seite ziemlich verunstaltet.

Eine Lösung besteht darin das benutzte Protokoll zu erfragen. Dazu gibt man im Template unter Konstanten folgenden Code ein:

protocol = http
[globalString = IENV:TYPO3_SSL=1]
  protocol = https
[global]

Nun kann man im Setup darauf Bezug nehmen:

# Das Protokoll wird unter Constants ermittelt
config.baseURL= {$protocol}://<domain>/

Nun klappt das auch mit der sicheren Verbindung.

Veröffentlicht unter typo3.

Ich bin jetzt zweimal auf ein Problem im Zusammenhang mit Typo3 und dem Nivo-Slider gestoßen. In beiden Fällen hat ein Browser die Bilder im Slider bei jedem Durchlauf neu geladen und damit eine gewisse Netzlast erzeugt, natürlich abhängig von der Internetanbindung des zugehörigen Rechners.

In einem ersten Durchlauf habe ich die zugehörige IP mit iptables blockiert und konnte anhand der IP den Verursacher erreichen. Im zweiten Fall ist das aber ein Ntuzer mit dynamischer IP, die sich täglich ändert. Das kann auf Dauer mühsam werden da am Ball zu bleiben, zumal der Verursacher keine weiteren Informationen bekommt.

Daher habe ich jetzt versucht per .htaccess der IP-Adresse eine andere Seite mit Probleminformationen zukommen zu lassen. Dazu habe ich die .htaccess von dem zugehörigen Typo3-System um folgende Zeilen erweitert:

RewriteCond %{REMOTE_ADDR} ^192\.168\.1\.1$  
RewriteCond %{REQUEST_URI} !^\/sorry\.html
RewriteRule $ /sorry.html [R=302,L]

Die IP-Adresse habe ich hier natürlich verändert.

Jeder Aufruf von dem Rechner aus wird also auf die Seite sorry.html umgeleitet, die Hinweise auf das Problem liefert.

Quellen:
http://www.the-art-of-web.com/system/rewrite/
http://www.modrewrite.de/mod-rewrite/beispiele/ip-bereiche-blocken/

Sollen normale Nutzer die Möglichkeit haben den Seitencache zu löschen, so muss man im Benutzer TSConfig die folgende Einstellung vornehmen:

 ### Loescht den FE-Cache ###
 options.clearCache.pages = 1

Auch für Admin-Benutzer kann es nützlich sein alle Caches löschen zu können:

 ### Loescht FE-Cache und Cache in typo3conf ###
 options.clearCache.all = 1
Veröffentlicht unter typo3.

Das Modul Liste im Backend von Typo3 sieht eine Suche vor. Das Suchformular taucht recht oben auf und unter den einzelnen Inhalts-Angaben. Leider funktioniert die Suche nicht im Zusammenhang mit Erweiterungen wie tt_news und anderen.

Bei diesen Extensions muss man die Datei tca.php (im Ordner der jeweiligen Extension) anpassen. Für tt_news ist folgende Zeile sinnvoll:

$TCA['tt_news']['ctrl']['searchFields'] = 'title,keywords,bodytext,abstract';

Die Zeile wird direkt vor dem passenden Array platziert (Zeile 22):

$TCA['tt_news'] = Array (
        'ctrl' => $TCA['tt_news']['ctrl'], 
        'interface' => Array (
        ....

Danach wird auch in den angegebenen Felder gesucht.
Ähnlich bei anderen Extensions:

$TCA['tx_kesmallads_smallads']['ctrl']['searchFields'] = 'title,content,email';
$TCA["tx_kesmallads_smallads"] = Array (
        "ctrl" => $TCA["tx_kesmallads_smallads"]["ctrl"],
        "interface" => Array (
        ....

oder

$TCA['user_adressen_adresse']['ctrl']['searchFields'] = 'name,strasse,webdokumente,infos';
$TCA["user_adressen_adresse"] = Array (
        "ctrl" => $TCA["user_adressen_adresse"]["ctrl"],
        "interface" => Array (
        ...

 

 

Veröffentlicht unter typo3.