Sammlung
This commit is contained in:
3
Sammlung/Praktikum/4/app/__init__.py
Normal file
3
Sammlung/Praktikum/4/app/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
# coding: utf-8
|
||||
|
||||
# hier können Paket-Initialisierungen eingetragen werden
|
BIN
Sammlung/Praktikum/4/app/__pycache__/__init__.cpython-34.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/__init__.cpython-34.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/__init__.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/__init__.cpython-35.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/application.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/application.cpython-35.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/database.cpython-34.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/database.cpython-34.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/database.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/database.cpython-35.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/discussion.cpython-34.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/discussion.cpython-34.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/discussion.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/discussion.cpython-35.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/login.cpython-34.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/login.cpython-34.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/login.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/login.cpython-35.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/mytime.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/mytime.cpython-35.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/post.cpython-34.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/post.cpython-34.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/post.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/post.cpython-35.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/template.cpython-34.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/template.cpython-34.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/template.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/template.cpython-35.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/topic.cpython-34.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/topic.cpython-34.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/topic.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/topic.cpython-35.pyc
Normal file
Binary file not shown.
BIN
Sammlung/Praktikum/4/app/__pycache__/view.cpython-35.pyc
Normal file
BIN
Sammlung/Praktikum/4/app/__pycache__/view.cpython-35.pyc
Normal file
Binary file not shown.
25
Sammlung/Praktikum/4/app/application.py
Normal file
25
Sammlung/Praktikum/4/app/application.py
Normal file
@ -0,0 +1,25 @@
|
||||
# coding: utf-8
|
||||
|
||||
import cherrypy
|
||||
|
||||
#----------------------------------------------------------
|
||||
class Application_cl(object):
|
||||
#----------------------------------------------------------
|
||||
|
||||
exposed = True # gilt für alle Methoden
|
||||
|
||||
#-------------------------------------------------------
|
||||
def __init__(self):
|
||||
#-------------------------------------------------------
|
||||
pass
|
||||
|
||||
#-------------------------------------------------------
|
||||
def default(self, *arguments, **kwargs):
|
||||
#-------------------------------------------------------
|
||||
msg_s = "unbekannte Anforderung: " + \
|
||||
str(arguments) + \
|
||||
' ' + \
|
||||
str(kwargs)
|
||||
raise cherrypy.HTTPError(404, msg_s)
|
||||
|
||||
# EOF
|
340
Sammlung/Praktikum/4/app/database.py
Normal file
340
Sammlung/Praktikum/4/app/database.py
Normal file
@ -0,0 +1,340 @@
|
||||
# coding: utf-8
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import codecs
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
class Database_cl(object):
|
||||
#----------------------------------------------------------
|
||||
|
||||
# alle Elemente werden zur Laufzeit des Servers zur Vereinfachung auch im
|
||||
# Hauptspeicher abgelegt
|
||||
|
||||
# die nächste zu vergebende Id wird ebenfalls dauerhaft gespeichert
|
||||
|
||||
# zur Vereinfachung wird hier fest vorgegebenen, dass sich die Daten
|
||||
# im Unterverzeichnis "data" befinden
|
||||
|
||||
#-------------------------------------------------------
|
||||
def __init__(self):
|
||||
#-------------------------------------------------------
|
||||
self.data_o = {}
|
||||
self.readData_p()
|
||||
|
||||
#-------------------------------------------------------
|
||||
def createTopic_px(self, data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Überprüfung der Daten müsste ergänzt werden!
|
||||
id_ = self.nextTopicId_p()
|
||||
self.data_o['topics'][str(id_)] = data_opl
|
||||
|
||||
file_o = codecs.open(os.path.join('data', 'topics.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['topics']))
|
||||
file_o.close()
|
||||
|
||||
return id_
|
||||
|
||||
#-------------------------------------------------------
|
||||
def createDiscussion_px(self, tId, data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Überprüfung der Daten müsste ergänzt werden!
|
||||
id_ = self.nextDiscussionId_p()
|
||||
self.data_o['discussions'][id_] = data_opl
|
||||
self.data_o['topics'][tId]['discs'].append(id_)
|
||||
|
||||
file_o = codecs.open(os.path.join('data', 'discussions.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['discussions']))
|
||||
file_o.close()
|
||||
|
||||
file_o = codecs.open(os.path.join('data', 'topics.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['topics']))
|
||||
file_o.close()
|
||||
|
||||
return id_
|
||||
|
||||
#-------------------------------------------------------
|
||||
def createPost_px(self, dId, data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Überprüfung der Daten müsste ergänzt werden!
|
||||
|
||||
id_ = self.nextPostId_p()
|
||||
self.data_o['posts'][id_] = data_opl
|
||||
self.data_o['discussions'][dId]['posts'].append(id_)
|
||||
|
||||
file_o = codecs.open(os.path.join('data', 'posts.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['posts']))
|
||||
file_o.close()
|
||||
|
||||
file_o = codecs.open(os.path.join('data', 'discussions.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['discussions']))
|
||||
file_o.close()
|
||||
|
||||
return id_
|
||||
|
||||
|
||||
#-------------------------------------------------------
|
||||
def readTopic_px(self, id_ = None):
|
||||
#-------------------------------------------------------
|
||||
# hier zur Vereinfachung:
|
||||
# Aufruf ohne id: alle Einträge liefern
|
||||
data_o = None
|
||||
if id_ == None:
|
||||
data_o = self.data_o['topics']
|
||||
elif str(id_) == '0':
|
||||
data_o = self.getDefaultTopic_px()
|
||||
else:
|
||||
if str(id_) in self.data_o['topics']:
|
||||
data_o = self.data_o['topics'][str(id_)]
|
||||
|
||||
return data_o
|
||||
|
||||
#-------------------------------------------------------
|
||||
def readDiscussion_px(self, tId, dId = None):
|
||||
#-------------------------------------------------------
|
||||
# hier zur Vereinfachung:
|
||||
# Aufruf ohne id: alle Einträge liefern
|
||||
data_o = None
|
||||
if dId == None:
|
||||
data_o = {}
|
||||
discs = self.data_o['discussions']
|
||||
indices = self.data_o['topics'][str(tId)]['discs']
|
||||
for index in indices:
|
||||
data_o[index] = discs[index]
|
||||
elif str(dId) == '0':
|
||||
data_o = self.getDefaultDiscussion_px()
|
||||
else:
|
||||
if str(dId) in self.data_o['discussions']:
|
||||
data_o = self.data_o['discussions'][str(dId)]
|
||||
|
||||
return data_o
|
||||
|
||||
#-------------------------------------------------------
|
||||
def readPost_px(self, dId, pId = None):
|
||||
#-------------------------------------------------------
|
||||
# hier zur Vereinfachung:
|
||||
# Aufruf ohne id: alle Einträge liefern
|
||||
data_o = None
|
||||
if pId == None:
|
||||
data_o = {}
|
||||
posts = self.data_o['posts']
|
||||
indices = self.data_o['discussions'][str(dId)]['posts']
|
||||
for index in indices:
|
||||
data_o[index] = posts[index]
|
||||
elif str(pId) == '0':
|
||||
data_o = self.getDefaultPost_px()
|
||||
else:
|
||||
if str(pId) in self.data_o['posts']:
|
||||
data_o = self.data_o['posts'][str(pId)]
|
||||
|
||||
return data_o
|
||||
|
||||
#-------------------------------------------------------
|
||||
def updateTopic_px(self, id_, data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Überprüfung der Daten müsste ergänzt werden!
|
||||
updated = False
|
||||
if id_ in self.data_o['topics']:
|
||||
for key in data_opl:
|
||||
self.data_o['topics'][id_][key] = data_opl[key]
|
||||
|
||||
# Datei aktualisieren
|
||||
file_o = codecs.open(os.path.join('data', 'topics.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['topics']))
|
||||
file_o.close()
|
||||
|
||||
updated = True
|
||||
|
||||
return updated
|
||||
|
||||
#-------------------------------------------------------
|
||||
def updateDiscussion_px(self, id_, data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Überprüfung der Daten müsste ergänzt werden!
|
||||
updated = False
|
||||
if id_ in self.data_o['discussions']:
|
||||
for key in data_opl:
|
||||
self.data_o['discussions'][id_][key] = data_opl[key]
|
||||
|
||||
# Datei aktualisieren
|
||||
file_o = codecs.open(os.path.join('data', 'discussions.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['discussions']))
|
||||
file_o.close()
|
||||
|
||||
updated = True
|
||||
|
||||
return updated
|
||||
|
||||
#-------------------------------------------------------
|
||||
def updatePost_px(self, id_, data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Überprüfung der Daten müsste ergänzt werden!
|
||||
updated = False
|
||||
if id_ in self.data_o['posts']:
|
||||
for key in data_opl:
|
||||
self.data_o['posts'][id_][key] = data_opl[key]
|
||||
|
||||
# Datei aktualisieren
|
||||
file_o = codecs.open(os.path.join('data', 'posts.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['posts']))
|
||||
file_o.close()
|
||||
|
||||
updated = True
|
||||
|
||||
return updated
|
||||
|
||||
#-------------------------------------------------------
|
||||
def deleteTopic_px(self, id_):
|
||||
#-------------------------------------------------------
|
||||
deleted = False
|
||||
if id_ in self.data_o['topics']:
|
||||
self.data_o['topics'][id_]['deleted'] = True
|
||||
for key in self.data_o['topics'][id_]['discs']:
|
||||
del self.data_o['discussions'][key]
|
||||
self.data_o['topics'][id_]['discs'] = []
|
||||
|
||||
# Dateien aktualisieren
|
||||
file_o = codecs.open(os.path.join('data', 'topics.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['topics']))
|
||||
file_o.close()
|
||||
|
||||
file_o = codecs.open(os.path.join('data', 'discussions.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['discussions']))
|
||||
file_o.close()
|
||||
|
||||
deleted = True
|
||||
|
||||
return deleted
|
||||
|
||||
#-------------------------------------------------------
|
||||
def deleteDiscussion_px(self, id_):
|
||||
#-------------------------------------------------------
|
||||
deleted = False
|
||||
if id_ in self.data_o['discussions']:
|
||||
self.data_o['discussions'][id_]['deleted'] = True
|
||||
for key in self.data_o['discussions'][id_]['posts']:
|
||||
del self.data_o['posts'][key]
|
||||
self.data_o['discussions'][id_]['posts'] = []
|
||||
|
||||
# Dateien aktualisieren
|
||||
file_o = codecs.open(os.path.join('data', 'discussions.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['discussions']))
|
||||
file_o.close()
|
||||
|
||||
file_o = codecs.open(os.path.join('data', 'posts.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['posts']))
|
||||
file_o.close()
|
||||
|
||||
deleted = True
|
||||
|
||||
return deleted
|
||||
|
||||
#-------------------------------------------------------
|
||||
def deletePost_px(self, id_):
|
||||
#-------------------------------------------------------
|
||||
deleted = False
|
||||
if id_ in self.data_o['posts']:
|
||||
self.data_o['posts'][id_]['deleted'] = True
|
||||
|
||||
# Datei aktualisieren
|
||||
file_o = codecs.open(os.path.join('data', 'posts.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['posts']))
|
||||
file_o.close()
|
||||
|
||||
deleted = True
|
||||
|
||||
return deleted
|
||||
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getDefaultTopic_px(self):
|
||||
#-------------------------------------------------------
|
||||
|
||||
return {
|
||||
'name' : '',
|
||||
'owner': '',
|
||||
'deleted': False,
|
||||
'discs': []
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getDefaultDiscussion_px(self):
|
||||
#-------------------------------------------------------
|
||||
|
||||
return {
|
||||
'name' : '',
|
||||
'owner': '',
|
||||
'deleted': False,
|
||||
'posts': []
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getDefaultPost_px(self):
|
||||
#-------------------------------------------------------
|
||||
return {
|
||||
'title' : '',
|
||||
'text' : '',
|
||||
'owner': '',
|
||||
'time': time.localtime(),
|
||||
'deleted': False,
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getUsers_px(self):
|
||||
#-------------------------------------------------------
|
||||
|
||||
return self.data_o['users']
|
||||
|
||||
#-------------------------------------------------------
|
||||
def saveUsers_px(self, data_o):
|
||||
#-------------------------------------------------------
|
||||
file_o = codecs.open(os.path.join('data', 'users.dat'), 'w', 'utf-8')
|
||||
file_o.write(json.dumps(self.data_o['users']))
|
||||
file_o.close()
|
||||
|
||||
#-------------------------------------------------------
|
||||
def readData_p(self):
|
||||
#-------------------------------------------------------
|
||||
|
||||
files_a = os.listdir('data')
|
||||
for fileName_s in files_a:
|
||||
if fileName_s.endswith('.dat'):
|
||||
file_o = codecs.open(os.path.join('data', fileName_s), 'rU', 'utf-8')
|
||||
content_s = file_o.read()
|
||||
file_o.close()
|
||||
id_s = fileName_s[:-4]
|
||||
self.data_o[id_s] = json.loads(content_s)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def nextTopicId_p(self):
|
||||
#-------------------------------------------------------
|
||||
id_ = str(self.data_o['topics']['nextID'])
|
||||
nextID = int(self.data_o['topics']['nextID'])
|
||||
self.data_o['topics']['nextID'] = str(nextID + 1)
|
||||
|
||||
return id_
|
||||
|
||||
#-------------------------------------------------------
|
||||
def nextDiscussionId_p(self):
|
||||
#-------------------------------------------------------
|
||||
id_ = str(self.data_o['discussions']['nextID'])
|
||||
nextID = int(self.data_o['discussions']['nextID'])
|
||||
self.data_o['discussions']['nextID'] = str(nextID + 1)
|
||||
|
||||
return id_
|
||||
|
||||
#-------------------------------------------------------
|
||||
def nextPostId_p(self):
|
||||
#-------------------------------------------------------
|
||||
id_ = str(self.data_o['posts']['nextID'])
|
||||
nextID = int(self.data_o['posts']['nextID'])
|
||||
self.data_o['posts']['nextID'] = str(nextID + 1)
|
||||
|
||||
return id_
|
||||
|
||||
db_o = Database_cl()
|
||||
# EOF
|
120
Sammlung/Praktikum/4/app/discussion.py
Normal file
120
Sammlung/Praktikum/4/app/discussion.py
Normal file
@ -0,0 +1,120 @@
|
||||
# coding: utf-8
|
||||
|
||||
import json
|
||||
|
||||
import cherrypy
|
||||
|
||||
from app import database
|
||||
|
||||
# Method-Dispatching!
|
||||
|
||||
# Übersicht Anforderungen / Methoden
|
||||
# (beachte: / relativ zu /discussion, siehe Konfiguration Server!)
|
||||
|
||||
"""
|
||||
|
||||
Anforderung GET PUT POST DELETE
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/diskussion/{thema-id} alle disk. neue Diskussion - -
|
||||
zum Thema zum Thema speichern
|
||||
ausgeben diskussion-id zurück
|
||||
|
||||
/diskussion/{diskussion-id} eine - Diskussion mit ID Diskussion mit ID
|
||||
Diskussion ändern löschen
|
||||
anfordern
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
#----------------------------------------------------------
|
||||
class Discussion_cl(object):
|
||||
#----------------------------------------------------------
|
||||
|
||||
exposed = True # gilt für alle Methoden
|
||||
|
||||
#-------------------------------------------------------
|
||||
def __init__(self):
|
||||
#-------------------------------------------------------
|
||||
# spezielle Initialisierung können hier eingetragen werden
|
||||
self.db_o = database.db_o
|
||||
|
||||
#-------------------------------------------------------
|
||||
def GET(self, tId, dId = None):
|
||||
#-------------------------------------------------------
|
||||
retVal_o = {'data': None, 'id': None, 'tId': tId}
|
||||
|
||||
if dId == None:
|
||||
# Anforderung der Liste
|
||||
retVal_o['data'] = self.getList_p(tId)
|
||||
else:
|
||||
# Anforderung eines Dokuments
|
||||
retVal_o['data'] = self.getDiscussion(tId, dId)
|
||||
retVal_o['id'] = dId
|
||||
|
||||
if retVal_o['data'] == None:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def POST(self, tId, id_, **data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Sichern der Daten: jetzt wird keine vollständige Seite
|
||||
# zurückgeliefert, sondern nur noch die Information, ob das
|
||||
# Speichern erfolgreich war
|
||||
|
||||
retVal_o = {
|
||||
'id': None
|
||||
}
|
||||
|
||||
# data_opl: Dictionary mit den gelieferten key-value-Paaren
|
||||
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
|
||||
id_ = str(id_)
|
||||
data_o = self.db_o.data_o['discussions'][id_]
|
||||
data_o['name'] = data_opl['name']
|
||||
|
||||
# Update-Operation
|
||||
retVal_o['id'] = id_
|
||||
if self.db_o.updateDiscussion_px(id_, data_o):
|
||||
pass
|
||||
else:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def DELETE(self, id_):
|
||||
#-------------------------------------------------------
|
||||
# Eintrag löschen, nur noch Rückmeldung liefern
|
||||
retVal_o = {
|
||||
'id': id_
|
||||
}
|
||||
|
||||
if self.db_o.deleteDiscussion_px(id_):
|
||||
pass
|
||||
else:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getList_p(self, tId):
|
||||
#-------------------------------------------------------
|
||||
data_o = self.db_o.readDiscussion_px(tId)
|
||||
|
||||
return data_o
|
||||
getList_p.exposed = False;
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getDiscussion(self, tId, dId):
|
||||
#-------------------------------------------------------
|
||||
data_o = self.db_o.readDiscussion_px(tId, dId)
|
||||
|
||||
return data_o
|
||||
getDiscussion.exposed = False;
|
||||
|
||||
# EOF
|
54
Sammlung/Praktikum/4/app/login.py
Normal file
54
Sammlung/Praktikum/4/app/login.py
Normal file
@ -0,0 +1,54 @@
|
||||
# coding: utf-8
|
||||
|
||||
import json
|
||||
|
||||
import os
|
||||
import codecs
|
||||
|
||||
import cherrypy
|
||||
|
||||
from app import database
|
||||
# Method-Dispatching!
|
||||
|
||||
# (beachte: / relativ zu /login, siehe Konfiguration Server!)
|
||||
|
||||
#----------------------------------------------------------
|
||||
class Login_cl(object):
|
||||
#----------------------------------------------------------
|
||||
|
||||
exposed = True # gilt für alle Methoden
|
||||
|
||||
#-------------------------------------------------------
|
||||
def __init__(self):
|
||||
#-------------------------------------------------------
|
||||
self.db_o = database.Database_cl()
|
||||
|
||||
|
||||
|
||||
#**********************REST ANSATZ**********************
|
||||
#-------------------------------------------------------
|
||||
def GET(self, **data_o):
|
||||
#-------------------------------------------------------
|
||||
authenticated = False
|
||||
|
||||
users = self.db_o.getUsers_px();
|
||||
if data_o['username'] in users and data_o['password'] == users[data_o['username']]:
|
||||
authenticated = True
|
||||
|
||||
return json.dumps(authenticated)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def PUT(self, **data_o):
|
||||
#-------------------------------------------------------
|
||||
success = False
|
||||
|
||||
users = self.db_o.getUsers_px();
|
||||
if data_o['username'] not in users:
|
||||
users[data_o['username']] = data_o['password']
|
||||
self.db_o.saveUsers_px(users);
|
||||
success = True
|
||||
|
||||
return json.dumps(success)
|
||||
#*******************************************************
|
||||
|
||||
# EOF
|
46
Sammlung/Praktikum/4/app/mytime.py
Normal file
46
Sammlung/Praktikum/4/app/mytime.py
Normal file
@ -0,0 +1,46 @@
|
||||
# coding: utf-8
|
||||
|
||||
import json
|
||||
|
||||
import os
|
||||
import codecs
|
||||
|
||||
import cherrypy
|
||||
import time
|
||||
|
||||
from app import database
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
class Time_cl(object):
|
||||
#----------------------------------------------------------
|
||||
exposed=True
|
||||
#----------------------------------------------------------
|
||||
def __init__(self):
|
||||
#----------------------------------------------------------
|
||||
t = time.localtime()
|
||||
self.date_o = {
|
||||
"day":"",
|
||||
"month":"",
|
||||
"year":"",
|
||||
"hour":"",
|
||||
"minute":""
|
||||
}
|
||||
self.date_o['day'] = t[2]
|
||||
self.date_o['month']=t[1]
|
||||
self.date_o['year']=t[0]
|
||||
self.date_o['hour']=t[3]
|
||||
self.date_o['minute']=t[4]
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
def getDateAsString_px(self):
|
||||
#----------------------------------------------------------
|
||||
return str(self.date_o['hour'])+':'+str(self.date_o['minute'])+' | '+str(self.date_o['day'])+'.'+str(self.date_o['month'])+'.'+str(self.date_o['year'] )
|
||||
|
||||
#----------------------------------------------------------
|
||||
def getDate_px(self):
|
||||
#----------------------------------------------------------
|
||||
return self.date_o
|
||||
|
||||
# EOF
|
150
Sammlung/Praktikum/4/app/post.py
Normal file
150
Sammlung/Praktikum/4/app/post.py
Normal file
@ -0,0 +1,150 @@
|
||||
# coding: utf-8
|
||||
|
||||
import json
|
||||
import datetime
|
||||
import time
|
||||
|
||||
import cherrypy
|
||||
|
||||
from app import database
|
||||
|
||||
# Method-Dispatching!
|
||||
|
||||
# Übersicht Anforderungen / Methoden
|
||||
# (beachte: / relativ zu /discussion, siehe Konfiguration Server!)
|
||||
|
||||
"""
|
||||
|
||||
Anforderung GET PUT POST DELETE
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
||||
/beitrag/{diskussion-id} alle Beiträge neuen Beitrag - -
|
||||
zur Diskussion zur Diskussion speichern
|
||||
anfordern beitrag-id zurück
|
||||
|
||||
/beitrag/{beitrag-id} einen Beitrag - Beitrag mit ID Beitrag mit ID
|
||||
anfordern ändern löschen
|
||||
|
||||
"""
|
||||
|
||||
#----------------------------------------------------------
|
||||
class Post_cl(object):
|
||||
#----------------------------------------------------------
|
||||
|
||||
exposed = True # gilt für alle Methoden
|
||||
|
||||
#-------------------------------------------------------
|
||||
def __init__(self):
|
||||
#-------------------------------------------------------
|
||||
# spezielle Initialisierung können hier eingetragen werden
|
||||
self.db_o = database.db_o
|
||||
|
||||
#-------------------------------------------------------
|
||||
def GET(self, tId, dId, pId = None):
|
||||
#-------------------------------------------------------
|
||||
retVal_o = {'data': None, 'id': pId, 'tId':tId, 'dId': dId}
|
||||
|
||||
if dId == None:
|
||||
# Anforderung der Liste
|
||||
retVal_o['data'] = self.getList_p(dId)
|
||||
else:
|
||||
# Anforderung eines Dokuments
|
||||
retVal_o['data'] = self.getPost(dId, pId)
|
||||
|
||||
if retVal_o['data'] == None:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def PUT(self, tId, dId, **data_opl):
|
||||
#-------------------------------------------------------
|
||||
retVal_o = {
|
||||
'id': None,
|
||||
'dId': dId
|
||||
}
|
||||
|
||||
# data_opl: Dictionary mit den gelieferten key-value-Paaren
|
||||
if dId == 0 or dId == "0":
|
||||
discData_o = self.db_o.getDefaultDiscussion_px()
|
||||
discData_o['name'] = data_opl['title']
|
||||
discData_o['owner'] = data_opl['owner']
|
||||
dId = self.db_o.createDiscussion_px(tId, discData_o)
|
||||
retVal_o['dId'] = dId
|
||||
|
||||
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
|
||||
data_o = self.db_o.getDefaultPost_px()
|
||||
data_o['title'] = data_opl['title']
|
||||
data_o['text'] = data_opl['text']
|
||||
data_o['owner'] = data_opl['owner']
|
||||
|
||||
# Create-Operation
|
||||
id_s = self.db_o.createPost_px(dId, data_o)
|
||||
retVal_o['id'] = id_s
|
||||
if retVal_o['id'] == None:
|
||||
cherrypy.response.status = 409
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def POST(self, tId, dId, id_, **data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Sichern der Daten: jetzt wird keine vollständige Seite
|
||||
# zurückgeliefert, sondern nur noch die Information, ob das
|
||||
# Speichern erfolgreich war
|
||||
|
||||
retVal_o = {
|
||||
'id': None,
|
||||
'tId': tId,
|
||||
'dId': dId
|
||||
}
|
||||
|
||||
# data_opl: Dictionary mit den gelieferten key-value-Paaren
|
||||
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
|
||||
id_ = str(id_)
|
||||
data_o = self.db_o.data_o['posts'][id_]
|
||||
data_o['text'] = data_opl['text']
|
||||
data_o['title'] = data_opl['title']
|
||||
|
||||
# Update-Operation
|
||||
retVal_o['id'] = id_
|
||||
if self.db_o.updatePost_px(id_, data_o):
|
||||
pass
|
||||
else:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def DELETE(self, id_):
|
||||
#-------------------------------------------------------
|
||||
# Eintrag löschen, nur noch Rückmeldung liefern
|
||||
retVal_o = {
|
||||
'id': id_
|
||||
}
|
||||
|
||||
if self.db_o.deletePost_px(id_):
|
||||
pass
|
||||
else:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getList_p(self, tId):
|
||||
#-------------------------------------------------------
|
||||
data_o = self.db_o.readPost_px(tId)
|
||||
|
||||
return data_o
|
||||
getList_p.exposed = False;
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getPost(self, tId, dId):
|
||||
#-------------------------------------------------------
|
||||
data_o = self.db_o.readPost_px(tId, dId)
|
||||
|
||||
return data_o
|
||||
getPost.exposed = False;
|
||||
|
||||
# EOF
|
52
Sammlung/Praktikum/4/app/template.py
Normal file
52
Sammlung/Praktikum/4/app/template.py
Normal file
@ -0,0 +1,52 @@
|
||||
# coding: utf-8
|
||||
|
||||
import json
|
||||
|
||||
import os
|
||||
import codecs
|
||||
|
||||
import cherrypy
|
||||
|
||||
# Method-Dispatching!
|
||||
|
||||
# Übersicht Anforderungen / Methoden
|
||||
# (beachte: / relativ zu /template, siehe Konfiguration Server!)
|
||||
|
||||
"""
|
||||
|
||||
Anforderung GET PUT POST DELETE
|
||||
----------------------------------------------------------------
|
||||
/ Alle - - -
|
||||
Templates
|
||||
liefern
|
||||
|
||||
"""
|
||||
|
||||
#----------------------------------------------------------
|
||||
class Template_cl(object):
|
||||
#----------------------------------------------------------
|
||||
|
||||
exposed = True # gilt für alle Methoden
|
||||
|
||||
#-------------------------------------------------------
|
||||
def __init__(self):
|
||||
#-------------------------------------------------------
|
||||
pass
|
||||
|
||||
#-------------------------------------------------------
|
||||
def GET(self):
|
||||
#-------------------------------------------------------
|
||||
retVal_o = {
|
||||
'templates': {}
|
||||
}
|
||||
|
||||
files_a = os.listdir('templates')
|
||||
for fileName_s in files_a:
|
||||
file_o = codecs.open(os.path.join('templates', fileName_s), 'rU', 'utf-8')
|
||||
content_s = file_o.read()
|
||||
file_o.close()
|
||||
retVal_o["templates"][fileName_s] = content_s
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
# EOF
|
149
Sammlung/Praktikum/4/app/topic.py
Normal file
149
Sammlung/Praktikum/4/app/topic.py
Normal file
@ -0,0 +1,149 @@
|
||||
# coding: utf-8
|
||||
|
||||
import json
|
||||
|
||||
import cherrypy
|
||||
|
||||
from app import database
|
||||
|
||||
# Method-Dispatching!
|
||||
|
||||
# Übersicht Anforderungen / Methoden
|
||||
# (beachte: / relativ zu /topic, siehe Konfiguration Server!)
|
||||
|
||||
"""
|
||||
|
||||
Anforderung GET PUT POST DELETE
|
||||
----------------------------------------------------------------
|
||||
/ Liste - - -
|
||||
Themen
|
||||
liefern
|
||||
|
||||
/0 Thema Thema - -
|
||||
mit id=0 anlegen
|
||||
liefern
|
||||
(Vorgabe-Werte)
|
||||
|
||||
/{id} Thema - Thema Thema
|
||||
mit {id} ändern löschen
|
||||
liefern
|
||||
|
||||
id > 0 !
|
||||
|
||||
"""
|
||||
|
||||
#----------------------------------------------------------
|
||||
class Topic_cl(object):
|
||||
#----------------------------------------------------------
|
||||
|
||||
exposed = True # gilt für alle Methoden
|
||||
|
||||
#-------------------------------------------------------
|
||||
def __init__(self):
|
||||
#-------------------------------------------------------
|
||||
# spezielle Initialisierung können hier eingetragen werden
|
||||
self.db_o = database.db_o
|
||||
|
||||
#-------------------------------------------------------
|
||||
def GET(self, id_ = None):
|
||||
#-------------------------------------------------------
|
||||
retVal_o = {'data': None, 'id': None}
|
||||
|
||||
if id == None:
|
||||
# Anforderung der Liste
|
||||
retVal_o['data'] = self.getList_p()
|
||||
else:
|
||||
# Anforderung eines Dokuments
|
||||
retVal_o['data'] = self.getTopic(id_)
|
||||
retVal_o['id'] = id_
|
||||
|
||||
if retVal_o['data'] == None:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def PUT(self, **data_opl):
|
||||
#-------------------------------------------------------
|
||||
retVal_o = {
|
||||
'id': None
|
||||
}
|
||||
|
||||
# data_opl: Dictionary mit den gelieferten key-value-Paaren
|
||||
|
||||
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
|
||||
|
||||
print(data_opl)
|
||||
data_o = {
|
||||
'name' : data_opl['name'],
|
||||
'owner': data_opl['owner'],
|
||||
'deleted': False,
|
||||
'discs': []
|
||||
}
|
||||
|
||||
# Create-Operation
|
||||
id_s = self.db_o.createTopic_px(data_o)
|
||||
retVal_o['id'] = id_s
|
||||
if retVal_o['id'] == None:
|
||||
cherrypy.response.status = 409
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def POST(self, id_, **data_opl):
|
||||
#-------------------------------------------------------
|
||||
# Sichern der Daten: jetzt wird keine vollständige Seite
|
||||
# zurückgeliefert, sondern nur noch die Information, ob das
|
||||
# Speichern erfolgreich war
|
||||
|
||||
retVal_o = {
|
||||
'id': None
|
||||
}
|
||||
|
||||
# data_opl: Dictionary mit den gelieferten key-value-Paaren
|
||||
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
|
||||
id_ = str(id_)
|
||||
data_o = self.db_o.data_o['topics'][id_]
|
||||
data_o['name'] = data_opl['name']
|
||||
|
||||
# Update-Operation
|
||||
retVal_o['id'] = id_
|
||||
if self.db_o.updateTopic_px(id_, data_o):
|
||||
pass
|
||||
else:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def DELETE(self, id_):
|
||||
#-------------------------------------------------------
|
||||
# Eintrag löschen, nur noch Rückmeldung liefern
|
||||
retVal_o = {
|
||||
'id': id_
|
||||
}
|
||||
|
||||
if self.db_o.deleteTopic_px(id_):
|
||||
pass
|
||||
else:
|
||||
cherrypy.response.status = 404
|
||||
|
||||
return json.dumps(retVal_o)
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getList_p(self):
|
||||
#-------------------------------------------------------
|
||||
data_o = self.db_o.readTopic_px()
|
||||
|
||||
return data_o
|
||||
getList_p.exposed = False;
|
||||
|
||||
#-------------------------------------------------------
|
||||
def getTopic(self, id_spl):
|
||||
#-------------------------------------------------------
|
||||
data_o = self.db_o.readTopic_px(id_spl)
|
||||
|
||||
return data_o
|
||||
getTopic.exposed = False;
|
||||
|
||||
# EOF
|
287
Sammlung/Praktikum/4/css/main.css
Normal file
287
Sammlung/Praktikum/4/css/main.css
Normal file
@ -0,0 +1,287 @@
|
||||
/* main.css */
|
||||
|
||||
/* allgemeine Vorgaben */
|
||||
body {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-size: 12pt;
|
||||
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Basislayout */
|
||||
|
||||
.clSiteHeader {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
font-size: 12pt;
|
||||
color: #efc9a0;
|
||||
background-color: #40200d;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.clLoggedInText {
|
||||
position: absolute;
|
||||
right: 50px;
|
||||
height: 80px;
|
||||
line-height: 48px;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
font-size: 12pt;
|
||||
color: #efc9a0;
|
||||
background-color: #40200d;
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.clNav {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 150px;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
|
||||
}
|
||||
|
||||
.clNav a, a:hover, a:visited, a:active{
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.clNav a:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.clContentOuter {
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.clContent {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
background-color: #efc9a0;
|
||||
}
|
||||
|
||||
/* Elemente im Content-Bereich */
|
||||
|
||||
.clContentHeader {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
font-size: 14pt;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.clContentArea {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 40px;
|
||||
margin: 0;
|
||||
padding: 0px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.clSelected{
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.clButtonArea {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
background-color: #40200d;
|
||||
|
||||
}
|
||||
|
||||
/* Links und Submit-Schalter im Buttonbereich gestalten */
|
||||
|
||||
.clButtonArea button, a, input[type="submit"] {
|
||||
margin: 0 5px;
|
||||
padding: 3px 6px;
|
||||
font-size: 10pt;
|
||||
text-decoration: none;
|
||||
border: 1px solid;
|
||||
color: black;
|
||||
background-color: #efc9a0;
|
||||
}
|
||||
|
||||
.clButtonArea button:disabled {
|
||||
color: graytext;
|
||||
}
|
||||
|
||||
|
||||
.clButtonArea button:enabled {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Gestaltung von Tabellen */
|
||||
|
||||
#idTopicList, #idDiscussionList {
|
||||
table-layout: fixed;
|
||||
width: 66%;
|
||||
border: 1px solid;
|
||||
border-collapse: collapse;
|
||||
margin:auto;
|
||||
|
||||
}
|
||||
|
||||
#idTopicList th, #idDiscussionList th {
|
||||
text-align: left;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
#idTopicList th, #idTopicList td, #idDiscussionList th, #idDiscussionList td{
|
||||
padding: 3px;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
#idPostList {
|
||||
width: 80%;
|
||||
border: 1px solid;
|
||||
border-collapse: collapse;
|
||||
margin:auto;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.listheader th{
|
||||
color:#efc9a0;
|
||||
background-color:#40200d;
|
||||
}
|
||||
|
||||
#idTopicList tr, #idDiscussionList tr{
|
||||
background-color:#F4C484
|
||||
}
|
||||
|
||||
#idTopicList tr:nth-of-type(even), #idDiscussionList tr:nth-of-type(even){
|
||||
background-color:#E4A454;
|
||||
}
|
||||
|
||||
|
||||
/* Gestaltung von Formularen */
|
||||
|
||||
/* das Formular nochmals zusätzlich gestalten */
|
||||
#idForm .clContentArea {
|
||||
width: 500px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.clFormRow {
|
||||
position: relative; /* damit das Element in jedem Fall "positioniert" ist und damit als Bezugspunkt geeignet ist */
|
||||
height: 25px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.clFormRow label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 150px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.clFormRow input, .clFormRow textarea {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 160px;
|
||||
width: 250px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************STYLES für einzelne Posts der Postliste*/
|
||||
#idPostList li {
|
||||
border: 1px solid;
|
||||
border-collapse: collapse;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
list-style-type: none;
|
||||
|
||||
}
|
||||
|
||||
.clMetaDataContainer {
|
||||
width: 15%;
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
left: 0;
|
||||
right: 80%;
|
||||
color: #efc9a0;
|
||||
background-color: #40200D;
|
||||
}
|
||||
|
||||
.clPostContainer{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.clPostDataContainer{
|
||||
position: absolute;
|
||||
width: 85%;
|
||||
left: 15%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#idPostList .clOwner {
|
||||
margin: 0px;
|
||||
|
||||
}
|
||||
#idPostList .clTime {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#idPostList .clTitle {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #efc9a0;
|
||||
background-color: #40200d;
|
||||
}
|
||||
|
||||
#idPostList .clText {
|
||||
margin: 0;
|
||||
margin-left: 3px;
|
||||
bottom: 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* EOF */
|
1
Sammlung/Praktikum/4/data/discussions.dat
Normal file
1
Sammlung/Praktikum/4/data/discussions.dat
Normal file
@ -0,0 +1 @@
|
||||
{"8": {"name": "Hallo", "deleted": false, "posts": ["10"], "owner": "Florian"}, "nextID": "11", "10": {"name": "test 2", "deleted": false, "posts": ["13", "14"], "owner": ""}, "9": {"name": "TestDiskussion", "deleted": false, "posts": ["11", "12"], "owner": "Florian"}}
|
1
Sammlung/Praktikum/4/data/posts.dat
Normal file
1
Sammlung/Praktikum/4/data/posts.dat
Normal file
@ -0,0 +1 @@
|
||||
{"13": {"deleted": false, "text": "", "time": [2016, 4, 26, 16, 37, 48, 1, 117, 1], "title": "test 2", "owner": ""}, "8": {"deleted": false, "text": "Hallo zusammen! Meiner Meinung nach ist das v\u00f6lliger Schwachsinn. Wie seht ihr das?", "title": "Ist ein Single-Page-Ansatz sinnvoll f\u00fcr ein Forum", "time": [2016, 1, 14, 14, 14, 39, 3, 14, 0], "owner": "Florian"}, "4": {"deleted": false, "text": "asdasdasdasd", "title": "asdasd", "time": [2016, 1, 14, 14, 10, 57, 3, 14, 0], "owner": "Test"}, "7": {"deleted": false, "text": "aaa", "title": "Hallo Freunde", "time": [2016, 1, 14, 14, 11, 30, 3, 14, 0], "owner": "Test"}, "6": {"deleted": false, "text": "asdasdAasdas", "title": "12123", "time": [2016, 1, 14, 14, 11, 21, 3, 14, 0], "owner": "Test"}, "9": {"deleted": false, "text": "Ich sehe das \u00e4hnlich, au\u00dferdem ist Javascript h\u00e4sslich", "title": "Re: Ist ein Single-Page-Ansatz sinnvoll f\u00fcr ein Forum", "time": [2016, 1, 14, 14, 16, 4, 3, 14, 0], "owner": "Kai"}, "14": {"deleted": false, "text": "test", "time": [2016, 4, 26, 16, 37, 59, 1, 117, 1], "title": "test3", "owner": ""}, "11": {"deleted": false, "text": "Test", "title": "TestBeitrag", "time": [2016, 1, 14, 15, 24, 38, 3, 14, 0], "owner": "Florian"}, "nextID": "15", "10": {"deleted": false, "text": "Freunde", "title": "Hallo", "time": [2016, 1, 14, 15, 19, 17, 3, 14, 0], "owner": "Florian"}, "12": {"deleted": true, "text": "noch ei test", "title": "Beitrag2", "time": [2016, 1, 14, 15, 25, 35, 3, 14, 0], "owner": "Florian"}}
|
1
Sammlung/Praktikum/4/data/topics.dat
Normal file
1
Sammlung/Praktikum/4/data/topics.dat
Normal file
@ -0,0 +1 @@
|
||||
{"1": {"name": "Ich bin das erste Test-Thema", "discs": [], "deleted": true, "owner": "Test"}, "5": {"name": "test", "deleted": false, "discs": [], "owner": "test"}, "4": {"name": "TestThema", "discs": ["9"], "deleted": false, "owner": "Florian"}, "2": {"name": "Und ich das zweite!", "discs": ["8", "10"], "deleted": false, "owner": "Test"}, "nextID": "6", "3": {"name": "Web-Engineering", "discs": [], "deleted": true, "owner": "Florian"}}
|
1
Sammlung/Praktikum/4/data/users.dat
Normal file
1
Sammlung/Praktikum/4/data/users.dat
Normal file
@ -0,0 +1 @@
|
||||
{"Kai": "fucku", "Test": "test", "test": "test", "Florian": "123", "": ""}
|
129
Sammlung/Praktikum/4/doku/Dokumentation.html
Normal file
129
Sammlung/Praktikum/4/doku/Dokumentation.html
Normal file
@ -0,0 +1,129 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="pandoc">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<title></title>
|
||||
<style type="text/css">code{white-space: pre;}</style>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="dokumentation-praktikum-3">Dokumentation Praktikum 3</h1>
|
||||
<h2 id="einleitende-daten">Einleitende Daten</h2>
|
||||
<p>Gruppe: D Team: Florian Heinze Kai Rese</p>
|
||||
<p>Gültigkeitsdatum:<br />
|
||||
13.01.16</p>
|
||||
<h2 id="allgemeine-beschreibung-der-lösung">1.Allgemeine Beschreibung der Lösung</h2>
|
||||
<p>Die Aufgabe wird als Single-Page-Applikation umgesetzt. Serverseitig werden die Daten hierbei in einzelnen .dat Dateien gespeichert, deren Inhalt nach Json-Standard eingetragen ist.<br />
|
||||
Clientseitig werden html, CSS, Javascript, die Javascript-Bibliothek Jquery und Module vom Professor verwendet.</p>
|
||||
<p>Es können Themen mit einem Titel erstellt, bearbeitet und gelöscht werden.<br />
|
||||
Zu den Themen können Diskussionen erstellt, bearbeitet und gelöscht werden.<br />
|
||||
Zu den Diskussionen können Beiträge erstellt, bearbeitet und gelöscht werden.</p>
|
||||
<p>Daten können jedoch nur erstellt, bearbeitet oder gelöscht werden, wenn man sich eingeloggt hat. Weiterhin kann man nur seine eigenen Daten bearbeiten/löschen.</p>
|
||||
<h2 id="implementierung-des-serverseitig">2.Implementierung des Serverseitig</h2>
|
||||
<h3 id="rest-interface">2.1 REST-Interface</h3>
|
||||
<p>Folgende URL werden mittels REST-Prinzip entgegengenommen:<br />
|
||||
/topic /discussion<br />
|
||||
/post<br />
|
||||
/login</p>
|
||||
<h3 id="module">2.2 Module</h3>
|
||||
<h4 id="server.py">server.py:</h4>
|
||||
<p>Startet und konfiguriert den Server und das REST-Interface</p>
|
||||
<h4 id="topic.py">topic.py:</h4>
|
||||
<p>Dieses Modul soll alle Anfragen annehmen, die sich direkt auf Themen beziehen.</p>
|
||||
<p>Enthält die Klasse: "Topic_cl".</p>
|
||||
<p>Topic_cl enthält folgende Methoden:<br />
|
||||
GET: Wenn keine ID übergeben wird, wird die Themenliste zurückgegeben, anderenfalls wird das Thema zurückgegeben. Bei der ID "0" wird ein "Default-Topic" zurückgegeben.</p>
|
||||
<p>PUT: Erzeugt aus den übergegeben Werten ein Thema.</p>
|
||||
<p>POST: Editiert das Thema mit der übergebenen ID mit den übergebenen Werten.</p>
|
||||
<p>DELETE: Das Thema mit der übergebenen ID wird gelöscht.</p>
|
||||
<h4 id="discussion.py">discussion.py:</h4>
|
||||
<p>Dieses Modul soll alle Anfragen annehmen, die sich direkt auf Diskussionen beziehen.</p>
|
||||
<p>Enthält die Klasse: "Discussion_cl".</p>
|
||||
<p>Diskussion_cl enthält folgende Methoden:<br />
|
||||
GET: Wenn keine Diskussions-ID übergeben wird, wird die Diskussionsliste der übergebenen Themen-ID zurückgegeben, anderenfalls wird die Diskussion zurückgegeben. Bei der ID "0" wird eine "Default-Discussion" zurückgegeben.</p>
|
||||
<p>PUT: Erzeugt aus den übergegeben Werten eine Diskussion.</p>
|
||||
<p>POST: Editiert die Diskussion mit der übergebenen ID mit den übergebenen Werten.</p>
|
||||
<p>DELETE: Die Diskussion mit der übergebenen ID wird gelöscht.</p>
|
||||
<h4 id="post.py">post.py:</h4>
|
||||
<p>Dieses Modul soll alle Anfragen annehmen, die sich direkt auf Beiträge beziehen.</p>
|
||||
<p>Enthält die Klasse: "Post_cl".</p>
|
||||
<p>Diskussion_cl enthält folgende Methoden:<br />
|
||||
GET: Wenn keine Beitrags-ID übergeben wird, wird die Beitragsliste der übergebenen Diskussions-ID zurückgegeben, anderenfalls wird der Beitrag zurückgegeben. Bei der ID "0" wird ein "Default-Beitrag" zurückgegeben.</p>
|
||||
<p>PUT: Erzeugt aus den übergegeben Werten einen Beitrag.</p>
|
||||
<p>POST: Editiert den Beitrag mit der übergebenen ID mit den übergebenen Werten.</p>
|
||||
<p>DELETE: Der Beitrag mit der übergebenen ID wird gelöscht.</p>
|
||||
<h4 id="database.py">database.py:</h4>
|
||||
<p>Dieses Modul verwaltet die Daten der anderen Module, die zurückgegeben, verändert oder gespeichert werden sollen.</p>
|
||||
<p>Enthält die Klasse: "Database_cl".</p>
|
||||
<p>Database_cl enthält folgende Methoden: createTopic_px(self, data_opl): Speichert ein neues Thema mit dem Werten von "data_opl" in die topics.dat.</p>
|
||||
<p>createDiscussion_px(self, tID, data_opl): Speichert eine neue Diskussion mit den Werten von "data_opl" in die discussions.dat und seine ID in das übergebene Thema.</p>
|
||||
<p>createPost_px(self, dID, data_opl): Speichert einen neuen Beitrag mit den Werten von "data_opl" in die posts.dat und seine ID in die übergebene Diskussion.</p>
|
||||
<p>readTopic_px(self, id_ = None):Bei id_ == None wird die Themenliste, bei "0" ein "Default-Thema" und bei einem Wert != 0 das entsprechende Thema zurückgegeben.</p>
|
||||
<p>readDiscussion_px(self, tId, dId = None): Bei dId == None wird die Diskussionsliste, bei "0" eine "Default-Diskussion" und bei einem Wert != 0 die entsprechende Diskussion zurückgegeben.</p>
|
||||
<p>readPost_px(self, dID, pID = None): Bei dId == None wird die Beitragsliste, bei "0" ein "Default-Beitrag" und bei einem Wert != 0 der entsprechende Beitrag zurückgegeben.</p>
|
||||
<p>updateTopic_px(self, id_, data_opl): Überprüft ob ein Thema mit der übergebenen ID existiert, wenn ja wird das editierte Thema abgespeichert.</p>
|
||||
<p>updateDiscussion_px(self, id_, data_opl): Überprüft ob eine Diskussion mit der übergebenen ID existiert, wenn ja wird die editierte Diskussion abgespeichert.</p>
|
||||
<p>updatePost_px(self, id_, data_opl): Überprüft ob ein Beitrag mit der übergebenen ID existiert, wenn ja wird der editerte Beitrag abgespeichert.</p>
|
||||
<p>deleteTopic_px(self, id_): Überprüft ob ein Thema mit der übergebenen ID existiert, wenn ja wird es gelöscht.</p>
|
||||
<p>deleleteDiscussion_px(self, id_): Überprüft ob eine Diskussion mit der übergebenen ID existiert, wenn ja wird sie gelöscht.</p>
|
||||
<p>deletePost_px(self, id_): Überprüft ob ein Beitrag mit der übergebenen ID existiert, wenn ja wird er gelöscht.</p>
|
||||
<p>getDefaultTopic_px(self): Gibt ein "Default-Thema" zurück.</p>
|
||||
<p>getDefaultDiscussion_px(self): Gibt eine "Default-Diskussion" zurück.</p>
|
||||
<p>getDefaultPost_px(self): Gibt einen "Default-Beitrag" zurück.</p>
|
||||
<p>getUsers_px(self): Gibt die Benutzer zurück.</p>
|
||||
<p>saveUsers_px(self, data_o): Speichert den übergebenen Benutzer in die "users.dat".</p>
|
||||
<h4 id="login.py">login.py</h4>
|
||||
<p>Dieses Modul verwaltet den Login.</p>
|
||||
<p>Enthält die Klasse: "Login_cl".</p>
|
||||
<p>Login_cl enhält folgende Methoden: GET: Prüft, ob der übergebene Benutzer vorhanden ist. Wenn ja, wird zurückgegebenen, dass dieser autorisiert ist.</p>
|
||||
<p>Put: Prüft, ob der übergebene Benutzername schon existiert, falls nicht wird dieser neu angelegt und gespeichert.</p>
|
||||
<h4 id="template.py">template.py</h4>
|
||||
<p>Dieses Modul lädt alle Templates</p>
|
||||
<p>Enthält die Klasse: "Template_cl".</p>
|
||||
<p>Template_cl enthält folgende Methoden: GET: Gibt alle Templates zurück.</p>
|
||||
<h4 id="application.py">application.py:</h4>
|
||||
<p>Dieses Modul gibt bei unbekannter Anforderung eine Fehlermeldung zurück.</p>
|
||||
<h4 id="zusammenwirken">Zusammenwirken</h4>
|
||||
<p>Die Module topic.py, discussion.py, login.py und post.py verwalten alle ihre Daten mithilfe der database.py. Diese löscht, speichert, erstellt oder verändert Daten und übergibt diese dann an die entsprechenden Module zur weiteren Verarbeitung.</p>
|
||||
<h3 id="datenhaltung">2.3 Datenhaltung</h3>
|
||||
<h4 id="topics.dat">topics.dat</h4>
|
||||
<p>Die Themen werden wie folgt in der "topics.dat" gespeichert: "name": [string] "owner": [string] "discs": [Keys der dazugehörigen Diskussionen] "deleted": [boolean]</p>
|
||||
<p>Zusätzlich wird die ID für das nächste Thema gespeichert.</p>
|
||||
<h4 id="discussions.dat">discussions.dat</h4>
|
||||
<p>Die Diskussionen werden wie folgt in der "discussions.dat" gespeichert: "name": [string] "owner": [string] "posts": [Keys der dazugehörigen Beiträge] "deleted": [boolean]</p>
|
||||
<p>Zusätzlich wird die ID für die nächste Diskussion gespeichert.</p>
|
||||
<h4 id="posts.dat">posts.dat</h4>
|
||||
<p>Die Beiträge werden wie folgt in der "posts.dat" gespeichert: "text": [string] "owner": [string] "title": [string] "time": [Zeitangaben] "deleted": [boolean]</p>
|
||||
<p>Zusätzlich wird die ID für den nächsten Beitrag gespeichert.</p>
|
||||
<h4 id="users.dat">users.dat</h4>
|
||||
<p>Die Themen werden wie folgt in der "users.dat" gespeichert: "[Benutzername]": [Passwort]</p>
|
||||
<h3 id="implementierung-des-clients">3. Implementierung des Clients</h3>
|
||||
<h4 id="klassen">3.1 Klassen</h4>
|
||||
<p>FORUM.User_cl: Stellt die Funktionen für den Benutzer zur Verfügung.</p>
|
||||
<p>FORUM.Application_cl: Erzeugt die Instanzen der einzelnen Klassen und verwaltet das Anzeigen der Inhalte auf Basis der Nachrichten des Eventservices.</p>
|
||||
<p>FORUM.TopicListView_cl: Verwaltet die Anzeige der Themenliste und die in diesem Teil enstehenden Events.</p>
|
||||
<p>FORUM.TopicDetailView_cl: Verwaltet die Anzeige des Themenformulars und die in diesem Teil enstehenden Events.</p>
|
||||
<p>FORUM.DiscussionListView_cl: Verwaltet die Anzeige der Diskussionsliste und die in diesem Teil enstehenden Events.</p>
|
||||
<p>FORUM.DiscussionDetailView_cl: Verwaltet die Anzeige des Diskussionsformulars und die in diesem Teil enstehenden Events.</p>
|
||||
<p>FORUM.PostListView_cl: Verwaltet die Anzeige der Beitragsliste und die in diesem Teil enstehenden Events.</p>
|
||||
<p>FORUM.PostDetailView_cl: Verwaltet die Anzeige des Beitragsformulars und die in diesem Teil enstehenden Events.</p>
|
||||
<p>FORUM.LoginView_cl: Verwaltet die Anzeige des Loginformulars und die in diesem Teil enstehenden Events.</p>
|
||||
<h4 id="eventservice">3.2 Eventservice:</h4>
|
||||
<p>Der Eventservice wird benutzt um zu signalisieren, dass eine Seite angezeigt werden soll,<br />
|
||||
diese werden in Forum.js abgehandelt und dann zu den entsprechenden Skripten weitergeschickt.</p>
|
||||
<h4 id="templateverarbeitung">3.3 Templateverarbeitung:</h4>
|
||||
<p>Die drei Templates die verwendet werden sind:<br />
|
||||
list_topic.tpl<br />
|
||||
list_discussion.tpl<br />
|
||||
list_post.tpl<br />
|
||||
Diese Templates bauen die Tabellen zusammen, die jeweils die Listen aus Themen, Beiträgen und Diskussionen anzeigen.</p>
|
||||
<h2 id="prüfung-markup-und-stilregeln">Prüfung Markup und Stilregeln:</h2>
|
||||
<p>Ergebnis Test des Markups des HTML Codes der Index Datei mit Beispielementen in allen drei Kategorien: "Document checking completed. No errors or warnings to show."</p>
|
||||
<p>Ergebnis des Tests der CSS-Stilregeln:<br />
|
||||
"Congratulations! No Error Found." </p>
|
||||
</body>
|
||||
</html>
|
19
Sammlung/Praktikum/4/html/edit_discussion.html
Normal file
19
Sammlung/Praktikum/4/html/edit_discussion.html
Normal file
@ -0,0 +1,19 @@
|
||||
<div id="idDiscussionEditContent" class="clContent">
|
||||
<form id="idDiscussionDetail" class="clContent" action="#"">
|
||||
<h2 id="idDiscussionDetailContentHeader" class="clContentHeader">
|
||||
Diskussion Ändern
|
||||
</h2>
|
||||
<div id="idDiscussionFormContentArea" class="clContentArea">
|
||||
|
||||
<div class="clFormRow">
|
||||
<label for="dEditName">Name <span class="clRequired"></span></label>
|
||||
<input type="text" value="" id="dEditName" name="name" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="clButtonArea">
|
||||
<button data-action="back" class="clButton">Zurück</button>
|
||||
<button data-action="save" class="clButton">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
23
Sammlung/Praktikum/4/html/edit_post.html
Normal file
23
Sammlung/Praktikum/4/html/edit_post.html
Normal file
@ -0,0 +1,23 @@
|
||||
<div id="idPostEditContent" class="clContent">
|
||||
<form id="idPostDetail" class="clContent" action="#"">
|
||||
<h2 id="idPostDetailContentHeader" class="clContentHeader">
|
||||
Neuer Beitrag
|
||||
</h2>
|
||||
<div id="idPostFormContentArea" class="clContentArea">
|
||||
|
||||
<div class="clFormRow">
|
||||
<label for="pEditTitle">Titel <span class="clRequired"></span></label>
|
||||
<input type="text" value="" id="pEditTitle" name="title"/>
|
||||
</div>
|
||||
<div class="clFormRow">
|
||||
<label for="pEditText">Text <span class="clRequired"></span></label>
|
||||
<textarea id="pEditText" name="text" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="clButtonArea">
|
||||
<button data-action="back" class="clButton">Zurück</button>
|
||||
<button data-action="save" class="clButton">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
19
Sammlung/Praktikum/4/html/edit_topic.html
Normal file
19
Sammlung/Praktikum/4/html/edit_topic.html
Normal file
@ -0,0 +1,19 @@
|
||||
<div id="idTopicEditContent" class="clContent">
|
||||
<form id="idTopicDetail" class="clContent" action="#"">
|
||||
<h2 id="idTopicDetailContentHeader" class="clContentHeader">
|
||||
Neues Thema
|
||||
</h2>
|
||||
<div id="idTopicFormContentArea" class="clContentArea">
|
||||
|
||||
<div class="clFormRow">
|
||||
<label for="tEditName">Name <span class="clRequired"></span></label>
|
||||
<input type="text" value="" id="tEditName" name="name" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="clButtonArea">
|
||||
<button data-action="back" class="clButton">Zurück</button>
|
||||
<button data-action="save" class="clButton">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
49
Sammlung/Praktikum/4/html/index.html
Normal file
49
Sammlung/Praktikum/4/html/index.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Web Engineering 2015/2016 Forum Gruppe D
|
||||
</title>
|
||||
<meta charset="UTF-8" />
|
||||
<style type="text/css">
|
||||
@import url("/css/main.css");
|
||||
</style>
|
||||
<script type="text/javascript" src="/js/jquery-2.2.0.min.js"></script>
|
||||
<script type="text/javascript" src="/js/inheritance.js"></script>
|
||||
<script type="text/javascript" src="/js/es.js"></script>
|
||||
<script type="text/javascript" src="/js/te.js"></script>
|
||||
<script type="text/javascript" src="/js/tm.js"></script>
|
||||
<!-- hier zur Verdeutlichung der Strukturierung Aufteilung in mehrere js-Quellen -->
|
||||
<!-- wird man im produktiven Einsatz zu einer js-Quelle zusammenfassen -->
|
||||
<script type="text/javascript" src="/js/forum.js"></script>
|
||||
<script type="text/javascript" src="/js/list_topic.js"></script>
|
||||
<script type="text/javascript" src="/js/edit_topic.js"></script>
|
||||
<script type="text/javascript" src="/js/list_discussion.js"></script>
|
||||
<script type="text/javascript" src="/js/edit_discussion.js"></script>
|
||||
<script type="text/javascript" src="/js/list_post.js"></script>
|
||||
<script type="text/javascript" src="/js/edit_post.js"></script>
|
||||
<script type="text/javascript" src="/js/post.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/js/nav.js"></script>
|
||||
<script type="text/javascript" src="/js/login.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 id="idSiteHeader" class="clSiteHeader">
|
||||
Web Engineering 2015/2016 Forum Gruppe D
|
||||
</h1>
|
||||
</header>
|
||||
<section class="clLoggedInText">
|
||||
<p id="idNotLoggedIn">Sie sind nicht eingeloggt!</p>
|
||||
<p id="idLoggedIn">Sie sind eingeloggt als: </p>
|
||||
</section>
|
||||
<section id="idContentOuter" class="clContentOuter">
|
||||
</section>
|
||||
<nav id="idNav" class="clNav">
|
||||
<a href="#" data-action="topicList">Home</a>
|
||||
<a href="#" data-action="login" class="clLinkToLogin">Login</a>
|
||||
<a href="#" data-action="logout" class="clLinkToLogout">Logout</a>
|
||||
</nav>
|
||||
</body>
|
||||
</html>
|
||||
|
16
Sammlung/Praktikum/4/html/list_discussion.html
Normal file
16
Sammlung/Praktikum/4/html/list_discussion.html
Normal file
@ -0,0 +1,16 @@
|
||||
<div id="idDiscussionListContent" class="clContent">
|
||||
<h2 id="idContentHeader" class="clContentHeader">Diskussionen</h2>
|
||||
<div id="idContentArea" class="clContentArea">
|
||||
<table id="idDiscussionList"><tbody>
|
||||
<tr class="listheader"><th>Diskussion</th><th>Besitzer</th></tr>
|
||||
</tbody></table>
|
||||
|
||||
<div class="clButtonArea">
|
||||
<button data-action="back" class="clButton">Zurück</button>
|
||||
<button data-action="addDiscussion" class="clButton">Hinzufügen</button>
|
||||
<button data-action="discussion" class="clButton">Ansehen</button>
|
||||
<button data-action="editDiscussion" class="clButton">Bearbeiten</button>
|
||||
<button data-action="deleteDiscussion" class="clButton">Löschen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
15
Sammlung/Praktikum/4/html/list_post.html
Normal file
15
Sammlung/Praktikum/4/html/list_post.html
Normal file
@ -0,0 +1,15 @@
|
||||
<div id="idPostListContent" class="clContent">
|
||||
<h2 id="idContentHeader" class="clContentHeader">Beiträge</h2>
|
||||
<div id="idContentArea" class="clContentArea">
|
||||
<ul id="idPostList">
|
||||
</ul>
|
||||
|
||||
<div class="clButtonArea">
|
||||
<button data-action="back" class="clButton">Zurück</button>
|
||||
<button data-action="addPost" class="clButton">Hinzufügen</button>
|
||||
<button data-action="post" class="clButton">Ansehen</button>
|
||||
<button data-action="editPost" class="clButton">Bearbeiten</button>
|
||||
<button data-action="deletePost" class="clButton">Löschen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
15
Sammlung/Praktikum/4/html/list_topic.html
Normal file
15
Sammlung/Praktikum/4/html/list_topic.html
Normal file
@ -0,0 +1,15 @@
|
||||
<div id="idTopicListContent" class="clContent">
|
||||
<h2 id="idContentHeader" class="clContentHeader">Themen</h2>
|
||||
<div id="idContentArea" class="clContentArea">
|
||||
<table id="idTopicList"><tbody>
|
||||
<tr class="listheader"><th>Thema</th><th>Besitzer</th></tr>
|
||||
</tbody></table>
|
||||
|
||||
<div class="clButtonArea">
|
||||
<button data-action="addTopic" class="clButton">Hinzufügen</button>
|
||||
<button data-action="discussionList" class="clButton">Diskussionen</button>
|
||||
<button data-action="editTopic" class="clButton">Bearbeiten</button>
|
||||
<button data-action="deleteTopic" class="clButton">Löschen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
26
Sammlung/Praktikum/4/html/login.html
Normal file
26
Sammlung/Praktikum/4/html/login.html
Normal file
@ -0,0 +1,26 @@
|
||||
<div id="idLoginContent" class="clContent">
|
||||
<h2 id="idContentHeader" class="clContentHeader">Einloggen</h2>
|
||||
<div id="idContentArea" class="clContentArea">
|
||||
<form id="idLoginForm" class="clContent" action="#">
|
||||
|
||||
<div id="idLogin" class="clLogin">
|
||||
|
||||
<div class="clFormRow">
|
||||
<label for="username">Benutzername</label>
|
||||
<input type="text" value="" id="username" name="username" />
|
||||
</div>
|
||||
<div class="clFormRow">
|
||||
<label for="password">Passwort</label>
|
||||
<input type="password" value="" id="password" name="password" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="idButtonArea" class="clButtonArea">
|
||||
<button data-action="back" class="clButton">Zurück</button>
|
||||
<button data-action="login" class="clButton">Login</button>
|
||||
<button data-action="register" class="clButton">Registrieren</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
13
Sammlung/Praktikum/4/html/post.html
Normal file
13
Sammlung/Praktikum/4/html/post.html
Normal file
@ -0,0 +1,13 @@
|
||||
<div id="idPostContent" class="clContent">
|
||||
<h2 id="idContentHeader" class="clContentHeader">Beitrag</h2>
|
||||
<div id="idContentArea" class="clContentArea">
|
||||
<ul id="idPost">
|
||||
</ul>
|
||||
|
||||
<div class="clButtonArea">
|
||||
<button data-action="back" class="clButton">Zurück</button>
|
||||
<button data-action="editPost" class="clButton">Bearbeiten</button>
|
||||
<button data-action="deletePost" class="clButton">Löschen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
116
Sammlung/Praktikum/4/js/edit_discussion.js
Normal file
116
Sammlung/Praktikum/4/js/edit_discussion.js
Normal file
@ -0,0 +1,116 @@
|
||||
// ----------------------------------------------
|
||||
// edit_discussion.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.DiscussionDetailView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
initialize: function () {
|
||||
// Basis-Markup des Formulars anfordern
|
||||
var that = this;
|
||||
$.get('/html/edit_discussion.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idDiscussionEditContent").hide();
|
||||
that.initHandler_p();
|
||||
|
||||
that.storeFormContent_p();
|
||||
});
|
||||
|
||||
},
|
||||
canClose_px: function () {
|
||||
// Prüfen, ob Formularinhalt verändert wurde
|
||||
return (this.isModified_p() ? confirm("Es gibt nicht gespeicherte Änderungen - verwerfen?") : true);
|
||||
},
|
||||
close_px: function () {
|
||||
$("#idDiscussionEditContent").hide();
|
||||
},
|
||||
render_px: function (ids) {
|
||||
tId_ = ids[0];
|
||||
id_ = ids[1];
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: '/discussion/' + tId_ + '/' + (id_ == null?'0':id_),
|
||||
type: 'GET'
|
||||
})
|
||||
.done($.proxy(this.doRender_p, this))
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[Form] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
},
|
||||
doRender_p: function (data_opl) {
|
||||
// in das Formular übertragen
|
||||
var data_o = data_opl['data'];
|
||||
$('#dEditName').val(data_o['name']);
|
||||
this.id_s = data_opl['id'];
|
||||
this.tId = data_opl['tId'];
|
||||
|
||||
this.storeFormContent_p();
|
||||
|
||||
$("#idDiscussionEditContent").show();
|
||||
},
|
||||
initHandler_p: function () {
|
||||
// Ereignisverarbeitung für das Formular einrichten
|
||||
$("#idDiscussionEditContent").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
},
|
||||
onClickButtons_p: function (event_opl) {
|
||||
var do_b = false;
|
||||
var path_s;
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
switch (action_s) {
|
||||
case "back":
|
||||
// Weiterleiten
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussionList', this.tId]);
|
||||
break;
|
||||
case "save":
|
||||
// Formularinhalt prüfen
|
||||
if (this.isModified_p()) {
|
||||
if (this.checkContent_p()) {
|
||||
// kein klassisches submit, es wird auch keine neue Anzeige vorgenommen
|
||||
var data_s = $("#idDiscussionDetail").serialize();
|
||||
data_s += "&owner=" + FORUM.user_o.name_s;
|
||||
$.ajax({
|
||||
context: this,
|
||||
dataType: "json",
|
||||
data: data_s,
|
||||
url: '/discussion/' + this.tId + '/' + (this.id_s != 0?'/' + this.id_s:''),
|
||||
type: (this.id_s != 0?'POST':'PUT')
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
// aktuellen Formularinhalt speichern
|
||||
// (das Formular wird ja nicht mehr neu geladen!)
|
||||
this.storeFormContent_p();
|
||||
alert("Speichern ausgeführt!");
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussionList', this.tId]);
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
|
||||
} else {
|
||||
alert("Bitte prüfen Sie die Eingaben in den Formularfeldern!")
|
||||
}
|
||||
}
|
||||
else {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussionList', null]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Weiterleitung und Standardbearbeitung unterbinden
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
},
|
||||
isModified_p: function () {
|
||||
// Prüfen, ob Formularinhalt verändert wurde
|
||||
return (this.FormContentOrg_s != $("#idDiscussionDetail").serialize());
|
||||
},
|
||||
checkContent_p: function () {
|
||||
// hier nur zur Demonstration Prüfung des Typs gegen eine Werteliste
|
||||
// (das realisiert man besser mit einer Liste)
|
||||
var status_b = true;
|
||||
return status_b;
|
||||
},
|
||||
storeFormContent_p: function () {
|
||||
this.FormContentOrg_s = $("#idDiscussionDetail").serialize();
|
||||
}
|
||||
});
|
||||
// EOF
|
128
Sammlung/Praktikum/4/js/edit_post.js
Normal file
128
Sammlung/Praktikum/4/js/edit_post.js
Normal file
@ -0,0 +1,128 @@
|
||||
// ----------------------------------------------
|
||||
// edit_Topic.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.PostDetailView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
initialize: function () {
|
||||
// Basis-Markup des Formulars anfordern
|
||||
var that = this;
|
||||
$.get('/html/edit_post.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idPostEditContent").hide();
|
||||
that.initHandler_p();
|
||||
|
||||
that.storeFormContent_p();
|
||||
});
|
||||
|
||||
},
|
||||
canClose_px: function () {
|
||||
// Prüfen, ob Formularinhalt verändert wurde
|
||||
return (this.isModified_p() ? confirm("Es gibt nicht gespeicherte Änderungen - verwerfen?") : true);
|
||||
},
|
||||
close_px: function () {
|
||||
$("#idPostEditContent").hide();
|
||||
},
|
||||
render_px: function (ids) {
|
||||
tId_ = ids[0];
|
||||
dId_ = ids[1];
|
||||
id_ = ids[2];
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: '/post/' + tId_ + '/' + dId_ + '/' + (id_ == null?'0':id_),
|
||||
type: 'GET'
|
||||
})
|
||||
.done($.proxy(this.doRender_p, this))
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[Form] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
},
|
||||
doRender_p: function (data_opl) {
|
||||
// in das Formular übertragen
|
||||
var data_o = data_opl['data'];
|
||||
$('#pEditTitle').val(data_o['title']);
|
||||
$('#pEditText').val(data_o['text']);
|
||||
this.id_s = data_opl['id'];
|
||||
this.tId = data_opl['tId'];
|
||||
this.dId = data_opl['dId'];
|
||||
|
||||
if (parseInt(this.dId) == 0)
|
||||
$("#idPostDetailContentHeader").text("Neue Diskussion");
|
||||
else if (parseInt(this.id_s) != 0)
|
||||
$("#idPostDetailContentHeader").text("Beitrag ändern");
|
||||
|
||||
this.storeFormContent_p();
|
||||
|
||||
$("#idPostEditContent").show();
|
||||
},
|
||||
initHandler_p: function () {
|
||||
// Ereignisverarbeitung für das Formular einrichten
|
||||
$("#idPostEditContent").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
},
|
||||
onClickButtons_p: function (event_opl) {
|
||||
var do_b = false;
|
||||
var path_s;
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
switch (action_s) {
|
||||
case "back":
|
||||
// Weiterleiten
|
||||
if (this.dId != 0)
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussion', this.tId, this.dId]);
|
||||
else
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussionList', this.tId]);
|
||||
break;
|
||||
case "save":
|
||||
// Formularinhalt prüfen
|
||||
if (this.isModified_p()) {
|
||||
if (this.checkContent_p()) {
|
||||
// kein klassisches submit, es wird auch keine neue Anzeige vorgenommen
|
||||
var data_s = $("#idPostDetail").serialize();
|
||||
data_s += "&owner=" + FORUM.user_o.name_s;
|
||||
$.ajax({
|
||||
context: this,
|
||||
dataType: "json",
|
||||
data: data_s,
|
||||
url: '/post/' + this.tId + '/' + this.dId + (this.id_s != 0?'/' + this.id_s:''),
|
||||
type: (this.id_s != 0?'POST':'PUT')
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
// aktuellen Formularinhalt speichern
|
||||
// (das Formular wird ja nicht mehr neu geladen!)
|
||||
this.storeFormContent_p();
|
||||
this.dId = data_opl['dId'];
|
||||
alert("Speichern ausgeführt!");
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussion', this.tId, this.dId]);
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
|
||||
} else {
|
||||
alert("Bitte prüfen Sie die Eingaben in den Formularfeldern!")
|
||||
}
|
||||
}
|
||||
else {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussion', this.tId, this.dId]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Weiterleitung und Standardbearbeitung unterbinden
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
},
|
||||
isModified_p: function () {
|
||||
// Prüfen, ob Formularinhalt verändert wurde
|
||||
return (this.FormContentOrg_s != $("#idPostDetail").serialize());
|
||||
},
|
||||
checkContent_p: function () {
|
||||
// hier nur zur Demonstration Prüfung des Typs gegen eine Werteliste
|
||||
// (das realisiert man besser mit einer Liste)
|
||||
var status_b = true;
|
||||
return status_b;
|
||||
},
|
||||
storeFormContent_p: function () {
|
||||
this.FormContentOrg_s = $("#idPostDetail").serialize();
|
||||
}
|
||||
});
|
||||
// EOF
|
117
Sammlung/Praktikum/4/js/edit_topic.js
Normal file
117
Sammlung/Praktikum/4/js/edit_topic.js
Normal file
@ -0,0 +1,117 @@
|
||||
// ----------------------------------------------
|
||||
// edit_Topic.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.TopicDetailView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
initialize: function () {
|
||||
// Basis-Markup des Formulars anfordern
|
||||
var that = this;
|
||||
$.get('/html/edit_topic.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idTopicEditContent").hide();
|
||||
that.initHandler_p();
|
||||
|
||||
that.storeFormContent_p();
|
||||
});
|
||||
|
||||
},
|
||||
canClose_px: function () {
|
||||
// Prüfen, ob Formularinhalt verändert wurde
|
||||
return (this.isModified_p() ? confirm("Es gibt nicht gespeicherte Änderungen - verwerfen?") : true);
|
||||
},
|
||||
close_px: function () {
|
||||
$("#idTopicEditContent").hide();
|
||||
},
|
||||
render_px: function (id_) {
|
||||
this.id_ = id_;
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: '/topic/' + (id_ == null?'0':id_),
|
||||
type: 'GET'
|
||||
})
|
||||
.done($.proxy(this.doRender_p, this))
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[Form] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
},
|
||||
doRender_p: function (data_opl) {
|
||||
// in das Formular übertragen
|
||||
var data_o = data_opl['data'];
|
||||
$('#tEditName').val(data_o['name']);
|
||||
this.id_s = data_opl['id'];
|
||||
|
||||
if (this.id_s != 0)
|
||||
$("#idTopicDetailContentHeader").text("Thema ändern");
|
||||
|
||||
this.storeFormContent_p();
|
||||
|
||||
$("#idTopicEditContent").show();
|
||||
},
|
||||
initHandler_p: function () {
|
||||
// Ereignisverarbeitung für das Formular einrichten
|
||||
$("#idTopicEditContent").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
},
|
||||
onClickButtons_p: function (event_opl) {
|
||||
var do_b = false;
|
||||
var path_s;
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
switch (action_s) {
|
||||
case "back":
|
||||
// Weiterleiten
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
break;
|
||||
case "save":
|
||||
// Formularinhalt prüfen
|
||||
if (this.isModified_p()) {
|
||||
if (this.checkContent_p()) {
|
||||
// kein klassisches submit, es wird auch keine neue Anzeige vorgenommen
|
||||
var data_s = $("#idTopicDetail").serialize();
|
||||
data_s += "&owner=" + FORUM.user_o.name_s;
|
||||
$.ajax({
|
||||
context: this,
|
||||
dataType: "json",
|
||||
data: data_s,
|
||||
url: '/topic' + (this.id_s != 0?'/' + this.id_s:''),
|
||||
type: (this.id_s != 0?'POST':'PUT')
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
// aktuellen Formularinhalt speichern
|
||||
// (das Formular wird ja nicht mehr neu geladen!)
|
||||
this.storeFormContent_p();
|
||||
alert("Speichern ausgeführt!");
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
|
||||
} else {
|
||||
alert("Bitte prüfen Sie die Eingaben in den Formularfeldern!")
|
||||
}
|
||||
}
|
||||
else {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Weiterleitung und Standardbearbeitung unterbinden
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
},
|
||||
isModified_p: function () {
|
||||
// Prüfen, ob Formularinhalt verändert wurde
|
||||
return (this.FormContentOrg_s != $("#idTopicDetail").serialize());
|
||||
},
|
||||
checkContent_p: function () {
|
||||
// hier nur zur Demonstration Prüfung des Typs gegen eine Werteliste
|
||||
// (das realisiert man besser mit einer Liste)
|
||||
var status_b = true;
|
||||
return status_b;
|
||||
},
|
||||
storeFormContent_p: function () {
|
||||
this.FormContentOrg_s = $("#idTopicDetail").serialize();
|
||||
}
|
||||
});
|
||||
// EOF
|
91
Sammlung/Praktikum/4/js/es.js
Normal file
91
Sammlung/Praktikum/4/js/es.js
Normal file
@ -0,0 +1,91 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Event-Service: asynchroner Nachrichtenaustausch
|
||||
//------------------------------------------------------------------------------
|
||||
// depends-on:
|
||||
// jquery
|
||||
// inheritance
|
||||
// underscore
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
function defer_p (notifier_ppl, entry_opl, message_spl, data_opl) {
|
||||
return setTimeout(function() {
|
||||
return notifier_ppl.apply(entry_opl, [entry_opl, message_spl, data_opl]);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function each(object_opl, iterator, context) {
|
||||
for (var key in object_opl) {
|
||||
iterator.call(context, object_opl[key], key);
|
||||
}
|
||||
}
|
||||
|
||||
function findAll(object_opl, iterator, context) {
|
||||
var results = [];
|
||||
each(object_opl, function(value, index) {
|
||||
if (iterator.call(context, value, index))
|
||||
results.push(value);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
function compact(object_opl) {
|
||||
return findAll(object_opl, function(value) {
|
||||
return value != null;
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
var EventService_cl = Class.create({
|
||||
//------------------------------------------------------------------------------
|
||||
initialize: function () {
|
||||
this.Data_o = null;
|
||||
this.Subscriber_o = {};
|
||||
this.Method_o = null;
|
||||
},
|
||||
subscribe_px: function (Subscriber_opl, Message_spl) {
|
||||
if (Message_spl in this.Subscriber_o) {
|
||||
// Message bekannt, Liste der Subscriber untersuchen
|
||||
if (this.Subscriber_o[Message_spl].indexOf(Subscriber_opl) == -1) {
|
||||
this.Subscriber_o[Message_spl].push(Subscriber_opl);
|
||||
}
|
||||
} else {
|
||||
// Message noch nicht vorhanden, neu eintragen
|
||||
this.Subscriber_o[Message_spl] = [Subscriber_opl];
|
||||
}
|
||||
},
|
||||
unSubscribe_px: function (Subscriber_opl, Message_spl) {
|
||||
if (Message_spl in this.Subscriber_o) {
|
||||
// Message bekannt, Liste der Subscriber untersuchen
|
||||
var Entry_a = this.Subscriber_o[Message_spl];
|
||||
var index_i = Entry_a.indexOf(Subscriber_opl);
|
||||
if (index_i >= 0) {
|
||||
// Eintrag entfernen
|
||||
Entry_a[index_i] = null;
|
||||
Entry_a = compact(Entry_a); // compact liefert Kopie!
|
||||
if (Entry_a.length == 0) {
|
||||
// keine Subscriber mehr, kann entfernt werden
|
||||
delete this.Subscriber_o[Message_spl];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Message nicht vorhanden, falsche Anforderung
|
||||
}
|
||||
},
|
||||
publish_px: function (Message_spl, Data_opl) {
|
||||
console.info('es - publish ' + Message_spl);
|
||||
each(this.Subscriber_o, function (value_apl, key_spl) {
|
||||
// geliefert wird jeweils ein Wert, hier ein Array, und der Key
|
||||
if (key_spl == Message_spl) {
|
||||
// an alle Subscriber weitergeben
|
||||
each(value_apl, function (entry_opl, index_ipl) {
|
||||
// geliefert wird hier das Element und der Index
|
||||
//_.defer(entry_opl.notify_px, entry_opl, Message_spl, Data_opl);
|
||||
defer_p(entry_opl.notify_px, entry_opl, Message_spl, Data_opl);
|
||||
}, this
|
||||
);
|
||||
}
|
||||
}, this
|
||||
)
|
||||
}
|
||||
});
|
||||
// EOF
|
178
Sammlung/Praktikum/4/js/forum.js
Normal file
178
Sammlung/Praktikum/4/js/forum.js
Normal file
@ -0,0 +1,178 @@
|
||||
// ----------------------------------------------
|
||||
// forum.js
|
||||
// ----------------------------------------------
|
||||
// Verwendung von jquery, inheritance, Single-Page / Ajax, Event-Service
|
||||
// REST-Interface
|
||||
// ----------------------------------------------
|
||||
|
||||
|
||||
var FORUM = {};
|
||||
|
||||
//********************************************** USER-object
|
||||
FORUM.User_cl = Class.create({
|
||||
initialize: function () {
|
||||
this.name_s = '';
|
||||
this.password = '';
|
||||
this.loggedin = false;
|
||||
$('.clLoggedInText #idLoggedIn').hide();
|
||||
|
||||
},
|
||||
logout: function () {
|
||||
this.id_s = "";
|
||||
this.name_s = "niemand";
|
||||
this.loggedin = false;
|
||||
this.items = [];
|
||||
|
||||
|
||||
$('#idNav .clLinkToLogin').show();
|
||||
$('#idNav .clLinkToSignup').show();
|
||||
$('#idNav .clLinkToLogout').hide();
|
||||
$('.clLoggedInText #idNotLoggedIn').show();
|
||||
$('.clLoggedInText #idLoggedIn').hide();
|
||||
$('.clLoggedInText #idLoggedIn').text('Sie sind eingeloggt als: ');
|
||||
},
|
||||
login: function (data_o) {
|
||||
this.name_s = data_o['username'];
|
||||
this.password = data_o['password'];
|
||||
this.loggedin = true;
|
||||
|
||||
$('#idNav .clLinkToLogin').hide();
|
||||
$('#idNav .clLinkToSignup').hide();
|
||||
$('#idNav .clLinkToLogout').show();
|
||||
$('.clLoggedInText #idNotLoggedIn').hide();
|
||||
$('.clLoggedInText #idLoggedIn').show();
|
||||
$('.clLoggedInText #idLoggedIn').text($('.clLoggedInText #idLoggedIn').text() + data_o['username']);
|
||||
},
|
||||
register: function () {
|
||||
this.id_s = "";
|
||||
this.name_s = "niemand";
|
||||
this.loggedin = false;
|
||||
|
||||
$('#idNav .clLinkToLogin').show();
|
||||
$('#idNav .clLinkToSignup').show();
|
||||
$('#idNav .clLinkToLogout').hide();
|
||||
}
|
||||
});
|
||||
//**********************************************
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.Application_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
initialize: function () {
|
||||
this.content_o = null; // das jeweils aktuelle Objekt im Contentbereich
|
||||
this.nav_o = new FORUM.Nav_cl();
|
||||
//this.discussionView_o = new FORUM.PostlistView_cl();
|
||||
this.topicListView_o = new FORUM.TopicListView_cl();
|
||||
this.topicDetailView_o = new FORUM.TopicDetailView_cl();
|
||||
this.discussionListView_o = new FORUM.DiscussionListView_cl();
|
||||
this.discussionDetailView_o = new FORUM.DiscussionDetailView_cl();
|
||||
this.postListView_o = new FORUM.PostListView_cl();
|
||||
this.postDetailView_o = new FORUM.PostDetailView_cl();
|
||||
this.postView_o = new FORUM.PostView_cl();
|
||||
|
||||
//this.discussionlistView_o = new FORUM.DiscussionlistView_cl();
|
||||
//this.postView_o = new FORUM.PostView_cl();
|
||||
this.loginView_o = new FORUM.LoginView_cl();
|
||||
|
||||
// Registrierungen
|
||||
FORUM.es_o.subscribe_px(this, 'ContentChanged');
|
||||
},
|
||||
notify_px: function (self_opl, message_spl, data_apl) {
|
||||
switch (message_spl) {
|
||||
case 'ContentChanged':
|
||||
switch (data_apl[0]) {
|
||||
case 'init':
|
||||
FORUM.tm_o = new TELIB.TemplateManager_cl();
|
||||
break;
|
||||
|
||||
case 'showRegister':
|
||||
self_opl.setContent_p(self_opl.registerView_o, data_apl[1]);
|
||||
break;
|
||||
|
||||
case 'showLogin':
|
||||
self_opl.setContent_p(self_opl.loginView_o, data_apl[1]);
|
||||
break;
|
||||
|
||||
case 'logout':
|
||||
FORUM.user_o.logout();
|
||||
self_opl.setContent_p(self_opl.topicListView_o, data_apl[1]);
|
||||
break;
|
||||
|
||||
case 'login':
|
||||
self_opl.setContent_p(self_opl.loginView_o, data_apl[1]);
|
||||
break;
|
||||
|
||||
case 'register':
|
||||
FORUM.user_o.register();
|
||||
self_opl.setContent_p(self_opl.topicListView_o, data_apl[1]);
|
||||
break;
|
||||
|
||||
case 'topicList':
|
||||
self_opl.setContent_p(self_opl.topicListView_o, data_apl[1]);
|
||||
break;
|
||||
|
||||
case 'topicEdit':
|
||||
self_opl.setContent_p(self_opl.topicDetailView_o, data_apl[1]);
|
||||
break;
|
||||
|
||||
case 'discussionList':
|
||||
self_opl.setContent_p(self_opl.discussionListView_o, data_apl[1]);
|
||||
break;
|
||||
|
||||
case 'discussionEdit':
|
||||
self_opl.setContent_p(self_opl.discussionDetailView_o, [data_apl[1], data_apl[2]]);
|
||||
break;
|
||||
|
||||
case 'discussion':
|
||||
self_opl.setContent_p(self_opl.postListView_o, [data_apl[1], data_apl[2]]);
|
||||
break;
|
||||
|
||||
case 'postEdit':
|
||||
self_opl.setContent_p(self_opl.postDetailView_o, [data_apl[1], data_apl[2], data_apl[3]]);
|
||||
break;
|
||||
|
||||
case 'post':
|
||||
self_opl.setContent_p(self_opl.postView_o, [data_apl[1], data_apl[2], data_apl[3]]);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn('[Application_cl] unbekannte app-Notification: ' + data_apl[0]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn('[Application_cl] unbekannte Notification: ' + message_spl);
|
||||
break;
|
||||
}
|
||||
},
|
||||
setContent_p: function (newContent_opl, data_opl) {
|
||||
if (this.content_o != null) {
|
||||
if (this.content_o.canClose_px()) {
|
||||
this.content_o.close_px();
|
||||
this.content_o = newContent_opl;
|
||||
this.content_o.render_px(data_opl);
|
||||
}
|
||||
} else {
|
||||
this.content_o = newContent_opl;
|
||||
this.content_o.render_px(data_opl);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ----------------------------------------------
|
||||
$(document).ready(function () {
|
||||
// ----------------------------------------------
|
||||
// wird ausgeführt, wenn das Dokument vollständig geladen wurde
|
||||
FORUM.es_o = new EventService_cl();
|
||||
FORUM.app_o = new FORUM.Application_cl();
|
||||
FORUM.user_o = new FORUM.User_cl();
|
||||
FORUM.es_o.publish_px('ContentChanged', ['init', null]);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// EOF
|
122
Sammlung/Praktikum/4/js/inheritance.js
Normal file
122
Sammlung/Praktikum/4/js/inheritance.js
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
Class, version 2.7
|
||||
Copyright (c) 2006, 2007, 2008, Alex Arnell <alex@twologic.com>
|
||||
Licensed under the new BSD License. See end of file for full license terms.
|
||||
*/
|
||||
|
||||
var Class = (function() {
|
||||
var __extending = {};
|
||||
|
||||
return {
|
||||
extend: function(parent, def) {
|
||||
if (arguments.length == 1) { def = parent; parent = null; }
|
||||
var func = function() {
|
||||
if (arguments[0] == __extending) { return; }
|
||||
this.initialize.apply(this, arguments);
|
||||
};
|
||||
if (typeof(parent) == 'function') {
|
||||
func.prototype = new parent( __extending);
|
||||
}
|
||||
var mixins = [];
|
||||
if (def && def.include) {
|
||||
if (def.include.reverse) {
|
||||
// methods defined in later mixins should override prior
|
||||
mixins = mixins.concat(def.include.reverse());
|
||||
} else {
|
||||
mixins.push(def.include);
|
||||
}
|
||||
delete def.include; // clean syntax sugar
|
||||
}
|
||||
if (def) Class.inherit(func.prototype, def);
|
||||
for (var i = 0; (mixin = mixins[i]); i++) {
|
||||
Class.mixin(func.prototype, mixin);
|
||||
}
|
||||
return func;
|
||||
},
|
||||
mixin: function (dest, src, clobber) {
|
||||
clobber = clobber || false;
|
||||
if (typeof(src) != 'undefined' && src !== null) {
|
||||
for (var prop in src) {
|
||||
if (clobber || (!dest[prop] && typeof(src[prop]) == 'function')) {
|
||||
dest[prop] = src[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
},
|
||||
inherit: function(dest, src, fname) {
|
||||
if (arguments.length == 3) {
|
||||
var ancestor = dest[fname], descendent = src[fname], method = descendent;
|
||||
descendent = function() {
|
||||
var ref = this.parent; this.parent = ancestor;
|
||||
var result = method.apply(this, arguments);
|
||||
ref ? this.parent = ref : delete this.parent;
|
||||
return result;
|
||||
};
|
||||
// mask the underlying method
|
||||
descendent.valueOf = function() { return method; };
|
||||
descendent.toString = function() { return method.toString(); };
|
||||
dest[fname] = descendent;
|
||||
} else {
|
||||
for (var prop in src) {
|
||||
if (dest[prop] && typeof(src[prop]) == 'function') {
|
||||
Class.inherit(dest, src, prop);
|
||||
} else {
|
||||
dest[prop] = src[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
},
|
||||
singleton: function() {
|
||||
var args = arguments;
|
||||
if (args.length == 2 && args[0].getInstance) {
|
||||
var klass = args[0].getInstance(__extending);
|
||||
// we're extending a singleton swap it out for it's class
|
||||
if (klass) { args[0] = klass; }
|
||||
}
|
||||
|
||||
return (function(args){
|
||||
// store instance and class in private variables
|
||||
var instance = false;
|
||||
var klass = Class.extend.apply(args.callee, args);
|
||||
return {
|
||||
getInstance: function () {
|
||||
if (arguments[0] == __extending) return klass;
|
||||
if (instance) return instance;
|
||||
return (instance = new klass());
|
||||
}
|
||||
};
|
||||
})(args);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
// finally remap Class.create for backward compatability with prototype
|
||||
Class.create = function() {
|
||||
return Class.extend.apply(this, arguments);
|
||||
};
|
||||
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
* Neither the name of typicalnoise.com nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
4
Sammlung/Praktikum/4/js/jquery-2.2.0.min.js
vendored
Normal file
4
Sammlung/Praktikum/4/js/jquery-2.2.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
196
Sammlung/Praktikum/4/js/list_discussion.js
Normal file
196
Sammlung/Praktikum/4/js/list_discussion.js
Normal file
@ -0,0 +1,196 @@
|
||||
// ----------------------------------------------
|
||||
// list_discussion.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.DiscussionListView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
onClickButtons_p: function (event_opl) {
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
switch (action_s) {
|
||||
|
||||
case 'addDiscussion':
|
||||
FORUM.es_o.publish_px('ContentChanged', ['postEdit', this.tId, 0, 0]);
|
||||
break;
|
||||
|
||||
case 'discussion':
|
||||
if (this.rowId_s != "") {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussion', this.tId, this.rowId_s]);
|
||||
this.updateButtons_p();
|
||||
} else {
|
||||
alert("Wählen Sie bitte einen Eintrag in der Tabelle aus!");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'deleteDiscussion':
|
||||
if (this.rowId_s != "") {
|
||||
if (confirm("Soll der Datensatz gelöscht werden?")) {
|
||||
var path_s = "/discussion/" + this.rowId_s;
|
||||
$.ajax({
|
||||
context: this,
|
||||
// dataType: "json",
|
||||
url: path_s,
|
||||
type: 'DELETE'
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
$('#d' + this.rowId_s + ' .clName').text('>>Gelöscht durch ' + $('#d' + this.rowId_s + ' .clOwner').text() + '<<');
|
||||
$('.clSelected').removeClass('clSelected');
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussionList', this.tId]);
|
||||
this.initList_p();
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[ThemenListe] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
alert("Wählen Sie bitte einen Eintrag in der Tabelle aus!");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'editDiscussion':
|
||||
if (this.rowId_s != "") {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussionEdit', this.tId, this.rowId_s]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'back':
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
break;
|
||||
}
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
},
|
||||
|
||||
|
||||
getContentFromEditForm_p: function () {
|
||||
return content_o = {
|
||||
'title': $('#idDiscussionFormEdit #edittitle_s').text(),
|
||||
'username': FORUM.user_o.name_s,
|
||||
'userid': FORUM.user_o.id_s
|
||||
}
|
||||
},
|
||||
storeContentToEditForm_p: function () {
|
||||
content_s = $('#idDiscussionList .clSelected #idDiscussionTitle').text();
|
||||
|
||||
$('#idDiscussionDetailContentHeader #edittitle_s').text(content_s);
|
||||
},
|
||||
onClickList_p: function (event_opl) {
|
||||
this.initList_p();
|
||||
|
||||
if ($(event_opl.target).parent().attr('id') != 'deleted') {
|
||||
this.rowId_s = $(event_opl.target).parent().attr('id').substring(1);
|
||||
$("#d" + this.rowId_s).addClass("clSelected");
|
||||
|
||||
this.updateButtons_p();
|
||||
}
|
||||
},
|
||||
initialize: function () {
|
||||
var that = this;
|
||||
$.get('/html/list_discussion.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idDiscussionListContent").hide();
|
||||
that.initHandler_p();
|
||||
that.initList_p();
|
||||
});
|
||||
},
|
||||
render_px: function (data_opl) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: '/discussion/' + data_opl,
|
||||
type: 'GET'
|
||||
})
|
||||
.done($.proxy(this.doRender_p, this))
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[Liste] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
},
|
||||
doRender_p: function (data_opl) {
|
||||
var unsorted = {};
|
||||
var sorted = [];
|
||||
for (key in data_opl['data']) {
|
||||
var lowest = parseInt(data_opl['data'][key]['posts'][0])
|
||||
for (lower in data_opl['data'][key]['posts']) {
|
||||
if (parseInt(data_opl['data'][key]['posts'][lower]) < lowest) {
|
||||
lowest = parseInt(data_opl['data'][key]['posts'][lower]);
|
||||
}
|
||||
}
|
||||
unsorted[lowest.toString()] = key;
|
||||
sorted.push(lowest);
|
||||
}
|
||||
sorted.sort(function (a, b) { return a - b; });
|
||||
for (key in sorted) {
|
||||
sorted[key] = unsorted[sorted[parseInt(key)]];
|
||||
}
|
||||
data_opl['indices'] = sorted;
|
||||
|
||||
var rows_s = FORUM.tm_o.execute_px('list_discussion.tpl', data_opl);
|
||||
this.tId = data_opl['tId'];
|
||||
this.initList_p();
|
||||
|
||||
$("#idDiscussionList tbody tr[class!='listheader']").remove();
|
||||
$("#idDiscussionList tbody").append(rows_s);
|
||||
$("#idDiscussionListContent").show();
|
||||
console.log("[ListView_cl] doRender");
|
||||
this.updateButtons_p();
|
||||
},
|
||||
initList_p: function () {
|
||||
$(".clSelected").removeClass("clSelected");
|
||||
this.rowId_s = '';
|
||||
this.updateButtons_p();
|
||||
},
|
||||
initHandler_p: function () {
|
||||
$("#idDiscussionList").on("click", "td", $.proxy(this.onClickList_p, this));
|
||||
$("#idDiscussionListContent").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
},
|
||||
enableButtons_p: function () {
|
||||
|
||||
$("#idDiscussionListContent .clButtonArea button[data-action=back]").prop("disabled", false);
|
||||
|
||||
if (FORUM.user_o.loggedin) {
|
||||
this.enableAddButton_p();
|
||||
}
|
||||
if (this.rowId_s != '') {
|
||||
this.enableViewButton_p();
|
||||
}
|
||||
if (this.rowId_s != '' && FORUM.user_o.loggedin && $("#d" + this.rowId_s + " .clOwner").text() == FORUM.user_o.name_s) {
|
||||
this.enableEditButtons_p();
|
||||
}
|
||||
},
|
||||
enableViewButton_p: function () {
|
||||
$("#idDiscussionListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "discussion") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
enableAddButton_p: function () {
|
||||
$("#idDiscussionListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "addDiscussion") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
enableEditButtons_p: function () {
|
||||
$("#idDiscussionListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "deleteDiscussion" || $(this).attr("data-action") == "editDiscussion") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateButtons_p: function () {
|
||||
$("#idDiscussionListContent .clButtonArea button").each(function () {
|
||||
$(this).prop("disabled", true);
|
||||
});
|
||||
this.enableButtons_p();
|
||||
},
|
||||
canClose_px: function () {
|
||||
return true;
|
||||
},
|
||||
close_px: function () {
|
||||
this.updateButtons_p();
|
||||
$('.clSelected').removeClass("clSelected");
|
||||
|
||||
$("#idDiscussionListContent").hide();
|
||||
}
|
||||
});
|
||||
// EOF
|
191
Sammlung/Praktikum/4/js/list_post.js
Normal file
191
Sammlung/Praktikum/4/js/list_post.js
Normal file
@ -0,0 +1,191 @@
|
||||
// ----------------------------------------------
|
||||
// list_post.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.PostListView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
onClickButtons_p: function (event_opl) {
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
switch (action_s) {
|
||||
|
||||
case 'addPost':
|
||||
FORUM.es_o.publish_px('ContentChanged', ['postEdit', this.tId, this.dId, 0]);
|
||||
break;
|
||||
|
||||
case 'post':
|
||||
if (this.rowId_s != "") {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['post', this.tId, this.dId, this.rowId_s]);
|
||||
this.updateButtons_p();
|
||||
} else {
|
||||
alert("Wählen Sie bitte einen Eintrag in der Tabelle aus!");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'deletePost':
|
||||
if (this.rowId_s != "") {
|
||||
if (confirm("Soll der Datensatz gelöscht werden?")) {
|
||||
var path_s = "/post/" + this.rowId_s;
|
||||
$.ajax({
|
||||
context: this,
|
||||
// dataType: "json",
|
||||
url: path_s,
|
||||
type: 'DELETE'
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
$('#p' + this.rowId_s + ' .clName').text('>>Gelöscht durch ' + $('#p' + this.rowId_s + ' .clOwner').text() + '<<');
|
||||
$('.clSelected').removeClass('clSelected');
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussion', this.tId, this.dId]);
|
||||
this.initList_p();
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[ThemenListe] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
alert("Wählen Sie bitte einen Eintrag in der Liste aus!");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'editPost':
|
||||
if (this.rowId_s != "") {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['postEdit', this.tId, this.dId, this.rowId_s]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'back':
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussionList', this.tId]);
|
||||
break;
|
||||
}
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
},
|
||||
|
||||
|
||||
getContentFromEditForm_p: function () {
|
||||
return content_o = {
|
||||
'title': $('#idPostFormEdit #edittitle_s').text(),
|
||||
'username': FORUM.user_o.name_s,
|
||||
'userid': FORUM.user_o.id_s
|
||||
}
|
||||
},
|
||||
storeContentToEditForm_p: function () {
|
||||
content_s = $('#p' + this.rowId_s + ' #idPostTitle').text();
|
||||
|
||||
$('#idPostDetailContentHeader #edittitle_s').text(content_s);
|
||||
},
|
||||
onClickList_p: function (event_opl) {
|
||||
this.initList_p();
|
||||
|
||||
if ($(event_opl.target).parent().parent().parent().attr('id') != 'deleted') {
|
||||
this.rowId_s = $(event_opl.target).parent().parent().parent().attr('id').substring(1);
|
||||
$("#p" + this.rowId_s).addClass("clSelected");
|
||||
|
||||
this.updateButtons_p();
|
||||
}
|
||||
},
|
||||
initialize: function () {
|
||||
var that = this;
|
||||
$.get('/html/list_post.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idPostListContent").hide();
|
||||
that.initHandler_p();
|
||||
that.initList_p();
|
||||
});
|
||||
},
|
||||
render_px: function (data_opl) {
|
||||
$("#pEditTitle").val('');
|
||||
$("#pEditText").val('');
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: '/post/' + data_opl[0] + '/' + data_opl[1],
|
||||
type: 'GET'
|
||||
})
|
||||
.done($.proxy(this.doRender_p, this))
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[Liste] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
},
|
||||
doRender_p: function (data_opl) {
|
||||
var sorted = [];
|
||||
for (key in data_opl['data']) {
|
||||
if (data_opl['data'][key] != 'nextID') {
|
||||
sorted.push(key);
|
||||
}
|
||||
}
|
||||
sorted.sort(function (a, b) { return a - b; });
|
||||
data_opl['indices'] = sorted;
|
||||
|
||||
var rows_s = FORUM.tm_o.execute_px('list_post.tpl', data_opl);
|
||||
this.tId = data_opl['tId'];
|
||||
this.dId = data_opl['dId'];
|
||||
this.initList_p();
|
||||
|
||||
$("#idPostList li").remove();
|
||||
$("#idPostList").append(rows_s);
|
||||
$("#idPostList li:last-of-type").addClass("newest");
|
||||
$("#idPostListContent").show();
|
||||
console.log("[PostListView_cl] doRender");
|
||||
this.updateButtons_p();
|
||||
},
|
||||
initList_p: function () {
|
||||
$(".clSelected").removeClass("clSelected");
|
||||
this.rowId_s = '';
|
||||
this.updateButtons_p();
|
||||
},
|
||||
initHandler_p: function () {
|
||||
$("#idPostList").on("click", ".clPostContainer", $.proxy(this.onClickList_p, this));
|
||||
$("#idPostListContent").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
},
|
||||
enableButtons_p: function () {
|
||||
|
||||
$("#idPostListContent .clButtonArea button[data-action=back]").prop("disabled", false);
|
||||
|
||||
if (FORUM.user_o.loggedin) {
|
||||
this.enableAddButton_p();
|
||||
}
|
||||
if (this.rowId_s != '') {
|
||||
this.enableViewButton_p();
|
||||
}
|
||||
if (this.rowId_s != '' && FORUM.user_o.loggedin && $("#p" + this.rowId_s + " .clOwner").text() == FORUM.user_o.name_s && $("#p" + this.rowId_s).attr('class') == "newest clSelected") {
|
||||
this.enableEditButtons_p();
|
||||
}
|
||||
},
|
||||
enableViewButton_p: function () {
|
||||
$("#idPostListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "post") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
enableAddButton_p: function () {
|
||||
$("#idPostListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "addPost") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
enableEditButtons_p: function () {
|
||||
$("#idPostListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "deletePost" || $(this).attr("data-action") == "editPost") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateButtons_p: function () {
|
||||
$("#idPostListContent .clButtonArea button").each(function () {
|
||||
$(this).prop("disabled", true);
|
||||
});
|
||||
this.enableButtons_p();
|
||||
},
|
||||
canClose_px: function () {
|
||||
return true;
|
||||
},
|
||||
close_px: function () {
|
||||
this.updateButtons_p();
|
||||
$('.clSelected').removeClass("clSelected");
|
||||
$("#idPostList li").remove();
|
||||
$("#idPostListContent").hide();
|
||||
}
|
||||
});
|
||||
// EOF
|
190
Sammlung/Praktikum/4/js/list_topic.js
Normal file
190
Sammlung/Praktikum/4/js/list_topic.js
Normal file
@ -0,0 +1,190 @@
|
||||
// ----------------------------------------------
|
||||
// list_topic.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.TopicListView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
onClickButtons_p: function (event_opl) {
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
switch (action_s) {
|
||||
|
||||
case 'addTopic':
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicEdit', 0]);
|
||||
break;
|
||||
|
||||
|
||||
case 'discussionList':
|
||||
if (this.rowId_s != "") {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussionList', this.rowId_s]);
|
||||
this.updateButtons_p();
|
||||
} else {
|
||||
alert("Wählen Sie bitte einen Eintrag in der Tabelle aus!");
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'deleteTopic':
|
||||
if (this.rowId_s != "") {
|
||||
if (confirm("Soll der Datensatz gelöscht werden?")) {
|
||||
var path_s = "/topic/" + this.rowId_s;
|
||||
$.ajax({
|
||||
context: this,
|
||||
// dataType: "json",
|
||||
url: path_s,
|
||||
type: 'DELETE'
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
$('#t' + this.rowId_s + ' .clName').text('>>Gelöscht durch ' + $('#t' + this.rowId_s + ' .clOwner').text() + '<<');
|
||||
$('.clSelected').removeClass('clSelected');
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
this.initList_p();
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[ThemenListe] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
alert("Wählen Sie bitte einen Eintrag in der Tabelle aus!");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'editTopic':
|
||||
if (this.rowId_s != "") {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicEdit', this.rowId_s]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
},
|
||||
|
||||
|
||||
getContentFromEditForm_p: function () {
|
||||
return content_o = {
|
||||
'title': $('#idTopicFormEdit #edittitle_s').text(),
|
||||
'username': FORUM.user_o.name_s,
|
||||
'userid': FORUM.user_o.id_s
|
||||
}
|
||||
},
|
||||
storeContentToEditForm_p: function () {
|
||||
content_s = $('#idTopicList .clSelected #idTopicTitle').text();
|
||||
|
||||
$('#idTopicDetailContentHeader #edittitle_s').text(content_s);
|
||||
},
|
||||
onClickList_p: function (event_opl) {
|
||||
this.initList_p();
|
||||
|
||||
if ($(event_opl.target).parent().attr('id') != 'deleted') {
|
||||
this.rowId_s = $(event_opl.target).parent().attr('id').substring(1);
|
||||
$("#t" + this.rowId_s).addClass("clSelected");
|
||||
|
||||
this.updateButtons_p();
|
||||
}
|
||||
},
|
||||
initialize: function () {
|
||||
var that = this;
|
||||
$.get('/html/list_topic.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idTopicListContent").hide();
|
||||
that.initHandler_p();
|
||||
that.initList_p();
|
||||
});
|
||||
},
|
||||
render_px: function (data_opl) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: '/topic',
|
||||
type: 'GET'
|
||||
})
|
||||
.done($.proxy(this.doRender_p, this))
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[Liste] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
},
|
||||
doRender_p: function (data_opl) {
|
||||
var unsorted = [];
|
||||
var sorted = [];
|
||||
for (key in data_opl['data']) {
|
||||
if (data_opl['data'][key] != 'nextID') {
|
||||
unsorted.push(data_opl['data'][key]['name']);
|
||||
}
|
||||
}
|
||||
unsorted.sort();
|
||||
for (key in unsorted) {
|
||||
for (key2 in data_opl['data']) {
|
||||
if (key2 != 'nextID' && unsorted[key] == data_opl['data'][key2]['name']) {
|
||||
sorted.push(key2);
|
||||
}
|
||||
}
|
||||
}
|
||||
data_opl['indices'] = sorted;
|
||||
|
||||
var rows_s = FORUM.tm_o.execute_px('list_topic.tpl', data_opl);
|
||||
this.initList_p();
|
||||
|
||||
$("#idTopicList tbody tr[class!='listheader']").remove();
|
||||
$("#idTopicList tbody").append(rows_s);
|
||||
$("#idTopicListContent").show();
|
||||
console.log("[TopicListView_cl] doRender");
|
||||
this.updateButtons_p();
|
||||
},
|
||||
initList_p: function () {
|
||||
$(".clSelected").removeClass("clSelected");
|
||||
this.rowId_s = '';
|
||||
this.updateButtons_p();
|
||||
},
|
||||
initHandler_p: function () {
|
||||
$("#idTopicList").on("click", "td", $.proxy(this.onClickList_p, this));
|
||||
$("#idTopicListContent .clButtonArea").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
},
|
||||
enableButtons_p: function () {
|
||||
|
||||
if (FORUM.user_o.loggedin) {
|
||||
this.enableAddButton_p();
|
||||
}
|
||||
if (this.rowId_s != '') {
|
||||
this.enableViewButton_p();
|
||||
}
|
||||
if (this.rowId_s != '' && FORUM.user_o.loggedin && $("#t" + this.rowId_s + " .clOwner").text() == FORUM.user_o.name_s) {
|
||||
this.enableEditButtons_p();
|
||||
}
|
||||
},
|
||||
enableViewButton_p: function () {
|
||||
$("#idTopicListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "discussionList") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
enableAddButton_p: function () {
|
||||
$("#idTopicListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "addTopic") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
enableEditButtons_p: function () {
|
||||
$("#idTopicListContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "deleteTopic" || $(this).attr("data-action") == "editTopic") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateButtons_p: function () {
|
||||
$("#idTopicListContent .clButtonArea button").each(function () {
|
||||
$(this).prop("disabled", true);
|
||||
});
|
||||
this.enableButtons_p();
|
||||
},
|
||||
canClose_px: function () {
|
||||
return true;
|
||||
},
|
||||
close_px: function () {
|
||||
this.updateButtons_p();
|
||||
$('.clSelected').removeClass("clSelected");
|
||||
|
||||
$("#idTopicListContent").hide();
|
||||
}
|
||||
});
|
||||
// EOF
|
135
Sammlung/Praktikum/4/js/login.js
Normal file
135
Sammlung/Praktikum/4/js/login.js
Normal file
@ -0,0 +1,135 @@
|
||||
// ----------------------------------------------
|
||||
// login.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.LoginView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
initialize: function () {
|
||||
|
||||
var that = this;
|
||||
$.get('/html/login.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idLoginContent").hide();
|
||||
that.initHandler_p();
|
||||
});
|
||||
FORUM.es_o.subscribe_px(this, 'loginform');
|
||||
|
||||
},
|
||||
|
||||
notify_px: function (self_opl, message_spl, data_apl) {
|
||||
switch (message_spl) {
|
||||
case 'loginform':
|
||||
switch (data_apl[0]) {
|
||||
case 'refresh':
|
||||
self_opl.render_px(null);
|
||||
break;
|
||||
default:
|
||||
console.warning('[LoginView_cl] unbekannte list-Notification: ' + data_apl[0]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warning('[LoginView_cl] unbekannte Notification: ' + message_spl);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
canClose_px: function () {
|
||||
return true;
|
||||
},
|
||||
|
||||
close_px: function () {
|
||||
$("#idLoginContent").hide();
|
||||
},
|
||||
|
||||
render_px: function (data_opl) {
|
||||
this.doRender_p();
|
||||
},
|
||||
|
||||
doRender_p: function () {
|
||||
$("#idLoginContent").show();
|
||||
console.log("[LoginView_cl] doRender");
|
||||
},
|
||||
|
||||
initHandler_p: function () {
|
||||
$("#idLoginContent #idButtonArea").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
},
|
||||
|
||||
onClickButtons_p: function (event_opl) {
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
|
||||
data_o = {
|
||||
"username": $("#idLoginContent #username").val(),
|
||||
"password": $("#idLoginContent #password").val()
|
||||
}
|
||||
switch (action_s) {
|
||||
case 'login':
|
||||
$.ajax({
|
||||
data: data_o,
|
||||
dataType: "json",
|
||||
url: '/login/',
|
||||
type: 'GET'
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
if (data_opl) {
|
||||
FORUM.user_o.login(data_o);
|
||||
alert("Sie sind eingeloggt als \"" + data_o['username'] + "\"")
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
}
|
||||
else {
|
||||
alert("Die Login-Daten sind nicht korrekt!");
|
||||
}
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert( "Fehler bei Anforderung: " + textStatus_spl );
|
||||
});
|
||||
break;
|
||||
case 'register':
|
||||
$.ajax({
|
||||
data: data_o,
|
||||
dataType: "json",
|
||||
url: '/login/',
|
||||
type: 'PUT'
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
if (data_opl) {
|
||||
FORUM.user_o.login(data_o);
|
||||
alert("Sie sind registriert als \"" + data_o['username'] + "\"")
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
}
|
||||
else {
|
||||
alert("Der Benutzername ist leider schon vergeben!");
|
||||
}
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
break;
|
||||
case 'back':
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
break;
|
||||
}
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
},
|
||||
|
||||
enableButtons_p: function () {
|
||||
$("#idLoginContent #idButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") != "add") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
disableButtons_p: function () {
|
||||
$("#idLoginContent #idButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") != "add") {
|
||||
$(this).prop("disabled", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// EOF
|
29
Sammlung/Praktikum/4/js/nav.js
Normal file
29
Sammlung/Praktikum/4/js/nav.js
Normal file
@ -0,0 +1,29 @@
|
||||
// ----------------------------------------------
|
||||
// litnav.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.Nav_cl = Class.create({
|
||||
|
||||
// ----------------------------------------------
|
||||
initialize: function () {
|
||||
this.render_px();
|
||||
this.initHandler_p();
|
||||
},
|
||||
|
||||
render_px: function (data_opl) {
|
||||
$('#idNav .clLinkToLogout').hide();
|
||||
},
|
||||
|
||||
initHandler_p: function () {
|
||||
$("#idNav").on("click", "a", function (event_opl) {
|
||||
var action_s = $(event_opl.target).attr('data-action');
|
||||
FORUM.es_o.publish_px('ContentChanged', [action_s, null]);
|
||||
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// EOF
|
124
Sammlung/Praktikum/4/js/post.js
Normal file
124
Sammlung/Praktikum/4/js/post.js
Normal file
@ -0,0 +1,124 @@
|
||||
// ----------------------------------------------
|
||||
// list_post.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.PostView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
onClickButtons_p: function (event_opl) {
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
switch (action_s) {
|
||||
case 'deletePost':
|
||||
if (confirm("Soll der Datensatz gelöscht werden?")) {
|
||||
var path_s = "/post/" + this.id_s;
|
||||
$.ajax({
|
||||
context: this,
|
||||
// dataType: "json",
|
||||
url: path_s,
|
||||
type: 'DELETE'
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussion', this.tId, this.dId]);
|
||||
this.initList_p();
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[ThemenListe] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'editPost':
|
||||
FORUM.es_o.publish_px('ContentChanged', ['postEdit', this.tId, this.dId, this.id_s]);
|
||||
break;
|
||||
|
||||
case 'back':
|
||||
FORUM.es_o.publish_px('ContentChanged', ['discussion', this.tId, this.dId]);
|
||||
break;
|
||||
}
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
},
|
||||
storeContentToEditForm_p: function () {
|
||||
content_s = $('#p' + this.rowId_s + ' #idPostTitle').text();
|
||||
|
||||
$('#idPostContentHeader #edittitle_s').text(content_s);
|
||||
},
|
||||
initialize: function () {
|
||||
var that = this;
|
||||
$.get('/html/post.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idPostContent").hide();
|
||||
that.initHandler_p();
|
||||
that.initList_p();
|
||||
});
|
||||
},
|
||||
render_px: function (data_opl) {
|
||||
$("#pEditTitle").val('');
|
||||
$("#pEditText").val('');
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: '/post/' + data_opl[0] + '/' + data_opl[1] + '/' + data_opl[2],
|
||||
type: 'GET'
|
||||
})
|
||||
.done($.proxy(this.doRender_p, this))
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[Liste] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
},
|
||||
doRender_p: function (data_opl) {
|
||||
this.initList_p();
|
||||
|
||||
this.tId = data_opl['tId'];
|
||||
this.dId = data_opl['dId'];
|
||||
this.id_s = data_opl['id'];
|
||||
|
||||
data_o = {};
|
||||
data_o[this.id_s] = data_opl['data'];
|
||||
data_opl['data'] = data_o
|
||||
|
||||
data_opl['indices'] = [this.id_s];
|
||||
var rows_s = FORUM.tm_o.execute_px('list_post.tpl', data_opl);
|
||||
|
||||
$("#idPost li").remove();
|
||||
$("#idPost").append(rows_s);
|
||||
$("#idPostContent").show();
|
||||
console.log("[PostView_cl] doRender");
|
||||
this.updateButtons_p();
|
||||
},
|
||||
initList_p: function () {
|
||||
$(".clSelected").removeClass("clSelected");
|
||||
this.id_s = '';
|
||||
},
|
||||
initHandler_p: function () {
|
||||
$("#idPostContent").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
},
|
||||
enableButtons_p: function () {
|
||||
|
||||
$("#idPostContent .clButtonArea button[data-action=back]").prop("disabled", false);
|
||||
if (FORUM.user_o.loggedin && $("#p" + this.id_s + " .clOwner").text() == FORUM.user_o.name_s) {
|
||||
this.enableEditButtons_p();
|
||||
}
|
||||
},
|
||||
enableEditButtons_p: function () {
|
||||
$("#idPostContent .clButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") == "deletePost" || $(this).attr("data-action") == "editPost") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateButtons_p: function () {
|
||||
$("#idPostContent .clButtonArea button").each(function () {
|
||||
$(this).prop("disabled", true);
|
||||
});
|
||||
this.enableButtons_p();
|
||||
},
|
||||
canClose_px: function () {
|
||||
return true;
|
||||
},
|
||||
close_px: function () {
|
||||
this.updateButtons_p();
|
||||
$("#idPost li").remove();
|
||||
$("#idPostContent").hide();
|
||||
}
|
||||
});
|
||||
// EOF
|
111
Sammlung/Praktikum/4/js/register.js
Normal file
111
Sammlung/Praktikum/4/js/register.js
Normal file
@ -0,0 +1,111 @@
|
||||
// ----------------------------------------------
|
||||
// register.js
|
||||
// ----------------------------------------------
|
||||
|
||||
// ----------------------------------------------
|
||||
FORUM.RegisterView_cl = Class.create({
|
||||
// ----------------------------------------------
|
||||
initialize: function () {
|
||||
var that = this;
|
||||
$.get('/html/register.html', function (data_spl) {
|
||||
$("#idContentOuter").append(data_spl);
|
||||
$("#idRegisterContent").hide();
|
||||
that.initHandler_p();
|
||||
});
|
||||
FORUM.es_o.subscribe_px(this, 'register');
|
||||
},
|
||||
|
||||
notify_px: function (self_opl, message_spl, data_apl) {
|
||||
switch (message_spl) {
|
||||
case 'register':
|
||||
switch (data_apl[0]) {
|
||||
case 'refresh':
|
||||
self_opl.render_px(null);
|
||||
break;
|
||||
default:
|
||||
console.warning('[RegisterView_cl] unbekannte list-Notification: ' + data_apl[0]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warning('[RegisterView_cl] unbekannte Notification: ' + message_spl);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
canClose_px: function () {
|
||||
return true;
|
||||
},
|
||||
|
||||
close_px: function () {
|
||||
$("#idRegisterContent").hide();
|
||||
},
|
||||
|
||||
render_px: function (data_opl) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: '/register',
|
||||
type: 'GET'
|
||||
})
|
||||
.done($.proxy(this.doRender_p, this))
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert("[Register] Fehler bei Anforderung: " + textStatus_spl);
|
||||
});
|
||||
},
|
||||
|
||||
doRender_p: function (data_opl) {
|
||||
$("#idRegisterContent").show();
|
||||
console.log("[RegisterView_cl] doRender");
|
||||
},
|
||||
|
||||
initHandler_p: function () {
|
||||
$("#idRegisterContent #idButtonArea").on("click", "button", $.proxy(this.onClickButtons_p, this));
|
||||
|
||||
},
|
||||
|
||||
onClickButtons_p: function (event_opl) {
|
||||
|
||||
var action_s = $(event_opl.target).attr("data-action");
|
||||
|
||||
switch (action_s) {
|
||||
case 'registerme':
|
||||
var data_s = $("#idForm").serialize();
|
||||
alert(data_s);
|
||||
$.ajax({
|
||||
context: this,
|
||||
data: data_s,
|
||||
url: '/register',
|
||||
type: 'PUT'
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
alert("Speichern ausgeführt!");
|
||||
})
|
||||
.fail(function (jqXHR_opl, textStatus_spl) {
|
||||
alert( "Fehler bei Anforderung: " + textStatus_spl );
|
||||
});
|
||||
FORUM.es_o.publish_px('app', [action_s, null]);
|
||||
break;
|
||||
}
|
||||
event_opl.stopPropagation();
|
||||
event_opl.preventDefault();
|
||||
|
||||
},
|
||||
|
||||
enableButtons_p: function () {
|
||||
$("#idRegisterContent #idButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") != "add") {
|
||||
$(this).prop("disabled", false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
disableButtons_p: function () {
|
||||
$("#idRegisterContent #idButtonArea button").each(function () {
|
||||
if ($(this).attr("data-action") != "add") {
|
||||
$(this).prop("disabled", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// EOF
|
308
Sammlung/Praktikum/4/js/te.js
Normal file
308
Sammlung/Praktikum/4/js/te.js
Normal file
@ -0,0 +1,308 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Template-Engine
|
||||
//------------------------------------------------------------------------------
|
||||
// depends-on:
|
||||
// inheritance
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// String-Methoden ergänzen
|
||||
|
||||
APPCO = {};
|
||||
|
||||
APPCO.apply = function(o, c, defaults){
|
||||
// no "this" reference for friendly out of scope calls
|
||||
if (defaults) {
|
||||
APPCO.apply(o, defaults);
|
||||
}
|
||||
if (o && c && typeof c == 'object') {
|
||||
for (var p in c) {
|
||||
o[p] = c[p];
|
||||
}
|
||||
}
|
||||
return o;
|
||||
};
|
||||
|
||||
// quick and dirty! Manche Autoren lehnen solche Erweiterungen ab
|
||||
|
||||
APPCO.apply(String.prototype, {
|
||||
include: function (pattern) {
|
||||
return this.indexOf(pattern) > -1;
|
||||
},
|
||||
startsWith: function (pattern) {
|
||||
return this.lastIndexOf(pattern, 0) === 0;
|
||||
},
|
||||
endsWith: function (pattern) {
|
||||
var d = this.length - pattern.length;
|
||||
return d >= 0 && this.indexOf(pattern, d) === d;
|
||||
}
|
||||
});
|
||||
|
||||
APPCO.apply(String, {
|
||||
interpret: function(value) {
|
||||
return value == null ? '' : String(value);
|
||||
}
|
||||
});
|
||||
|
||||
// Namensraum
|
||||
|
||||
var TELIB = {};
|
||||
|
||||
TELIB.Generator_cl = Class.create({
|
||||
initialize: function () {
|
||||
this.reset_px();
|
||||
},
|
||||
reset_px: function () {
|
||||
this.code_a = ['var result_a = [];\n'];
|
||||
},
|
||||
write_px: function (text_spl) {
|
||||
// Escape-Zeichen bei Strings ergänzen
|
||||
var text_s = text_spl.replace(/"/g, '\\"');
|
||||
text_s = text_s.replace(/'/g, "\\'");
|
||||
this.code_a.push('result_a.push("' + text_s + '");\n');
|
||||
},
|
||||
code_px: function (code_spl) {
|
||||
if (code_spl.startsWith('if')) {
|
||||
this.code_a.push('if (' + code_spl.substr(2) + ') {\n');
|
||||
} else if (code_spl.startsWith('else')) {
|
||||
this.code_a.push('} else {\n');
|
||||
} else if (code_spl.startsWith('endif')) {
|
||||
this.code_a.push('}\n');
|
||||
} else if (code_spl.startsWith('for')) {
|
||||
this.code_a.push('for (' + code_spl.substr(3) + ') {\n');
|
||||
} else if (code_spl.startsWith('endfor')) {
|
||||
this.code_a.push('}\n');
|
||||
} else {
|
||||
this.code_a.push(code_spl + '\n');
|
||||
}
|
||||
},
|
||||
substitute_px: function (subst_spl) {
|
||||
this.code_a.push('result_a.push(' + String.interpret(subst_spl) + ');\n');
|
||||
},
|
||||
generate_px: function () {
|
||||
var result_s = this.code_a.join('') + ' return result_a.join("");';
|
||||
var f_o = new Function ('context', result_s);
|
||||
return f_o;
|
||||
}
|
||||
});
|
||||
|
||||
TELIB.TemplateCompiler_cl = Class.create({
|
||||
initialize: function () {
|
||||
this.gen_o = new TELIB.Generator_cl();
|
||||
this.reset_px();
|
||||
},
|
||||
reset_px: function () {
|
||||
this.gen_o.reset_px();
|
||||
this.preservePreWS_b = false;
|
||||
this.preservePostWS_b = false;
|
||||
},
|
||||
setPreWS_px: function (on_bpl) {
|
||||
if ((on_bpl == undefined) || (on_bpl == false)) {
|
||||
this.preservePreWS_b = false;
|
||||
} else {
|
||||
this.preservePreWS_b = true;
|
||||
}
|
||||
},
|
||||
setPostWS_px: function (on_bpl) {
|
||||
if ((on_bpl == undefined) || (on_bpl == false)) {
|
||||
this.preservePostWS_b = false;
|
||||
} else {
|
||||
this.preservePostWS_b = true;
|
||||
}
|
||||
},
|
||||
compile_px: function (source_spl) {
|
||||
var state_i = 0;
|
||||
var pos_i = 0;
|
||||
var len_i = source_spl.length;
|
||||
var text_s = '';
|
||||
var code_s = '';
|
||||
var subst_s = '';
|
||||
this.gen_o.reset_px();
|
||||
|
||||
var doubletest_f = function (char_spl) {
|
||||
var status_b = false;
|
||||
if ((pos_i + 1) < len_i) {
|
||||
if ((source_spl[pos_i] == char_spl) && (source_spl[pos_i+1] == char_spl)) {
|
||||
status_b = true;
|
||||
}
|
||||
}
|
||||
return status_b;
|
||||
}
|
||||
|
||||
while (pos_i < len_i) {
|
||||
switch (state_i) {
|
||||
case 0:
|
||||
// outside
|
||||
if (source_spl[pos_i] == '@') { // ECMA 5!
|
||||
if (doubletest_f('@') == false) {
|
||||
state_i = 2;
|
||||
code_s = '';
|
||||
} else {
|
||||
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
||||
state_i = 1;
|
||||
text_s = '@';
|
||||
pos_i++;
|
||||
}
|
||||
} else if (source_spl[pos_i] == '#') {
|
||||
if (doubletest_f('#') == false) {
|
||||
state_i = 3;
|
||||
subst_s = '';
|
||||
} else {
|
||||
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
||||
state_i = 1;
|
||||
text_s = '#';
|
||||
pos_i++;
|
||||
}
|
||||
} else if ((source_spl[pos_i] == ' ') || (source_spl[pos_i] == '\t')) {
|
||||
state_i = 4;
|
||||
text_s = '';
|
||||
pos_i--; // Zeichen erneut verarbeiten
|
||||
} else {
|
||||
state_i = 1;
|
||||
text_s = '';
|
||||
pos_i--; // Zeichen erneut verarbeiten
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// inText
|
||||
if (source_spl[pos_i] == '@') {
|
||||
if (doubletest_f('@') == false) {
|
||||
// Textende, neuer Code
|
||||
state_i = 0;
|
||||
this.gen_o.write_px(text_s);
|
||||
pos_i--; // Zeichen erneut verarbeiten
|
||||
} else {
|
||||
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
||||
text_s += '@';
|
||||
pos_i++;
|
||||
}
|
||||
} else if (source_spl[pos_i] == '#') {
|
||||
if (doubletest_f('#') == false) {
|
||||
// Textende, neue Substitution
|
||||
state_i = 0;
|
||||
this.gen_o.write_px(text_s);
|
||||
pos_i--; // Zeichen erneut verarbeiten
|
||||
// Textende, neuer Code
|
||||
} else {
|
||||
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
||||
text_s += '#';
|
||||
pos_i++;
|
||||
}
|
||||
} else if ((source_spl[pos_i] == ' ') || (source_spl[pos_i] == '\t')) {
|
||||
// Textende
|
||||
state_i = 0;
|
||||
this.gen_o.write_px(text_s);
|
||||
pos_i--; // Zeichen erneut verarbeiten
|
||||
} else {
|
||||
// sammeln
|
||||
if ((source_spl[pos_i] != '\n') && (source_spl[pos_i] != '\r')) {
|
||||
text_s += source_spl[pos_i];
|
||||
} else if (source_spl[pos_i] == '\n') {
|
||||
text_s += '\\n';
|
||||
} else {
|
||||
text_s += '\\r';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// inCode
|
||||
if (source_spl[pos_i] == '@') {
|
||||
if (doubletest_f('@') == false) {
|
||||
// zu Ende, erzeugen
|
||||
this.gen_o.code_px(code_s);
|
||||
state_i = 5; //0
|
||||
} else {
|
||||
// als normales Zeichen verarbeiten, ein Zeichen überlesen
|
||||
code_s += '@';
|
||||
pos_i++;
|
||||
}
|
||||
} else {
|
||||
// sammeln
|
||||
code_s += source_spl[pos_i];
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// inSubst
|
||||
// Verdopplung # hier nicht zulässig!
|
||||
if (source_spl[pos_i] == '#') {
|
||||
// zu Ende, erzeugen
|
||||
this.gen_o.substitute_px(subst_s);
|
||||
state_i = 0;
|
||||
} else {
|
||||
// sammeln
|
||||
subst_s += source_spl[pos_i];
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// pre-code-whitespace
|
||||
switch (source_spl[pos_i]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
// sammeln
|
||||
text_s += source_spl[pos_i];
|
||||
break;
|
||||
default:
|
||||
state_i = 0;
|
||||
if (source_spl[pos_i] != '@') {
|
||||
this.gen_o.write_px(text_s);
|
||||
} else {
|
||||
if (doubletest_f('@') == false) {
|
||||
// Whitespace vor Code-Beginn erkannt
|
||||
if (this.preservePreWS_b == true) {
|
||||
// trotzdem ausgeben
|
||||
this.gen_o.write_px(text_s);
|
||||
}
|
||||
} // ansonsten wie normales Zeichen behandeln
|
||||
}
|
||||
pos_i--; // Zeichen erneut verarbeiten
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
// post-code-whitespace
|
||||
switch (source_spl[pos_i]) {
|
||||
case '\n':
|
||||
text_s += '\\n';
|
||||
state_i = 0;
|
||||
break;
|
||||
case '\r':
|
||||
text_s += '\\r';
|
||||
state_i = 0;
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
// ggf. sammeln
|
||||
text_s += source_spl[pos_i];
|
||||
break;
|
||||
default:
|
||||
// Whitespace nach Code erkannt
|
||||
if (this.preservePostWS_b == true) {
|
||||
// trotzdem ausgeben
|
||||
this.gen_o.write_px(text_s);
|
||||
}
|
||||
state_i = 0;
|
||||
pos_i--; // Zeichen erneut verarbeiten
|
||||
}
|
||||
break;
|
||||
}
|
||||
pos_i++;
|
||||
}
|
||||
// welcher Zustand liegt abschließend vor?
|
||||
if (state_i == 1) {
|
||||
this.gen_o.write_px(text_s);
|
||||
} else if (state_i == 2) {
|
||||
this.gen_o.code_px(code_s);
|
||||
} else if (state_i == 3) {
|
||||
this.gen_o.substitute_px(subst_s);
|
||||
} else if (state_i == 4) {
|
||||
if (this.preservePreWS_b == true) {
|
||||
this.gen_o.write_px(text_s);
|
||||
}
|
||||
} else if (state_i == 5) {
|
||||
if (this.preservePostWS_b == true) {
|
||||
this.gen_o.write_px(text_s);
|
||||
}
|
||||
}
|
||||
|
||||
return this.gen_o.generate_px();
|
||||
}
|
||||
});
|
||||
// EOF
|
61
Sammlung/Praktikum/4/js/tm.js
Normal file
61
Sammlung/Praktikum/4/js/tm.js
Normal file
@ -0,0 +1,61 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Template-Manager
|
||||
// - Laden und Bereitstellen von Template-Quellen oder anderen Textquellen
|
||||
//------------------------------------------------------------------------------
|
||||
// depends-on:
|
||||
// jquery
|
||||
// inheritance
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Namensraum TELIB verwenden
|
||||
|
||||
TELIB.TemplateManager_cl = Class.create({
|
||||
initialize: function () {
|
||||
this.templates_o = {};
|
||||
this.compiled_o = {};
|
||||
this.teCompiler_o = new TELIB.TemplateCompiler_cl();
|
||||
// Templates als Ressource anfordern und speichern
|
||||
var path_s = "/template/";
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: path_s,
|
||||
type: 'GET',
|
||||
context: this
|
||||
})
|
||||
.done(function (data_opl) {
|
||||
this.templates_o = data_opl['templates'];
|
||||
// Benachrichtigung senden
|
||||
//+++ Bezeichnung Namensraum korrigieren
|
||||
FORUM.es_o.publish_px('ContentChanged', ['topicList', null]);
|
||||
})
|
||||
.fail(function(jqXHR_opl, textStatus_spl) {
|
||||
alert( "[TELIB.tm] Fehler bei Anforderung: " + textStatus_spl );
|
||||
});
|
||||
},
|
||||
get_px: function (name_spl) {
|
||||
if (name_spl in this.templates_o) {
|
||||
return this.templates_o[name_spl];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
execute_px: function (name_spl, data_opl) {
|
||||
var compiled_o = null;
|
||||
if (name_spl in this.compiled_o) {
|
||||
compiled_o = this.compiled_o[name_spl];
|
||||
} else {
|
||||
// Übersetzen und ausführen
|
||||
if (name_spl in this.templates_o) {
|
||||
this.teCompiler_o.reset_px();
|
||||
compiled_o = this.teCompiler_o.compile_px(this.templates_o[name_spl]);
|
||||
this.compiled_o[name_spl] = compiled_o;
|
||||
}
|
||||
}
|
||||
if (compiled_o != null) {
|
||||
return compiled_o(data_opl);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
// EOF
|
19
Sammlung/Praktikum/4/server.conf
Normal file
19
Sammlung/Praktikum/4/server.conf
Normal file
@ -0,0 +1,19 @@
|
||||
[global]
|
||||
tools.log_headers.on: True
|
||||
tools.sessions.on: False
|
||||
tools.encode.on: True
|
||||
tools.encode.encoding:"utf-8"
|
||||
|
||||
server.socket_port: 8080
|
||||
server.socket_timeout:60
|
||||
|
||||
server.thread_pool: 10
|
||||
server.environment: "production"
|
||||
log.screen: True
|
||||
|
||||
[/]
|
||||
tools.staticdir.root: cherrypy.Application.currentDir_s
|
||||
tools.staticdir.on = True
|
||||
tools.staticdir.dir = '.'
|
||||
tools.staticdir.index = 'html/index.html'
|
||||
|
66
Sammlung/Praktikum/4/server.py
Normal file
66
Sammlung/Praktikum/4/server.py
Normal file
@ -0,0 +1,66 @@
|
||||
# coding:utf-8
|
||||
|
||||
import os.path
|
||||
import cherrypy
|
||||
|
||||
from app import topic, discussion, post, login, template
|
||||
|
||||
#----------------------------------------------------------
|
||||
def main():
|
||||
#----------------------------------------------------------
|
||||
|
||||
# aktuelles Verzeichnis ermitteln, damit es in der Konfigurationsdatei als
|
||||
# Bezugspunkt verwendet werden kann
|
||||
try: # aktuelles Verzeichnis als absoluter Pfad
|
||||
currentDir_s = os.path.dirname(os.path.abspath(__file__))
|
||||
except:
|
||||
currentDir_s = os.path.dirname(os.path.abspath(sys.executable))
|
||||
cherrypy.Application.currentDir_s = currentDir_s
|
||||
|
||||
configFileName_s = 'server.conf' # im aktuellen Verzeichnis
|
||||
if os.path.exists(configFileName_s) == False:
|
||||
# Datei gibt es nicht
|
||||
configFileName_s = None
|
||||
|
||||
# autoreload und timeout_Monitor hier abschalten
|
||||
# für cherrypy-Versionen >= "3.1.0" !
|
||||
cherrypy.engine.autoreload.unsubscribe()
|
||||
cherrypy.engine.timeout_monitor.unsubscribe()
|
||||
|
||||
# Standardverhalten, Berücksichtigung der Konfigurationsangaben im configFile
|
||||
cherrypy.tree.mount(
|
||||
None, '/', configFileName_s
|
||||
)
|
||||
|
||||
# Method-Dispatcher für die "Applikation" "topic" vereinbaren
|
||||
cherrypy.tree.mount(
|
||||
topic.Topic_cl(), '/topic', {'/': {'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}
|
||||
)
|
||||
|
||||
# Method-Dispatcher für die "Applikation" "discussion" vereinbaren
|
||||
cherrypy.tree.mount(
|
||||
discussion.Discussion_cl(), '/discussion', {'/': {'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}
|
||||
)
|
||||
|
||||
# Method-Dispatcher für die "Applikation" "discussion" vereinbaren
|
||||
cherrypy.tree.mount(
|
||||
post.Post_cl(), '/post', {'/': {'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}
|
||||
)
|
||||
|
||||
# Method-Dispatcher für die "Applikation" "login" vereinbaren
|
||||
cherrypy.tree.mount(
|
||||
login.Login_cl(), '/login', {'/': {'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}
|
||||
)
|
||||
|
||||
# Method-Dispatcher für die "Applikation" "template" vereinbaren
|
||||
cherrypy.tree.mount(
|
||||
template.Template_cl(), '/template', {'/': {'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}
|
||||
)
|
||||
|
||||
cherrypy.engine.start()
|
||||
cherrypy.engine.block()
|
||||
|
||||
#----------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
#----------------------------------------------------------
|
||||
main()
|
2
Sammlung/Praktikum/4/start.bat
Normal file
2
Sammlung/Praktikum/4/start.bat
Normal file
@ -0,0 +1,2 @@
|
||||
server.py
|
||||
pause
|
16
Sammlung/Praktikum/4/templates/list_discussion.tpl
Normal file
16
Sammlung/Praktikum/4/templates/list_discussion.tpl
Normal file
@ -0,0 +1,16 @@
|
||||
@var rows_o = context['data'];@
|
||||
@var order = context['indices'];@
|
||||
|
||||
@for var key in order@
|
||||
@if rows_o[order[key]]["deleted"]@
|
||||
<tr id="deleted">
|
||||
<td class="clName">>>Gelöscht durch #rows_o[order[key]]["owner"]#<<</td>
|
||||
@else@
|
||||
<tr id="d#order[key]#">
|
||||
<td class="clName">#rows_o[order[key]]["name"]#</td>
|
||||
@endif@
|
||||
<td class="clOwner">#rows_o[order[key]]["owner"]#</td>
|
||||
</tr>
|
||||
@endfor@
|
||||
|
||||
|
27
Sammlung/Praktikum/4/templates/list_post.tpl
Normal file
27
Sammlung/Praktikum/4/templates/list_post.tpl
Normal file
@ -0,0 +1,27 @@
|
||||
@var rows_o = context['data'];@
|
||||
@var order = context['indices'];@
|
||||
|
||||
@for var key in order@
|
||||
@if rows_o[order[key]]["deleted"]@
|
||||
<li id="deleted">
|
||||
@else@
|
||||
<li id="p#order[key]#">
|
||||
@endif@
|
||||
<div class="clPostContainer">
|
||||
<div class="clMetaDataContainer">
|
||||
<div class="clOwner">#rows_o[order[key]]["owner"]#</div>
|
||||
<div class="clTime">#rows_o[order[key]]["time"][2]#.#rows_o[order[key]]["time"][1]#.#rows_o[order[key]]["time"][0]#<br>
|
||||
#rows_o[order[key]]["time"][3]#:#rows_o[order[key]]["time"][4]#</div>
|
||||
</div>
|
||||
<div class="clPostDataContainer">
|
||||
@if rows_o[order[key]]["deleted"]@
|
||||
<div class="clTitle">>>Gelöscht<<</div>
|
||||
<div class="clText">>>Gelöscht<<</div>
|
||||
@else@
|
||||
<div class="clTitle">#rows_o[order[key]]["title"]#</div>
|
||||
<div class="clText">#rows_o[order[key]]["text"]#</div>
|
||||
@endif@
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endfor@
|
16
Sammlung/Praktikum/4/templates/list_topic.tpl
Normal file
16
Sammlung/Praktikum/4/templates/list_topic.tpl
Normal file
@ -0,0 +1,16 @@
|
||||
@var rows_o = context['data'];@
|
||||
@var order = context['indices'];@
|
||||
|
||||
@for var key in order@
|
||||
@if rows_o[order[key]]["deleted"]@
|
||||
<tr id="deleted">
|
||||
<td class="clName">>>Gelöscht durch #rows_o[order[key]]["owner"]#<<</td>
|
||||
@else@
|
||||
<tr id="t#order[key]#">
|
||||
<td class="clName">#rows_o[order[key]]["name"]#</td>
|
||||
@endif@
|
||||
<td class="clOwner">#rows_o[order[key]]["owner"]#</td>
|
||||
</tr>
|
||||
@endfor@
|
||||
|
||||
|
Reference in New Issue
Block a user