Rumpf-Konstrukt fuer Webapps
ulrich
2021-05-11 e27e7361c2e6f5c02b275ae320e778ab6fc7aaaf
commit | author | age
00c9b9 1 /*
U 2   Proto - Ein Rumpf-Konstrukt fuer Webapps
3   Copyright (C) 2021  Ulrich Hilger
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU Affero General Public License as
7   published by the Free Software Foundation, either version 3 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU Affero General Public License for more details.
14
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 function Proto() {
19   var self = this;
20   var appMenu;
21   var cache; // mustache templates
22
23
24   this.init = function() {
25     self.cache = new Array();
26     self.appMenu = new AppMenu();
27     self.appMenu.init(
28       "data/menu/",
29       "hauptmenue.json",
30       "data/tpl/app-menu.txt",
31       ".west",
32       "8em");
33
34     document.querySelector('.hamburger').addEventListener('click', function(e) {
35       self.menue_umschalten();
36     });
37     
38     self.fusszeile_umschalten();
39     self.seitenleiste_umschalten();
40
41   };
42
43   /* ------------------ sonstige Helfer ----------------------- */
44       
45   this.addEvtListener = function(selector, eventName, func) {
46     document.querySelectorAll(selector).forEach(elem => { elem.addEventListener(eventName, func); });
47   };
48   
49   this.removeClassMulti = function(selector) {
50     document.querySelectorAll('.' + selector).forEach(elem => { elem.classList.remove(selector); });
51   };
52   
53   /* --------------------- asynchroner HTTP Client ----------------- */
54   
55   this.http_get = function (u, cb) {
56     self.http_call('GET', u, null, cb);
57   };
58
59   this.http_post = function (u, data, cb) {
60     self.http_call('POST', u, data, cb);
61   };
62
63   this.http_put = function (u, data, cb) {
64     self.http_call('PUT', u, data, cb);
65   };
66   
67   this.http_delete = function (u, data, cb) {
68     // console.log("delete " + u);
69     self.http_call('DELETE', u, data, cb);
70   };
71   
72   this.http_call = function (method, callurl, data, scallback) {
73     var xhr = new XMLHttpRequest();
74     xhr.onreadystatechange = function () {
75       if (this.readyState === 4 && this.status === 200) {
76         scallback(this.responseText);
77       }
78     };
79     xhr.open(method, callurl);
80     if (method === 'GET') {
81       xhr.send();
82     } else if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
83       xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
84       xhr.send(data);
85     }
86   };
87   
88   /* ------------------------ aus App-Vorlage -------------------  */
89
90   this.menue_umschalten = function () {
91     var ham = document.querySelector(".hamburger");
92     ham.classList.toggle("is-active"); // hamburger-icon umschalten
93     self.appMenu.toggle(); // menue oeffnen/schliessen
94   };
95
96   this.info_dialog_zeigen = function () {
97     self.dialog_laden_und_zeigen('data/tpl/dlg-info.txt', '');
98     self.menue_umschalten();
99   };
100
101   this.seitenleiste_umschalten = function () {
102     var ostDiv = document.querySelector('.ost');
103     if (ostDiv.classList.contains('ost-open')) {
104       ostDiv.classList.remove('ost-open');
105       ostDiv.style.flexBasis = '0em';
106     } else {
107       ostDiv.classList.add('ost-open');
108       ostDiv.style.flexBasis = '6em';
109     }
110     self.menue_umschalten();
111   };
112
113   this.fusszeile_umschalten = function () {
114     var suedDiv = document.querySelector('.sued');
115     if (suedDiv.classList.contains('sued-open')) {
116       suedDiv.classList.remove('sued-open');
117       suedDiv.style.height = '0';
118     } else {
119       suedDiv.classList.add('sued-open');
120       suedDiv.style.height = '1.5em';
121     }
122     self.menue_umschalten();
123   };
124
125   this.menu_message = function (msg) {
126     self.meldung_mit_timeout(msg, 1500);
127     var suedDiv = document.querySelector('.sued');
128     if (suedDiv.classList.contains('sued-open')) {
129     } else {
130       suedDiv.classList.add('sued-open');
131       suedDiv.style.height = '1.5em';
132     }
133     self.menue_umschalten();
134   };
135
136   this.message_1 = function () {
137     self.menu_message('Eine Mitteilung.');
138   };
139
140   this.message_2 = function () {
141     self.menu_message('Was wir schon immer sagen wollten.');
142   };
143
144   this.message_3 = function (text) {
145     self.menu_message(text);
146   };
147
148   this.meldung_mit_timeout = function (meldung, timeout) {
149     var s = document.querySelector('.sued');
150     s.classList.add('sued-open');
151     s.style.height = '1.5em';
152     s.textContent = meldung;
153     setTimeout(function () {
154       s.textContent = 'Bereit.';
155       setTimeout(function () {
156         var suedDiv = document.querySelector('.sued');
157         if (suedDiv.classList.contains('sued-open')) {
158           suedDiv.classList.remove('sued-open');
159           suedDiv.style.height = '0';
160         }
161       }, 500);
162     }, timeout);
163   };
164   
165   /* --------------------- Dialog-Funktionen ------------------------ */
166
167   /*
168    Einen Dialog aus Vorlagen erzeugen
169    
170    vurl - URL zur Dialogvorlage
171    msgTpl - URL mit einer Vorlage eines Mitteilungstextes (optional)
172    */
173   this.dialog_laden_und_zeigen = function (vurl, msgTpl, cb) {
174     var vorlage = self.cache[vurl];
175     if(vorlage === undefined) {
176       self.http_get(vurl, function(antwort) {
177         self.cache[vurl] = antwort;
178         self.dialog_zeigen(vurl, msgTpl, cb);
179       });
180     } else {
181       self.dialog_zeigen(vurl, msgTpl, cb);
182     }
183   };
184
185   this.dialog_zeigen = function (vurl, inhalt, cb) {
186     var dlg = document.querySelector(".dialog");
187     self.html_erzeugen(vurl, inhalt, function (html) {
188       dlg.style.height = '7em';
189       dlg.innerHTML = html;
190       document.querySelector('.close-btn').addEventListener('click', self.dialog_schliessen);
191       if(typeof(cb) !== 'function') {
192         // ..
193       } else {
194         cb();
195       }
196     });
197   };
198   
199   this.dialog_schliessen = function () {
200     document.querySelector('.close-btn').removeEventListener('click', self.dialog_schliessen);
201     var dlg = document.querySelector('.dialog');
202     dlg.style.height = '0';
203     dlg.innerHTML = '';
204   };
205
206   /* ---------------------   Vorlagen   ---------------------- */
207
208   /*
209    Das HTML erzeugen, das entsteht, wenn eine Vorlage mit Inhalt
210    gefüllt wird
211    
212    Das Füllen erfolgt asynchron, d.h. der Programmlauf geht nach dem
213    Aufruf weiter ohne auf das Laden und Füllen der Vorlage zu warten.
214    Das fertige HTML wird der Callback-Funktion übergeben
215    sobald die Vorlage geladen und gefüllt ist, unabhängig davon, wo der
216    Programmlauf zu diesem Zeitpunkt mittlerweile ist.
217    
218    vurl - URL zur Vorlagendatei
219    inhalt - die JSON-Struktur, deren Inhalt in die
220    Vorlage gefüllt werden soll
221    cb - Callback-Funktion, die gerufen wird, wenn die Vorlage gefüllt ist.
222    Dieser Callback-Funktion wird das fertige HTML übergeben
223    */
224   this.html_erzeugen = function (vurl, inhalt, cb) {
225     var vorlage = self.cache[vurl];
226     if (vorlage === undefined) {
227       self.vorlage_laden_und_fuellen(vurl, inhalt, cb);
228     } else {
229       self.vorlage_fuellen(vurl, inhalt, cb);
230     }
231   };
232
233   this.vorlage_fuellen = function (vurl, inhalt, cb) {
234     cb(Mustache.render(self.cache[vurl], inhalt));
235   };
236
237   /*
238    Eine Vorlage vom Server in den lokalen Speicher laden
239    vurl - der URL unter dem die Vorlage zu finden ist
240    inhalt - die JSON-Struktur, deren Inhalt in die
241    Vorlage gefüllt werden soll
242    cb - callback: Diese Funktion wird gerufen, wenn die Vorlage mit dem
243    Inhalt gefüllt ist
244    */
245   this.vorlage_laden_und_fuellen = function (vurl, inhalt, cb) {
246     var xmlhttp = new XMLHttpRequest();
247     xmlhttp.onreadystatechange = function () {
248       if (this.readyState == 4 && this.status == 200) {
249         self.cache[vurl] = this.responseText;
250         self.vorlage_fuellen(vurl, inhalt, cb);
251       }
252     };
253     xmlhttp.open("GET", vurl, true);
254     xmlhttp.send();
255   };
256
257
258
259 }
260