Trigger onClose und nicht onUnload

19. Dezember 2009

OnClose und nicht Onload
In meinem Seminar über Webentwicklung kam die Frage auf, ob man abfangen kann, wenn ein Benutzer das Browserfenster – oder den aktuellen Tab – schließt, um so bspw. eine aktive Session zu beenden. Das wäre dann ja wohl der Event-Handler onClose, nur leider ist dieser in kaum einem Browser verfügbar.

Es gibt den Event-Handler onUnload, aber der ist für den angedachten Zweck nicht direkt zu gebrauchen, denn onUnload feuert wann immer man eine Seite verlässt oder erneut lädt.
In ein paar älteren Artikeln fand ich eine Idee, die zwar den onUnload Event-Handler nutzt, aber nur feuert, wenn Höhe und Breite des Fensters kleiner 0 sind – also kein Fenster (oder Tab) mehr vorhanden ist. Unglaublich, aber wahr: Das funktioniert – aber so eben nur im Internet Explorer. Mit ein paar Änderungen läuft das ganze auch im FireFox (getestet auf FF 3.5.5):

//einfaches binden von events, nur damit das script laeuft...
function listen(evnt, elem, func) {
 if (elem.addEventListener)  {
  elem.addEventListener(evnt,func,false);
 } else if (elem.attachEvent) {
  var r = elem.attachEvent("on"+evnt, func);
  return r;
 }
}
 
// die onclose Implementierung...
function checkClosed(e) {
 var e = e || window.event;
 var closed = false;
 if(window.innerWidth != undefined && window.innerWidth <= 0) {
  //ff
  closed = true;
 } else if(e != undefined &&
   e.clientY != undefined && e.clientY <= 0) {
  //ie
  closed = true;
 }
 if(closed) {
  //feuert nur dann, wenn das fenster geschlossen wird...
  [...]
 }
}
 
// und binden der funktion an den event unload
listen('unload',checkClosed);

Eine ernstzunehmende Lösung ist das aber nicht, so kann das Script bspw. nicht abfangen, ob ein Benutzer schlichtweg eine neue URL eingibt, oder die Anwendung über ALT+F4 beendet. Und unterstützt werden auch nur Internet Explorer und FireFox – Google Chrome, Opera und Safari lassen sich auf diese Weise nicht um ein “onClose” erweitern.

Um eine aktive Session dennoch nicht zu lange aufrecht zu erhalten, hilft es, den entsprechenden Wert in der PHP.ini anzupassen (session.gc_maxlifetime), das ist zwar nicht so exakt, aber erfüllt seinen Zweck, ganz unabhängig von JavaScript.

Typo3 Snippets

08. Dezember 2009

Typo3 Snippets
Kleine Sammlung von Typo3 Snippets und nützlichen Quellen zum gleichen Thema für alle Kursteilnehmer des Typo3 Einsteiger Seminars. Die hier aufgelisteten Snippets sind nur eine lose Auflistung von Fragmenten aus den verschiedensten Aufgabenbeeichen, die vielleicht hilfreich sein könnten. Von der Optimierung der generierten HTML Syntax, über Navigationsvarianten bis zu speziellen Wrap Anweisungen.

Was ist TypoScript eigentlich? Grundsätzlich: TypoScript ist keine Programmiersprache. Es ist eher eine Konfigurationssprache – vergleichbar mit der Windows Registry. Und wie die Windows Registry ist TypoScript mächtiger als man auf den ersten Blick vermutet. Die offizielle Dokumentation findet man unter TSref bei Typo3. Und noch eine Analogie zur Windows Registry – je mehr Module und Plugins man lädt, desto größer wird der TypoScript Anteil des Projektes. Viele Plugins (bspw. Better Contact) lassen sich komplett über TypoScript konfigurieren.
Die Scriptsyntax lässt sich übrigens auch in seperate Dateien auslagern. Und mit SweeTs gibt es für den Editor PSPad sogar entsprechendes Syntax-Highlighting. Ähnliches liefert DEV3 – TYPO3 Enterprise Development für Eclipse. Eingebunden werden solche externen Dateien dann über:

