Bedienoberfläche für Webradio
ulrich
2018-03-24 7a416cff73f06f6f2e2070119d38d46526b49f6d
Vorlagen asynchron und nur bei Bedarf laden
3 files modified
1 files added
220 ■■■■■ changed files
README.md 14 ●●●●● patch | view | raw | blame | history
app.js 150 ●●●● patch | view | raw | blame | history
index.html 1 ●●●● patch | view | raw | blame | history
vorlagen.js 55 ●●●●● patch | view | raw | blame | history
README.md
@@ -89,20 +89,6 @@
Die obige Ordnerstruktur wird auf einem HTTP-Server wie z.B. [Tomcat](https://de.wikipedia.org/wiki/Apache_Tomcat) oder [lighttpd](https://de.wikipedia.org/wiki/Lighttpd) hinterlegt und kann dann mit einem Browser aufgerufen werden.
## Noch zu erledigen
### Templates für Mustache dynamisch laden
Spart Ladezeit zu Beginn. Lösungsansatz: Eine Funktion, die als Parameter das Element erhält, dessen html mit dem gerenderten Template ersetzt werden soll und den zu rendernden Inhalt. Die dynamische Ladefunktion
1. prüft, ob das Template schon im cache ist
1. Lädt das Template, wenn nicht
1. wartet, bis das Template geladen ist
1. rendert das Template mit dem übergebenen Inhalt
1. schreibt das Ergebnis ins html des übergebenen Elements
Der letzte Teil des Ablaufs muss asynchron gefasst sein, damit auf das Laden gewartet werden kann.
## Schnittstellenbeschreibung
Für den Prototyp des radio-ui können verschiedene Arten des Umgangs mit Sendern und Abspielern hergestellt werden. Die folgenden Angaben zeigen die Punkte auf, an denen eine konkrete Implementierung ansetzen kann.
app.js
@@ -13,14 +13,15 @@
var TPL_DLG_ABSPIELER_EDIT_FORM = 'dlg-abspieler-edit-form';
var TPL_DLG_ABSPIELER_DEL = 'dlg-abspieler-del';
var TPL_ABSPIELER_EINTRAG = 'abspieler-eintrag';
var templateCache = {}; // mustache templates
var prefsRendered = false;
var senderKlickModus = "1"; // 1=abspielen, 2=bearbeiten, 3=loeschen
var ID_UNDEFINED = -1;
var A_ID_UNDEFINED = -1;
var suchTimeout;
var vorlagen;
function app_init() {
  vorlagen = new Vorlagen();
  $('.sued').text('Initialisieren..');
  $('.dialog').hide();
  $('.ost').hide();
@@ -32,21 +33,6 @@
    "../jslib/app-menu/app-menu.tpl",
    ".west",
    "8em");
  // Templates laden
  app_get_template('data/tpl/dlg-msg.tpl', TPL_DLG_MSG);
  app_get_template('data/tpl/dlg-info.tpl', TPL_DLG_INFO);
  app_get_template('data/tpl/sender.tpl', TPL_SENDER);
  app_get_template('data/tpl/dlg-sender-neu.tpl', TPL_DLG_SENDER_NEU);
  app_get_template('data/tpl/dlg-sender-edit.tpl', TPL_DLG_SENDER_EDIT);
  app_get_template('data/tpl/dlg-sender-loeschen.tpl', TPL_DLG_SENDER_DEL);
  app_get_template('data/tpl/dlg-sender-edit-form.tpl', TPL_SENDER_EDIT_FORM);
  app_get_template('data/tpl/kachel.tpl', TPL_SENDER_KACHEL);
  app_get_template('data/tpl/abspieler.tpl', TPL_ABSPIELER);
  app_get_template('data/tpl/dlg-abspieler-neu.tpl', TPL_DLG_ABSPIELER_NEU);
  app_get_template('data/tpl/abspieler-eintrag.tpl', TPL_ABSPIELER_EINTRAG);
  app_get_template('data/tpl/dlg-abspieler-loeschen.tpl', TPL_DLG_ABSPIELER_DEL);
  app_get_template('data/tpl/dlg-abspieler-edit-form.tpl', TPL_DLG_ABSPIELER_EDIT_FORM);
  // Klicks auf das Hamburger-Menü-Icon an eine Funktion leiten
  $(".hamburger").on("click", function(e) {
@@ -147,7 +133,7 @@
    Das folgende Kommando in Produktion auskommentieren
  */
  app_dialog_laden_und_zeigen(
    templateCache[TPL_DLG_MSG], 'data/msg-proto.json');
    'data/tpl/dlg-msg.tpl', 'data/msg-proto.json');
}
function app_abspielen_stoppen() {
@@ -163,13 +149,17 @@
}
function app_abspieler_neu(abspieler) {
  var html = Mustache.render(templateCache[TPL_ABSPIELER_EINTRAG], abspieler);
  if(abspieler.zustand === 'selected') {
    $.each($(".abspieler-auswahl option:selected"), function() {
       $(this).prop('selected', false);
    });
  }
  $(".abspieler-auswahl").append(html);
  vorlagen.html_erzeugen(
    'data/tpl/abspieler-eintrag.tpl',
    abspieler,
    function(html) {
      if(abspieler.zustand === 'selected') {
        $.each($(".abspieler-auswahl option:selected"), function() {
           $(this).prop('selected', false);
        });
      }
      $(".abspieler-auswahl").append(html);
  });
}
function app_abspieler_entfernen(abspieler) {
@@ -186,10 +176,14 @@
}
function app_kachel_neu(sender) {
  var html = Mustache.render(templateCache[TPL_SENDER_KACHEL], sender);
  $("#sender").append(html);
  var kachel = $( "div[sid='" + sender.id + "']" );
  kachel.on('click', app_kachel_klick);
  vorlagen.html_erzeugen(
    'data/tpl/kachel.tpl',
    abspieler,
    function(html) {
      $("#sender").append(html);
      var kachel = $( "div[sid='" + sender.id + "']" );
      kachel.on('click', app_kachel_klick);
  });
}
function app_kachel_entfernen(sender) {
@@ -208,23 +202,23 @@
        app_abspielen(s, app_get_abspiel_ziel());
        break;
      case "2":
        $(".dlg-behaelter").html(
          Mustache.render(templateCache[TPL_SENDER_EDIT_FORM], s)
        );
        $('#sender-speichern').on('click', function() {
          $('#sender-speichern').off('click');
          app_kachel_anpassen(app_sender_dialog_lesen(senderId));
          app_dialog_schliessen();
          app_meldung_mit_timeout('Speichern gewaehlt', 1500);
        vorlagen.html_erzeugen(
          'data/tpl/dlg-sender-edit-form.tpl',
          s,
          function(html) {
            $(".dlg-behaelter").html(html);
            var kachel = $( "div[sid='" + sender.id + "']" );
            kachel.on('click', app_kachel_klick);
            $('#sender-speichern').on('click', function() {
              $('#sender-speichern').off('click');
              app_kachel_anpassen(app_sender_dialog_lesen(senderId));
              app_dialog_schliessen();
              app_meldung_mit_timeout('Speichern gewaehlt', 1500);
            });
        });
        break;
      case "3":
        app_dialog_zeigen(templateCache[TPL_DLG_SENDER_DEL], s);
        /*
        $(".dlg-behaelter").html(
          Mustache.render(templateCache[TPL_DLG_SENDER_DEL], s)
        );
        */
        app_dialog_zeigen('data/tpl/dlg-sender-loeschen.tpl', s);
        $('#sender-loeschen').on('click', function() {
          $('#sender-loeschen').off('click');
          app_kachel_entfernen(s);
@@ -246,17 +240,17 @@
function app_nachricht_test() {
  app_dialog_laden_und_zeigen(
    templateCache[TPL_DLG_MSG], 'data/msg-test.json');
    'data/tpl/dlg-msg.tpl', 'data/msg-test.json');
  app_menue_umschalten();
}
function app_info_dialog_zeigen() {
  app_dialog_laden_und_zeigen(templateCache[TPL_DLG_INFO], '');
  app_dialog_laden_und_zeigen('data/tpl/dlg-info.tpl', '');
  app_menue_umschalten();
}
function app_neuer_sender() {
  app_dialog_laden_und_zeigen(templateCache[TPL_DLG_SENDER_NEU], '');
  app_dialog_laden_und_zeigen('data/tpl/dlg-sender-neu.tpl', '');
  $('#sender-speichern').on('click', function() {
    $('#sender-speichern').off('click');
    app_kachel_neu(app_sender_dialog_lesen(--ID_UNDEFINED));
@@ -268,19 +262,19 @@
function app_sender_bearbeiten() {
  senderKlickModus = "2"; // bearbeiten
  app_dialog_laden_und_zeigen(templateCache[TPL_DLG_SENDER_EDIT], '');
  app_dialog_laden_und_zeigen('data/tpl/dlg-sender-edit.tpl', '');
  app_menue_umschalten();
}
function app_sender_loeschen() {
  senderKlickModus = "3"; // loeschen
  app_dialog_laden_und_zeigen(templateCache[TPL_DLG_SENDER_EDIT], '');
  app_dialog_laden_und_zeigen('data/tpl/dlg-sender-edit.tpl', '');
  app_menue_umschalten();
}
function app_abspieler_loeschen() {
  var abspieler = app_get_abspiel_ziel();
  app_dialog_zeigen(templateCache[TPL_DLG_ABSPIELER_DEL], abspieler);
  app_dialog_zeigen('data/tpl/dlg-abspieler-loeschen.tpl', abspieler);
  $('#abspieler-loeschen').on('click', function() {
    $('#abspieler-loeschen').off('click');
    app_abspieler_entfernen(abspieler);
@@ -290,7 +284,7 @@
  app_menue_umschalten();
}
function app_neuer_abspieler() {
  app_dialog_laden_und_zeigen(templateCache[TPL_DLG_ABSPIELER_NEU], '');
  app_dialog_laden_und_zeigen('data/tpl/dlg-abspieler-neu.tpl', '');
  $('#abspieler-speichern').on('click', function() {
    $('#abspieler-speichern').off('click');
    app_abspieler_neu(app_abspieler_dialog_lesen(--A_ID_UNDEFINED));
@@ -301,7 +295,7 @@
}
function app_abspieler_bearbeiten() {
  var abspieler = app_get_abspiel_ziel();
  app_dialog_zeigen(templateCache[TPL_DLG_ABSPIELER_EDIT_FORM], abspieler);
  app_dialog_zeigen('data/tpl/dlg-abspieler-edit-form.tpl', abspieler);
  $("#abspieler-typ").val(abspieler.typ);
  $("#abspieler-zustand").val(abspieler.zustand);
  $('#abspieler-speichern').on('click', function() {
@@ -331,13 +325,18 @@
/* --- Dialogfunktionen --- */
function app_dialog_zeigen(vorlage, inhalt) {
function app_dialog_zeigen(vurl, inhalt) {
  var dlg = $(".dialog");
  dlg.html(Mustache.render(vorlage, inhalt));
  $(".close-btn").on('click', function() {
    app_dialog_schliessen();
  vorlagen.html_erzeugen(
    vurl,
    inhalt,
    function(html) {
      dlg.html(html);
      $(".close-btn").on('click', function() {
        app_dialog_schliessen();
      });
      dlg.slideDown(300);
  });
  dlg.slideDown(300);
}
function app_sender_dialog_lesen(senderId) {
@@ -387,9 +386,13 @@
    dataType : "json"
  }).done(function( senderliste ) {
    $(".sender-kachel").off("click");
    $(".sender-behaelter").html(
      Mustache.render(templateCache[TPL_SENDER], senderliste));
    $('.sender-kachel').on('click', app_kachel_klick);
    vorlagen.html_erzeugen(
      'data/tpl/sender.tpl',
      senderliste,
      function(html) {
        $(".sender-behaelter").html(html);
        $('.sender-kachel').on('click', app_kachel_klick);
    });
  });
}
@@ -399,9 +402,13 @@
    type: "GET",
    dataType : "json"
  }).done(function( abspielerliste ) {
    $(".abspieler-behaelter").html(
      Mustache.render(templateCache[TPL_ABSPIELER], abspielerliste));
    $("#abspielen-stoppen").on('click', app_abspielen_stoppen);
      vorlagen.html_erzeugen(
        'data/tpl/abspieler.tpl',
        abspielerliste,
        function(html) {
          $(".abspieler-behaelter").html(html);
          $("#abspielen-stoppen").on('click', app_abspielen_stoppen);
      });
  });
}
@@ -409,17 +416,17 @@
  vorlage - die Dialogvorlage
  msgTpl - eine Vorlage mit einem Mitteilungstext (optional)
*/
function app_dialog_laden_und_zeigen(vorlage, msgTpl) {
function app_dialog_laden_und_zeigen(vurl, msgTpl) {
  if(msgTpl !== '') {
    $.ajax({
      url: msgTpl,
      type: "GET",
      dataType : "json"
    }).done(function( msg ) {
      app_dialog_zeigen(vorlage, msg);
      app_dialog_zeigen(vurl, msg);
    });
  } else {
    app_dialog_zeigen(vorlage, '');
    app_dialog_zeigen(vurl, '');
  }
}
@@ -449,21 +456,6 @@
    app_meldung_mit_timeout(antwort, 2000);
  }).fail(function(xhr, status, errorThrown ) {
    app_meldung_mit_timeout(errorThrown + " " + status, 2000);
  });
}
/*
  Ein Template vom Server in den Cache laden
  template_url - home.tpl, prefs.tpl, sender.tpl
  tname - 'home', 'prefs', 'sender'
*/
function app_get_template(template_url, tname) {
  $.ajax({
    url: template_url,
    type: "GET",
    dataType : "text"
  }).done(function( template ) {
    templateCache[tname] = template;
  });
}
index.html
@@ -54,6 +54,7 @@
    <script src="../jslib/jquery-1.11.1/jquery-1.11.1.min.js"></script>
    <script src="../jslib/mustache/mustache.min.js"></script>
    <script src="../jslib/app-menu/app-menu.js"></script>
    <script src="vorlagen.js"></script>
    <script src="app.js"></script>
    <script type="text/javascript" charset="utf-8">
      $(document).ready(function() {
vorlagen.js
New file
@@ -0,0 +1,55 @@
function Vorlagen() {
  var self = this;
  this.cache = {}; // mustache templates
  /*
    Das HTML erzeugen, das entsteht, wenn eine Vorlage mit Inhalt
    gefüllt wird
    Das Füllen erfolgt asynchron, d.h. der Programmlauf geht nach dem
    Aufruf weiter ohne auf das Laden und Füllen der Vorlage zu warten.
    Das fertige HTML wird der Callback-Funktion übergeben
    sobald die Vorlage geladen und gefüllt ist, unabhängig davon, wo der
    Programmlauf zu diesem Zeitpunkt mittlerweile ist.
    vurl - URL zur Vorlagendatei
    inhalt - die JSON-Struktur, deren Inhalt in die
              Vorlage gefüllt werden soll
    cb - Callback-Funktion, die gerufen wird, wenn die Vorlage gefüllt ist.
          Dieser Callback-Funktion wird das fertige HTML übergeben
  */
  this.html_erzeugen = function(vurl, inhalt, cb) {
    var vorlage = self.cache[vurl];
    if(vorlage === undefined) {
      self.vorlage_laden_und_fuellen(vurl, inhalt, cb);
    } else {
      self.vorlage_fuellen(vurl, inhalt, cb);
    }
  };
  this.vorlage_fuellen = function(vurl, inhalt, cb) {
    cb(Mustache.render(self.cache[vurl], inhalt));
  };
  /*
    Eine Vorlage vom Server in den lokalen Speicher laden
    vurl - der URL unter dem die Vorlage zu finden ist
    inhalt - die JSON-Struktur, deren Inhalt in die
              Vorlage gefüllt werden soll
    cb - callback: Diese Funktion wird gerufen, wenn die Vorlage mit dem
            Inhalt gefüllt ist
  */
  this.vorlage_laden_und_fuellen = function(vurl, inhalt, cb) {
    $.ajax({
      url: vurl,
      type: "GET",
      dataType : "text"
    }).done(function( vorlage ) {
      self.cache[vurl] = vorlage;
      self.vorlage_fuellen(vurl, inhalt, cb);
    });
  };
}