TYPO3 newscalendar mit Ajax nachladen

Die Extension „newscalendar“ bietet die schöne Möglichkeit tt_news für Veranstaltungen zu verwenden und für die Termine einen Kalender zur Verfügung zu stellen. Das klappt einigermaßen out of the box. Drei Dinge allerdings stören: die Extension kommt mit der veralteten jQuery Version 1.3.2 daher, beim Weiterklicken auf einen Monat wird die Seite neu geladen und die Links zur Single Ansicht funktionieren nicht auf einem touch device.

Zunächst hole man sich von dieser Seite https://github.com/dillon-sellars/BeautyTips eine neuere Version des Plugins Beauty Tips. Diese funktioniert immerhin mit jQuery 1.8.2. und wird folgendermaßen eingebunden:

plugin.tx_newscalendar_pi1 {
  calendar.loadJQuery = 0
  file.jsJQueryTooltip = fileadmin/default/templates/js/jquery.bt.min.js
}

Die jQuery Bibliothek in der Version 1.8.2. bindet man unabhängig von der Extension ein.

Um den Kalender mit Ajax nachladen zu können, benötigt man eine Seite im TYPO3, die lediglich den HTML Code des Kalenders generiert. Um das zu erreichen legt man eine im Menü versteckte Seite an, bindet den Datensatz mit dem newscalendar-Plugin ein und erstellt ein Extension Template mit folgendem Inhalt:

config {
   disableAllHeaderCode = 1
}
page.10 = TEMPLATE
page.10 {
    template = FILE
    template.file = fileadmin/default/templates/blank.html
    workOnSubpart = DOCUMENT
}
page.10.subparts {
   CONTENT < styles.content.get 
}
tt_content.stdWrap.innerWrap >

Die Datei blank.html sieht so aus:

<!--###DOCUMENT###-->
<!--###CONTENT###-->
content
<!--###CONTENT###-->
<!--###DOCUMENT###-->

Für das Nachladen mit Ajax erstellt man eine JavaScript Datei mit folgendem Inhalt:

jQuery(function($) {
    var uid_of_calendar_page = 76;
    $('.tx-ttnews').parent('div').on('click', 'td.columPrevious a, td.columNext a', function(e) {
        e.preventDefault();
        var $a = $(this);
        var $parent = $a.closest('.tx-ttnews').addClass('loading');
        var url = $a.attr('href').split('?'); 
        var new_url = 'index.php?id='+uid_of_calendar_page+'&'+url[1];
        $.ajax({
            url: new_url,
            type: 'get',
            dataType: 'html',
            success: function(new_calendar) {
               $parent.find('div').remove();
               $(new_calendar).insertAfter($parent);
               $parent.remove();
           }
       });
        $parent.append('<div class="spinner"></div>');
    });
});

Die Seite mit der id 76 ist die oben erstellte Seite mit unserem Kalender HTML Code. Als nächstes wird auf die Monatsweiterschaltungen ein Klick Event gelegt. Nun wird die URL gesplittet. Der Ajaxcall lädt dann mit Hilfe der Variable new_url den Code aus der Seite mit der HTML Version des Kalenders und fügt ihn an die gewünschte Stelle auf der aktuellen Seite ein. Der div.spinner erzeugt eine loading-Animation, die ausschließlich mit CSS realisiert wird. Das ist die grobe Beschreibung der Lösung. Genauer Interessierte finden die Details im obigen Quellcode.

Den newscalendar auf einem touch device funktionstüchig machen

Weiterhin funktioniert beim newscalendar das Klicken auf den Termin nicht bei einem touch Gerät. Um das zu korrigieren muss man die Datei class.newscalendar.js modifizieren. Glücklicherweise kann man den Pfad zu der Datei über TypoScript konfigurieren:

plugin.tx_newscalendar_pi1 {
  calendar.loadJQuery = 0
  file.jsJQueryTooltip = fileadmin/default/templates/js/jquery.bt.min.js
  file.jsNewscalendar = fileadmin/default/templates/js/class.newscalendar.js
}

Zunächst wird abgefragt, ob es sich um ein touch Gerät handelt und das Ergebnis in einer Variable gespeichert:

var is_touch_device = 'ontouchstart' in document.documentElement;

Standardmäßig funktioniert der „Beauty Tip“ im Kalender mit den Events mouseover, mouseleave und mouseout. Diese steuern das Ein-und Ausblenden des Layers. Das funktioniert auf einem touch Gerät naturgemäß nicht. Im Original-Skript müssen ab ca. Zeile 90 folgende Änderungen vorgenommen werden:

if(!is_touch_device) {
  jQuery( '#idMenu' + toolTipID ).mouseover( function( event ) {
    event.preventDefault();
    var currentSelectStarter = this;
    newscalendar.addToolTipSelectorClass( currentSelectStarter, 'newscalendar-tip-selector' );
    jQuery( '#idMenu' + toolTipID ).btOn();
    jQuery( '.newscalendar-tip-id-' + toolTipID ).bind( 'mouseleave', function( event ) {
      event.preventDefault();
      jQuery( '#idMenu' + toolTipID ).btOff();
      newscalendar.removeToolTipSelectorClass( currentSelectStarter, 'newscalendar-tip-selector' );
    });
    jQuery( '#idMenu' + toolTipID ).mouseout( function( event ) {
      event.preventDefault();
      var checkTo = 'not_defined';
      if ( typeof event.toElement !== "undefined" ) {
        checkTo = event.toElement.tagName ;
      }  else if ( typeof event.relatedTarget !== "undefined" ) {
        checkTo = event.relatedTarget.localName;
      }
      try {
        if ( checkTo !== 'canvas' && checkTo !== 'CANVAS' &&  checkTo !== 'shape' ) {
        jQuery( '#idMenu' + toolTipID ).btOff();
        newscalendar.removeToolTipSelectorClass( currentSelectStarter, 'newscalendar-tip-selector' );
        }
      } catch(e) {}
    } );
  } );
}  else {
    jQuery( '#idMenu' + toolTipID ).bind('click', function( event ) {
      event.preventDefault();
      if($(this).data('tooltip')) {
        jQuery( '#idMenu' + toolTipID ).btOff();
        newscalendar.removeToolTipSelectorClass( currentSelectStarter, 'newscalendar-tip-selector' );
        $(this).data('tooltip', false);
        return;
      }
      $(this).data('tooltip', true);
      var currentSelectStarter = this;
      newscalendar.addToolTipSelectorClass( currentSelectStarter, 'newscalendar-tip-selector' );
      jQuery( '#idMenu' + toolTipID ).btOn();
    } );    
  }

Auf der Demoseite kann man sich über den Quelltext die komplette Datei class.newscalendar.js mitsamt den Änderungen anschauen.

Die Ajax Loading Animation ist reines CSS und stammt von hier:
http://tobiasahlin.com/spinkit/

Credits für diese Lösung an Paul