<INCLUDE_TYPOSCRIPT: source="FILE: fileadmin/scriptdatei.ts">

Folgendes ist dabei zu beachten:

  • Im Template muss das Include in einer eigenen Zeile stehen, sonst wird es nicht erkannt.
  • Das Include wird vor dem Parsen des TS ausgeführt und funktioniert nicht mit Conditions und Verschachtelungen.
  • Die Dateigröße darf nicht größer als 100KB sein.
  • Die URL der Datei muss ausgehend von PATH_side sein, darf also kein “..” enthalten.
  • Die Dateien werden “gecacht”, d.h. Änderungen greifen nicht sofort, sondern erst nach dem Leeren des Caches, in der Installationsanleitung bei SweeTS findet man aber einen Lösungsvorschlag, um dieses Problem zu umgehen.

Genug der Vorrede, hier nun ein paar Snippets aus der Welt von TypoScript. Viel mehr davon findet man bspw. unter TYPO3 Wizard: Snippets oder bei TYPO3 snippets.

Absatzidentifizierung verbessern (die leeren A-Tags)

Verändert man die Vorgaben für CSS Styled Contents nicht, so liefert Typo3 jeden Absatz mit einem leeren A-Tag aus. Dieser Tag enthält die eindeutige Referenz für den Absatz (‘c’+UID des Datenbank Eintrages). Grundsätzlich ist dieser Ansatz ja nicht schlecht – immerhin kann man so theoretisch auf jeden einzelnen Textbaustein der gesamten Seite verweisen, aber der Code lässt sich optimieren. Zum einen sind Tags ohne Inhalt (wenn es sich nicht um selbst-schließende Tags handelt) in XHTML strict gar nicht zugelassen, zum zweiten kann es hilfreich sein jeden Absatz mit einer eigenen ID zu versehen (in Hinblick auf CSS und Javascript Spielereien). Eine ID lässt sich ebenso als Sprungmarke nutzen wie ein A-TAG mit einem NAME-Attribut. Der TypoScript code dafür:

tt_content.stdWrap.dataWrap = <div id="c{field:uid}">|</div>

Jede Seite identifizieren (Optimierung body tag)

Wohl noch häufiger als die notwendige Identifizierung jedes einzelnen Textbausteins ist die Unterscheidung verschiedener Seiten, auch wenn Sie auf ein- und demselbem Template basieren, auch hier kann man sich die UID zu Nutze machen:

page.bodyTagCObject = HTML
page.bodyTagCObject.value.field = uid
page.bodyTagCObject.value.wrap = !!<=|>

Inhalte nur umschließen, wenn nicht leer

Ein Wrap ist manchmal nur dann nötig, bzw. sollte auch nur dann stattfinden, wenn auch Inhalte vorhanden sind, die Syntax hierfür ist:

tt_content.stdWrap {
 wrap =  <div>|</div>
 required = 1
}

Inhalte aus einer anderen Spalte ausgeben

Nützlich für den Fall, dass auf bestimmten Seiten die Inhalte an anderer Stelle dargestellt werden sollen, als es “normaler” Weise in dem Template vorgesehen ist, ohne dafür ein neues Template zu erstellen. Um diese Angabe auf einen bestimmten Seitenbereich einzugrenzen kann man PIDinRootline nutzen:

#Alle Seiten unterhalb von der Seite mit der uid 1
[PIDinRootline = 1]
#Wobei die ColPos die Spalte definiert
#(Normal=0, Links=1, Rechts=2, Rand=3)
temp.boxes = CONTENT
temp.boxes {
  table = tt_content
  select {
    pidInList.field = uid
    orderBy = sorting
    where = colPos = 2
  }
}
[END]

Eine Basis Konfiguration

Ein Satz an allgemeinen Konfigurationsregeln für die Ausgabe von XHTML Seiten.

config {
   doctype = xhtml_strict
   xhtml_cleaning = all
   xmlprologue = none
   metaCharset = utf-8
   additionalHeaders = Content-Type:text/html;charset=utf-8
   htmlTag_langKey = de
   locale_all = de_DE
   language = de
   removeDefaultJS = 1
   simulateStaticDocuments = 0
   baseURL = http://www.beispiel.de
   #für den Fall das RealUrl verwendet wird
   #tx_realurl_enable = 1
}

Aufräumen bei der HTML Ausgabe

CSS Styled Contents und der RTE Parser produzieren mir persönlich zuviele Klassen und Verschachtelungen, da kann man ruhig ein wenig anpassen:

#entfernen von class="bodytext" aus den <p>-Tags
lib.parseFunc_RTE.nonTypoTagStdWrap.encapsLines.addAttributes.P >
 
#Entfernen der style Attribute (Hoehe und breite) für Bild-Wrapper
tt_content.image.20.rendering.dl.imageRowStdWrap.dataWrap =
  <div class="csc-textpic-imagerow">|</div>
tt_content.image.20.rendering.dl.oneImageStdWrap.dataWrap =
  <dl class="csc-textpic-image###CLASSES###">|</dl>
 
## Liste der Tags, die nicht mit p-Tags umschlossen werden
lib.parseFunc_RTE.nonTypoTagStdWrap.encapsLines.encapsTagList =
 div,p,pre,h1,h2,h3,h4,h5,h6,address

Navigation

Nachfolgend noch ein Beispiel für ein Navigationsmenü, hier aufgeteilt auf zwei Ebenen (oberste Navigationsebene, enthält neben dem Titel noch einen Untertitel) und einem zweiten Menü für die untergeordneten Seiten:

#Hauptnavigtion (1. Ebene)
lib.mainMenu = HMENU
lib.mainMenu.1 = TMENU
lib.mainMenu.entryLevel = 0
lib.mainMenu.1.expAll = 0
lib.mainMenu.1.noBlur = 1
lib.mainMenu.1.NO = 1
lib.mainMenu.1.NO {
  stdWrap.cObject = COA
  stdWrap.cObject {
    10 = TEXT
    10.field = title
    10.stdWrap.htmlSpecialChars = 1
    10.wrap = <strong>|</strong>&#32;
    20 = TEXT
    20.field = subtitle
    20.stdWrap.htmlSpecialChars = 1
    20.wrap = <em>|</em>
  }
  linkWrap = <li id="mm_{elementUid}">|</li>
  subst_elementUid = 1
}
 
lib.mainMenu.1.ACT = 1
lib.mainMenu.1.ACT < .lib.mainMenu.1.NO
lib.mainMenu.1.ACT.linkWrap = <li id="mm_{elementUid}" class="active">|</li>
 
#Untergeordnetes Menü 2-3 Ebene
lib.subMenu = HMENU
lib.subMenu {
  entryLevel = 1
  1 = TMENU
  1 {
    NO = 1
    NO {
     linkWrap = <li>|</li>
    }
    ACT = 1
    ACT {
      stdWrap.cObject = COA
      stdWrap.cObject {
        10 = TEXT
        10.field = title
        10.stdWrap.htmlSpecialChars = 1
        10.wrap = <strong>|</strong>
     }
     linkWrap = <li>|</li>
    }
  }
  2 = TMENU
  2 {
    wrap = <ul>|</ul>
    NO = 1
    NO {
      linkWrap = <li>|</li>
    }
    ACT = 1
    ACT {
      stdWrap.cObject = COA
      stdWrap.cObject {
        10 = TEXT
        10.field = title
        10.stdWrap.htmlSpecialChars = 1
        10.wrap = <strong>|</strong>
      }
     linkWrap = <li>|</li>
    }
  }
}

Zugegeben, auf den ersten Blick ist TypoScript sicher ein wenig gewöhnungsbedürftig, aber wer ernsthafter mit Typo3 arbeiten will, der kommt nicht umhin, sich tiefer in die Materie einzuarbeiten. Neben der bereits erwähnten TSRef findet man bei Typo3 u.a. auch noch den Artikel TypoScript Syntax and In-depth Study, ein umfassendes Tutorial zur Syntax und Funktionsweise vom TypoScript und eine mehrteilige deutschsprachige Einführung findet man beim Webworking Blog. In diesem Sinne, erfolgreiches Skripten.

Seite 11 von 13Anfang...910111213