mirror of
https://github.com/ChronosX88/psyced.git
synced 2024-11-09 20:11:00 +00:00
threads web interface improvements, accessible now at /~nick/channel & /@place
This commit is contained in:
parent
bc0b9dd325
commit
a5b52d8264
@ -384,6 +384,12 @@ object compile_object(string file) {
|
|||||||
return rob;
|
return rob;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
if (sscanf(file, "%s/text.c", path) && path != "") {
|
||||||
|
rob = clone_object(NET_PATH "text");
|
||||||
|
rob -> sPath(path);
|
||||||
|
D2(if (rob) PP(("DB CLONED: %O becomes %s/text\n", rob, path));)
|
||||||
|
return rob;
|
||||||
|
}
|
||||||
if (sscanf(file, "place/%s.c", name) && name != "") {
|
if (sscanf(file, "place/%s.c", name) && name != "") {
|
||||||
#ifdef SANDBOX
|
#ifdef SANDBOX
|
||||||
string t;
|
string t;
|
||||||
@ -444,12 +450,6 @@ object compile_object(string file) {
|
|||||||
rob, name, path));)
|
rob, name, path));)
|
||||||
return rob;
|
return rob;
|
||||||
}
|
}
|
||||||
if (sscanf(file, "%s/text.c", path) && path != "") {
|
|
||||||
rob = clone_object(NET_PATH "text");
|
|
||||||
rob -> sPath(path);
|
|
||||||
D2(if (rob) PP(("DB CLONED: %O becomes %s/text\n", rob, path));)
|
|
||||||
return rob;
|
|
||||||
}
|
|
||||||
# ifdef JABBER_PATH
|
# ifdef JABBER_PATH
|
||||||
if (abbrev("S:xmpp:", file)) {
|
if (abbrev("S:xmpp:", file)) {
|
||||||
rob = clone_object(JABBER_PATH "gateway");
|
rob = clone_object(JABBER_PATH "gateway");
|
||||||
|
@ -18,7 +18,7 @@ mapping request_params = ([ ]);
|
|||||||
mapping access_params = ([ ]);
|
mapping access_params = ([ ]);
|
||||||
string access_token_url;
|
string access_token_url;
|
||||||
string authorize_url;
|
string authorize_url;
|
||||||
string callback_url = "http://" + my_lower_case_host() + ":" + HTTP_PORT + "/oauth"; //TODO: https?
|
string callback_url = HTTPS_OR_HTTP_URL + "/oauth";
|
||||||
object user;
|
object user;
|
||||||
|
|
||||||
varargs void fetch(object ua, string url, string method, mapping post, mapping oauth) {
|
varargs void fetch(object ua, string url, string method, mapping post, mapping oauth) {
|
||||||
|
@ -191,15 +191,21 @@ case "/oauth":
|
|||||||
quit();
|
quit();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
string name;
|
||||||
switch (file[1]) {
|
switch (file[1]) {
|
||||||
case '~':
|
case '~':
|
||||||
if (o = summon_person(file[2..], NET_PATH "user")) {
|
string channel, nick = file[2..];
|
||||||
o->htinfo(version, query, headers, qs);
|
if (sscanf(file, "/~%s/%s", nick, channel)) {
|
||||||
|
name = "~" + nick + "#" + channel;
|
||||||
|
} else if (o = summon_person(nick, NET_PATH "user")) {
|
||||||
|
o->htinfo(version, query, headers, qs, channel);
|
||||||
|
quit();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
quit();
|
//fall thru
|
||||||
return 1;
|
|
||||||
case '@':
|
case '@':
|
||||||
file = PLACE_PATH+ lower_case(file[2..]);
|
unless(name) name = file[2..];
|
||||||
|
o = find_place(name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (abbrev("/static/", file)) {
|
if (abbrev("/static/", file)) {
|
||||||
@ -232,7 +238,7 @@ case "/oauth":
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
o = file -> load();
|
unless (o) o = file -> load();
|
||||||
if (objectp(o) || o = find_object(file))
|
if (objectp(o) || o = find_object(file))
|
||||||
done = o->htget(version, query, headers, qs) != HTMORE;
|
done = o->htget(version, query, headers, qs) != HTMORE;
|
||||||
|
|
||||||
|
@ -125,6 +125,9 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define HTTPS_OR_HTTP_URL (HTTPS_URL ? HTTPS_URL : HTTP_URL)
|
||||||
|
#define HTTP_OR_HTTPS_URL (HTTP_URL ? HTTP_URL : HTTPS_URL)
|
||||||
|
|
||||||
#ifdef _uniform_node
|
#ifdef _uniform_node
|
||||||
# define SERVER_UNIFORM _uniform_node
|
# define SERVER_UNIFORM _uniform_node
|
||||||
#else
|
#else
|
||||||
|
@ -477,6 +477,7 @@ qDescription(source, vars, profile, itsme) {
|
|||||||
}
|
}
|
||||||
// don't make_json for anonymous queries which are handled locally
|
// don't make_json for anonymous queries which are handled locally
|
||||||
dv["_channels"] = source ? make_json(channels) : channels;
|
dv["_channels"] = source ? make_json(channels) : channels;
|
||||||
|
dv["_profile_url"] = HTTPS_OR_HTTP_URL + "/~" + MYNICK;
|
||||||
#endif
|
#endif
|
||||||
// PT(("sending: %O\n", dv))
|
// PT(("sending: %O\n", dv))
|
||||||
return dv;
|
return dv;
|
||||||
|
@ -450,6 +450,7 @@ showTopic(rcpt, verbose, mc) {
|
|||||||
|
|
||||||
#if HAS_PORT(HTTP_PORT, HTTP_PATH) || HAS_PORT(HTTPS_PORT, HTTP_PATH)
|
#if HAS_PORT(HTTP_PORT, HTTP_PATH) || HAS_PORT(HTTPS_PORT, HTTP_PATH)
|
||||||
htget(prot, query, headers, qs, data, noprocess) {
|
htget(prot, query, headers, qs, data, noprocess) {
|
||||||
|
//P3((">> archetype.gen:htget(%O, %O, %O, %O, %O, %O)\n", prot, query, headers, qs, data, noprocess))
|
||||||
# ifdef PLACE_SCRATCHPAD
|
# ifdef PLACE_SCRATCHPAD
|
||||||
sTextPath(query["layout"] || MYNICK, query["lang"], "html");
|
sTextPath(query["layout"] || MYNICK, query["lang"], "html");
|
||||||
if (!noprocess && (!qs || query["scratchpad"])) {
|
if (!noprocess && (!qs || query["scratchpad"])) {
|
||||||
|
@ -7,7 +7,11 @@
|
|||||||
inherit NET_PATH "place/owned";
|
inherit NET_PATH "place/owned";
|
||||||
|
|
||||||
#ifndef DEFAULT_BACKLOG
|
#ifndef DEFAULT_BACKLOG
|
||||||
# define DEFAULT_BACKLOG 5
|
# define DEFAULT_BACKLOG 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STYLESHEET
|
||||||
|
# define STYLESHEET (v("_uniform_style") || "/static/examine.css")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// datenstruktur für threads?
|
// datenstruktur für threads?
|
||||||
@ -173,19 +177,6 @@ _request_delentry(source, mc, data, vars, b) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
_request_iterator(source, mc, data, vars, b) {
|
|
||||||
unless (canPost(SNICKER)) return 0;
|
|
||||||
sendmsg(source, "_notice_thread_iterator",
|
|
||||||
"[_iterator] blog entries have been requested "
|
|
||||||
"since creation.", ([
|
|
||||||
// i suppose this wasn't intentionally using
|
|
||||||
// MMP _count so i rename it to _iterator
|
|
||||||
"_iterator" : v("iterator")
|
|
||||||
]) );
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
msg(source, mc, data, vars){
|
msg(source, mc, data, vars){
|
||||||
P3(("thread:msg(%O, %O, %O, %O)", source, mc, data, vars))
|
P3(("thread:msg(%O, %O, %O, %O)", source, mc, data, vars))
|
||||||
// TODO: die source muss hierbei uebereinstimmen mit dem autor
|
// TODO: die source muss hierbei uebereinstimmen mit dem autor
|
||||||
@ -201,63 +192,6 @@ msg(source, mc, data, vars){
|
|||||||
return ::msg(source, mc, data, vars);
|
return ::msg(source, mc, data, vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
listLastEntries(number) {
|
|
||||||
mapping* entries;
|
|
||||||
int i;
|
|
||||||
entries = _thread || ({ });
|
|
||||||
|
|
||||||
unless (sizeof(entries)) return 1;
|
|
||||||
|
|
||||||
i = v("iterator") || 0;
|
|
||||||
vSet("iterator", i + 1);
|
|
||||||
|
|
||||||
return entries[<number..];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if 0
|
|
||||||
allEntries(source) {
|
|
||||||
mapping* entries;
|
|
||||||
mapping ar;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
entries = _thread || ({ });
|
|
||||||
|
|
||||||
unless (sizeof(entries)) return 1;
|
|
||||||
|
|
||||||
foreach (ar : entries) {
|
|
||||||
sendmsg(source, "_message_", "([_id]) \"[_topic]\", [_author]", ([ // ??
|
|
||||||
"_topic" : ar["topic"],
|
|
||||||
"_text" : ar["text"],
|
|
||||||
"_author" : ar["author"],
|
|
||||||
"_date" : ar["date"],
|
|
||||||
"_id" : i++,
|
|
||||||
"_nick_place" : MYNICK ]) );
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
addForum() {
|
|
||||||
// suggested protocol message for the buha forum
|
|
||||||
// (creation of a new thread)
|
|
||||||
|
|
||||||
:_target psyc://psyced.org/@buha
|
|
||||||
:_encoding utf-8
|
|
||||||
|
|
||||||
:_nick_forum morpheus
|
|
||||||
:_category Test-Forum
|
|
||||||
:_thread Test-Thread_
|
|
||||||
:_page_thread https://www.buha.info/board/showthread.php?t=1
|
|
||||||
|
|
||||||
_notice_thread
|
|
||||||
[_nick_forum] hat einen neuen Thread in [_category] erstellt: [_thread] ([_page_thread])
|
|
||||||
.
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
setSubject(id, thread) {
|
setSubject(id, thread) {
|
||||||
unless (_thread && id >= 0 && id <= sizeof(_thread) && _thread[id]) return 0;
|
unless (_thread && id >= 0 && id <= sizeof(_thread) && _thread[id]) return 0;
|
||||||
_thread[id]["thread"] = thread;
|
_thread[id]["thread"] = thread;
|
||||||
@ -336,242 +270,195 @@ delEntry(int id, source, vars) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
htget(prot, query, headers, qs, data) {
|
htget(prot, query, headers, qs, data) {
|
||||||
mapping entrymap;
|
mapping entrymap;
|
||||||
mixed target;
|
mixed target;
|
||||||
string nick;
|
string nick;
|
||||||
int i;
|
int a;
|
||||||
int a;
|
int limit = to_int(query["limit"]) || DEFAULT_BACKLOG;
|
||||||
mapping* entries;
|
int offset = to_int(query["offset"]);
|
||||||
|
|
||||||
int num_entries = query["last"] ? to_int(query["last"]) : DEFAULT_BACKLOG;
|
|
||||||
unless (webact) webact = PLACE_PATH + MYLOWERNICK;
|
|
||||||
// shouldnt it be "html" here?
|
|
||||||
sTextPath(query["layout"] || MYNICK, query["lang"], "ht");
|
|
||||||
|
|
||||||
// Kommentare anzeigen
|
unless (webact) webact = PLACE_PATH + MYLOWERNICK;
|
||||||
if (query["comments"]) {
|
// shouldnt it be "html" here?
|
||||||
htok(prot);
|
sTextPath(query["layout"] || MYNICK, query["lang"], "ht");
|
||||||
// kommentare + urspruengliche Nachricht anzeigen
|
|
||||||
displayHeader();
|
// Kommentare anzeigen
|
||||||
displayComments(_thread[to_int(query["comments"])]);
|
if (query["id"]) {
|
||||||
// eingabeformular ohne betreff
|
htok(prot);
|
||||||
write("<form action='" + webact + "' method='GET'>\n"
|
// kommentare + urspruengliche Nachricht anzeigen
|
||||||
"<input type='hidden' name='request' value='post'>\n"
|
displayHeader();
|
||||||
"PSYC Uni: <input type='text' name='uni'><br>\n"
|
displayEntry(to_int(query["id"]));
|
||||||
"<input type='hidden' name='reply' value='" + query["comments"] +"'>\n"
|
#if 0
|
||||||
"<textarea name='text' rows='14' cols='80'>Enter your text here</textarea><br>\n"
|
// eingabeformular ohne betreff
|
||||||
"<input type='submit' value='submit'>\n"
|
write("<form action='" + webact + "' method='GET'>\n"
|
||||||
"</form>\n");
|
"<input type='hidden' name='request' value='post'>\n"
|
||||||
write("<br><hr><br>");
|
"PSYC Uni: <input type='text' name='uni'><br>\n"
|
||||||
logView(a < 24 ? a : 12, "html", 15);
|
"<input type='hidden' name='reply' value='" + query["comments"] +"'>\n"
|
||||||
displayFooter();
|
"<textarea name='text' rows='14' cols='80'>Enter your text here</textarea><br>\n"
|
||||||
return 1;
|
"<input type='submit' value='submit'>\n"
|
||||||
|
"</form>\n");
|
||||||
|
write("<br><hr><br>");
|
||||||
|
#endif
|
||||||
|
//logView(a < 24 ? a : 12, "html", 15);
|
||||||
|
displayFooter();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// formularbehandlung
|
||||||
|
if (query["request"] == "post" && query["uni"]) {
|
||||||
|
htok(prot);
|
||||||
|
/*
|
||||||
|
sendmsg uni -> _request_authentication mit thread und text drin
|
||||||
|
dann auf die antwort warten die nen vars mapping mit thread + text hat wieder
|
||||||
|
*/
|
||||||
|
if (nick = legal_name(target = query["uni"])) {
|
||||||
|
target = summon_person(nick);
|
||||||
|
nick = target->qNick();
|
||||||
|
} else {
|
||||||
|
nick = target;
|
||||||
|
// write("Hello " + query["uni"] + "<br>\n");
|
||||||
|
// write("Remote auth doesn't work yet. TODO!!!\n");
|
||||||
|
// return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// formularbehandlung
|
|
||||||
if (query["request"] == "post" && query["uni"]) {
|
|
||||||
htok(prot);
|
|
||||||
/*
|
|
||||||
sendmsg uni -> _request_authentication mit thread und text drin
|
|
||||||
dann auf die antwort warten die nen vars mapping mit thread + text hat wieder
|
|
||||||
*/
|
|
||||||
if (nick = legal_name(target = query["uni"])) {
|
|
||||||
target = summon_person(nick);
|
|
||||||
nick = target->qNick();
|
|
||||||
} else {
|
|
||||||
nick = target;
|
|
||||||
// write("Hello " + query["uni"] + "<br>\n");
|
|
||||||
// write("Remote auth doesn't work yet. TODO!!!\n");
|
|
||||||
// return 1;
|
|
||||||
}
|
|
||||||
#ifdef OWNED
|
#ifdef OWNED
|
||||||
if (canPost(nick)) {
|
if (canPost(nick)) {
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
sendmsg(target, "_request_authentication", "please auth me!",
|
sendmsg(target, "_request_authentication", "please auth me!",
|
||||||
(["_host_IP" : query_ip_number(),
|
(["_host_IP" : query_ip_number(),
|
||||||
"_blog_thread" : query["thread"],
|
"_blog_thread" : query["thread"],
|
||||||
"_blog_text" : query["text"] ]));
|
"_blog_text" : query["text"] ]));
|
||||||
write("your submit is avaiting authentication by " + query["uni"] + "<br>\n");
|
write("your submit is avaiting authentication by " + query["uni"] + "<br>\n");
|
||||||
#endif // 0
|
#endif // 0
|
||||||
if (target->checkAuthentication(ME, ([ "_host_IP" : query_ip_number() ]) ) > 0) {
|
if (target->checkAuthentication(ME, ([ "_host_IP" : query_ip_number() ]) ) > 0) {
|
||||||
// check ob reply auf irgendwas ist...
|
// check ob reply auf irgendwas ist...
|
||||||
if (query["reply"]) {
|
if (query["reply"]) {
|
||||||
addComment(query["text"], query["uni"], to_int(query["reply"]));
|
addComment(query["text"], query["uni"], to_int(query["reply"]));
|
||||||
} else {
|
|
||||||
addEntry(query["text"], query["uni"], query["thread"]);
|
|
||||||
}
|
|
||||||
write("authentication successful!\n");
|
|
||||||
} else {
|
} else {
|
||||||
write("not authenticated!\n");
|
addEntry(query["text"], query["uni"], query["thread"]);
|
||||||
}
|
}
|
||||||
|
write("authentication successful!\n");
|
||||||
|
} else {
|
||||||
|
write("not authenticated!\n");
|
||||||
|
}
|
||||||
#ifdef OWNED
|
#ifdef OWNED
|
||||||
} else {
|
|
||||||
write("You are not owner or aide of this place.\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// neuen Eintrag verfassen
|
|
||||||
if (query["request"] == "form") {
|
|
||||||
htok(prot);
|
|
||||||
displayHeader();
|
|
||||||
write("<form action='" + webact + "' method='GET'>\n"
|
|
||||||
"<input type='hidden' name='request' value='post'>\n"
|
|
||||||
"PSYC Identity:<br><input type='text' name='uni' size=60><br>\n"
|
|
||||||
"Thread:<br><input type='text' name='thread' size=60><br>\n"
|
|
||||||
"Text:<br>\n<textarea name='text' rows='14' cols='64'></textarea><br>\n"
|
|
||||||
"<input type='submit' value='CREATE MESSAGE'>\n"
|
|
||||||
"</form>\n");
|
|
||||||
displayFooter();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
::htget(prot, query, headers, qs, data, 1); // no processing, just info
|
|
||||||
// javascript-export
|
|
||||||
if (query["export"] == "javascript") {
|
|
||||||
// check If-Modified-Since header
|
|
||||||
htok3(prot, "application/x-javascript", "Cache-Control: no-cache\n");
|
|
||||||
jscriptExport(num_entries);
|
|
||||||
} else if (query["export"] == "rss" || query["export"] == "rdf") {
|
|
||||||
// export als RSS
|
|
||||||
// scheinbar gibt es ein limit von 15 items / channel
|
|
||||||
// htquote auch hier anwenden
|
|
||||||
// check If-Modified-Since header
|
|
||||||
htok3(prot, "text/xml", "");
|
|
||||||
rssExport(num_entries);
|
|
||||||
} else {
|
} else {
|
||||||
// normaler Export
|
write("You are not owner or aide of this place.\n");
|
||||||
P2(("all entries: %O\n", _thread))
|
|
||||||
htok3(prot, "text/html", "Cache-Control: no-cache\n");
|
|
||||||
displayHeader();
|
|
||||||
// display the blog
|
|
||||||
displayMain(num_entries);
|
|
||||||
// display the chatlog
|
|
||||||
logView(a < 24 ? a : 12, "html", 15);
|
|
||||||
displayFooter();
|
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rssExport(last) {
|
|
||||||
int i;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
len = sizeof(_thread);
|
|
||||||
if (last > len) last = len;
|
|
||||||
write("<?xml version=\"1.0\" encoding=\"" SYSTEM_CHARSET "\" ?>\n"
|
|
||||||
"<rdf:RDF\n"
|
|
||||||
"xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"
|
|
||||||
"xmlns=\"http://purl.org/rss/1.0/\">\n\n"
|
|
||||||
"<channel>\n"
|
|
||||||
"\t<title>PSYC - Protocol for Synchronous Conferencing</title>\n"
|
|
||||||
"\t<link>http://www.psyc.eu</link>\n"
|
|
||||||
"\t<description>News about the PSYC project</description>\n"
|
|
||||||
"</channel>\n");
|
|
||||||
for (i = len - last; i < len; i++) {
|
|
||||||
write("\n<item>\n"
|
|
||||||
"\t<title>"+ _thread[i]["thread"] +"</title>\n"
|
|
||||||
"\t<link>http://" + SERVER_HOST + ":33333" + webact + "?comments=" + i + "</link>\n"
|
|
||||||
"\t<description>" + _thread[i]["text"] + "</description>\n"
|
|
||||||
"\t<dc:date>" + isotime(ctime(_thread[i]["date"]), 1) + "</dc:date>\n"
|
|
||||||
"\t<dc:creator>" + _thread[i]["author"] + "</dc:creator>\n");
|
|
||||||
write("</item>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
write("</rdf:RDF>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
jscriptExport(last) {
|
|
||||||
mapping item;
|
|
||||||
string buf = "";
|
|
||||||
|
|
||||||
// htok3(prot, "application/x-javascript", "Cache-Control: no-cache\n");
|
|
||||||
write("function Entry(thread, author, date, text) {\n"
|
|
||||||
"\tthis.thread = thread;\n"
|
|
||||||
"\tthis.author = author;\n"
|
|
||||||
"\tthis.date = date;\n"
|
|
||||||
"\tthis.text = text;\n"
|
|
||||||
"}\n\n"
|
|
||||||
"document.blogentries = new Array(\n");
|
|
||||||
foreach (item : _thread[<last..]) {
|
|
||||||
if (item) buf += "new Entry(\"" + item["thread"] + "\", \""
|
|
||||||
+ item["author"] + "\", \""
|
|
||||||
+ isotime(ctime(item["date"]), 1) + "\", \""
|
|
||||||
+ item["text"] + "\"),\n";
|
|
||||||
}
|
|
||||||
buf = buf[..<3] + ");";
|
|
||||||
|
|
||||||
write(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
displayMain(last) {
|
|
||||||
int i;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
len = sizeof(_thread);
|
|
||||||
if (last > len) last = len;
|
|
||||||
P2(("len %d, last %d\n", len, last))
|
|
||||||
for (i = len - last; i < len; i++) {
|
|
||||||
write("<table><tr><td class='blogthread'>" + _thread[i]["thread"]
|
|
||||||
+ "</td>"
|
|
||||||
"<td class='blogauthor'>" + _thread[i]["author"] + "</td>"
|
|
||||||
"<td class='blogdate'>" + isotime(ctime(_thread[i]["date"]), 1) + "</td></tr>"
|
|
||||||
"<tr><td class='blogtext' colspan=3>" + _thread[i]["text"]
|
|
||||||
+ "</td></tr>"
|
|
||||||
"<tr><td colspan=3 align='right'>");
|
|
||||||
write("<a href='" + webact + "?comments=" + i + "'>there are " + sizeof(_thread[i]["comments"]) + " comments</a>");
|
|
||||||
write("</td></tr></table>\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// neuen Eintrag verfassen
|
||||||
|
if (query["request"] == "form") {
|
||||||
|
htok(prot);
|
||||||
|
displayHeader();
|
||||||
|
write("<form action='" + webact + "' method='GET'>\n"
|
||||||
|
"<input type='hidden' name='request' value='post'>\n"
|
||||||
|
"PSYC Identity:<br><input type='text' name='uni' size=60><br>\n"
|
||||||
|
"Thread:<br><input type='text' name='thread' size=60><br>\n"
|
||||||
|
"Text:<br>\n<textarea name='text' rows='14' cols='64'></textarea><br>\n"
|
||||||
|
"<input type='submit' value='CREATE MESSAGE'>\n"
|
||||||
|
"</form>\n");
|
||||||
|
displayFooter();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
htmlEntries(array(mapping) entries, int js, string chan, string submit) {
|
//::htget(prot, query, headers, qs, data, 1); // no processing, just info
|
||||||
P3((">> threads:htmlentries(%O, %O, %O, %O)\n", entries, js, chan, submit))
|
|
||||||
|
string export = query["export"] || query["format"];
|
||||||
|
if (export == "js") {
|
||||||
|
// check If-Modified-Since header
|
||||||
|
htok3(prot, "application/x-javascript", "Cache-Control: no-cache\n");
|
||||||
|
jsExport(limit, offset);
|
||||||
|
} else if (export == "json") {
|
||||||
|
// check If-Modified-Since header
|
||||||
|
htok3(prot, "application/json", "Cache-Control: no-cache\n");
|
||||||
|
jsonExport(limit, offset);
|
||||||
|
} else if (export == "rss" || export == "rdf") {
|
||||||
|
// export als RSS
|
||||||
|
// scheinbar gibt es ein limit von 15 items / channel
|
||||||
|
// htquote auch hier anwenden
|
||||||
|
// check If-Modified-Since header
|
||||||
|
htok3(prot, "text/xml", "");
|
||||||
|
rssExport(limit, offset);
|
||||||
|
} else {
|
||||||
|
// normaler Export
|
||||||
|
P2(("all entries: %O\n", _thread))
|
||||||
|
htok3(prot, "text/html", "Cache-Control: no-cache\n");
|
||||||
|
displayHeader();
|
||||||
|
// display the blog
|
||||||
|
displayMain(limit, offset);
|
||||||
|
// display the chatlog
|
||||||
|
|
||||||
|
if (showWebLog()) logView(a < 24 ? a : 12, "html", 15);
|
||||||
|
displayFooter();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries(int limit, int offset) {
|
||||||
|
array(mapping) entries = ({ });
|
||||||
|
int i, n = 0, o = 0;
|
||||||
|
for (i = sizeof(_thread) - 1; i >= 0; i--) {
|
||||||
|
P3((">>> _thread[%O]: %O\n", i, _thread[i]))
|
||||||
|
unless (_thread[i]) continue;
|
||||||
|
if (o++ < offset) continue;
|
||||||
|
entries += ({ _thread[i] });
|
||||||
|
if (++n >= limit) break;
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
htmlEntries(array(mapping) entries, int nojs, string chan, string submit, string url_prefix) {
|
||||||
|
P3((">> threads:htmlentries(%O, %O, %O, %O)\n", entries, nojs, chan, submit))
|
||||||
string t, ht = "";
|
string t, ht = "";
|
||||||
string id_prefix = chan ? chan + "-" : "";
|
string id_prefix = chan ? chan + "-" : "";
|
||||||
if (js) ht +=
|
unless(url_prefix) url_prefix = "";
|
||||||
|
unless (nojs) ht +=
|
||||||
"<script type='text/javascript'>\n"
|
"<script type='text/javascript'>\n"
|
||||||
"function toggle(e) { e = document.getElementById(e); e.className = e.className.match('hidden') ? e.className.replace(/ *hidden/, '') : e.className + ' hidden'; }\n"
|
"function toggle(e) { if (typeof e == 'string') e = document.getElementById(e); e.className = e.className.match('hidden') ? e.className.replace(/ *hidden/, '') : e.className + ' hidden'; }\n"
|
||||||
"</script>\n";
|
"</script>\n";
|
||||||
|
|
||||||
foreach (mapping item : entries) {
|
|
||||||
P3((">>> item: %O\n", item))
|
|
||||||
unless (item) continue;
|
|
||||||
|
|
||||||
t = htquote(item["text"]);
|
foreach (mapping entry : entries) {
|
||||||
|
P3((">>> entry: %O\n", entry))
|
||||||
|
unless (entry) continue;
|
||||||
|
|
||||||
|
t = htquote(entry["text"]);
|
||||||
t = replace(t, "\n", "<br>\n");
|
t = replace(t, "\n", "<br>\n");
|
||||||
t = replace(t, "<", "<");
|
t = replace(t, "<", "<");
|
||||||
t = replace(t, ">", ">");
|
t = replace(t, ">", ">");
|
||||||
|
|
||||||
string c = "";
|
string c = "";
|
||||||
if (item["comments"])
|
if (entry["comments"])
|
||||||
foreach(mapping comment : item["comments"])
|
foreach(mapping comment : entry["comments"])
|
||||||
c += "<div class='comment' title='" + isotime(ctime(comment["date"]), 1) + "'><span class='comment-author'>" + comment["nick"] + "</span>: <span class='comment-text'>" + comment["text"] + "</span></div>\n";
|
c += "<div class='comment' title='" + isotime(ctime(comment["date"]), 1) + "'><span class='comment-author'>" + comment["nick"] + "</span>: <span class='comment-text'>" + comment["text"] + "</span></div>\n";
|
||||||
|
|
||||||
ht +=
|
ht +=
|
||||||
"<div class='entry'>\n"
|
"<div class='entry'>\n"
|
||||||
"<div class='title'>\n"
|
"<div class='title'>\n"
|
||||||
"<span class='id'>#" + item["id"] + "</span> - \n"
|
"<a href=\"" + url_prefix + "?id=" + entry["id"] + "\">"
|
||||||
"<span class='author'>" + item["author"] + "</span>\n"
|
"<span class='id'>#" + entry["id"] + "</span> - \n"
|
||||||
+ (item["thread"] && strlen(item["thread"]) ? " - " : "") +
|
"<span class='author'>" + entry["author"] + "</span>\n"
|
||||||
"<span class='subject'>" + htquote(item["thread"]) + "</span>\n"
|
+ (entry["thread"] && strlen(entry["thread"]) ? " - " : "") +
|
||||||
|
"<span class='subject'>" + htquote(entry["thread"]) + "</span>\n"
|
||||||
|
"</a>"
|
||||||
"</div>\n"
|
"</div>\n"
|
||||||
"<div class='body'>\n"
|
"<div class='body'>\n"
|
||||||
"<div class='text'>" + t + "</div>\n"
|
"<div class='text'>" + t + "</div>\n"
|
||||||
"<div id='comments-" + id_prefix + item["id"] + "' class='comments hidden'>" + c +
|
"<div id='comments-" + id_prefix + entry["id"] + "' class='comments'>" + c +
|
||||||
(submit && strlen(submit) ?
|
(submit && strlen(submit) ?
|
||||||
"<div class='comment-submit'>"
|
"<a onclick=\"toggle(this.nextSibling)\">» reply</a>"
|
||||||
|
"<div class='comment-submit hidden'>"
|
||||||
"<textarea autocomplete='off'></textarea>"
|
"<textarea autocomplete='off'></textarea>"
|
||||||
//FIXME: cmd is executed twice, because after a set-cookie it's parsed again
|
//FIXME: cmd is executed twice, because after a set-cookie it's parsed again
|
||||||
"<input type='button' value='Comment' onclick=\"cmd('comment " + item["id"] + " '+ this.previousSibling.value, '" + submit + "')\">"
|
"<input type='button' value='Send' onclick=\"cmd('comment " + entry["id"] + " '+ this.previousSibling.value, '" + submit + "')\">"
|
||||||
"</div>" : "") +
|
"</div>" : "") +
|
||||||
"</div>\n"
|
"</div>\n"
|
||||||
"</div>\n"
|
"</div>\n"
|
||||||
"<div class='footer'>\n"
|
"<div class='footer'>\n"
|
||||||
"<span class='date'>" + isotime(ctime(item["date"]), 1) + "</span>\n"
|
"<span class='date'>" + isotime(ctime(entry["date"]), 1) + "</span>\n"
|
||||||
"<span class='comments-link'>"
|
"<span class='comments-link'>"
|
||||||
"<a onclick=\"toggle('comments-" + id_prefix + item["id"] + "')\">" + sizeof(item["comments"]) + " comments</a>"
|
"<a onclick=\"toggle('comments-" + id_prefix + entry["id"] + "')\">" + sizeof(entry["comments"]) + " comments</a>"
|
||||||
"</span>\n"
|
"</span>\n"
|
||||||
"</div>\n"
|
"</div>\n"
|
||||||
"</div>\n";
|
"</div>\n";
|
||||||
@ -580,50 +467,107 @@ htmlEntries(array(mapping) entries, int js, string chan, string submit) {
|
|||||||
return "<div class='threads'>" + ht + "</div>";
|
return "<div class='threads'>" + ht + "</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
htMain(int last) {
|
rssEntries(array(mapping) entries) {
|
||||||
return htmlEntries(entries(last), 1);
|
string rss =
|
||||||
}
|
"<?xml version=\"1.0\" encoding=\"" SYSTEM_CHARSET "\" ?>\n"
|
||||||
|
"<rdf:RDF\n"
|
||||||
|
"xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"
|
||||||
|
"xmlns=\"http://purl.org/rss/1.0/\">\n\n"
|
||||||
|
"<channel>\n"
|
||||||
|
"\t<title>PSYC - Protocol for Synchronous Conferencing</title>\n"
|
||||||
|
"\t<link>http://www.psyc.eu</link>\n"
|
||||||
|
"\t<description>News about the PSYC project</description>\n"
|
||||||
|
"</channel>\n";
|
||||||
|
|
||||||
entries(int last) {
|
foreach (mapping entry : entries) {
|
||||||
array(mapping) entries = ({ });
|
rss +=
|
||||||
int i, n = 0;
|
"\n<item>\n"
|
||||||
for (i = sizeof(_thread) - 1; i >= 0; i--) {
|
"\t<title>"+ entry["thread"] +"</title>\n"
|
||||||
P3((">>> _thread[%O]: %O\n", i, _thread[i]))
|
"\t<link>http://" + SERVER_HOST + ":33333" + webact + "?id=" + entry["id"] + "</link>\n"
|
||||||
unless (_thread[i]) continue;
|
"\t<description>" + entry["text"] + "</description>\n"
|
||||||
entries += ({ _thread[i] });
|
"\t<dc:date>" + isotime(ctime(entry["date"]), 1) + "</dc:date>\n"
|
||||||
if (++n >= last) break;
|
"\t<dc:creator>" + entry["author"] + "</dc:creator>\n"
|
||||||
|
"</item>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
rss += "</rdf:RDF>\n";
|
||||||
|
return rss;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonEntries(int last) {
|
jsEntries(array(mapping) entries) {
|
||||||
return make_json(entries(last));
|
string js =
|
||||||
}
|
"function Entry(id, thread, author, date, text) {\n"
|
||||||
|
"\tthis.id = id;\n"
|
||||||
|
"\tthis.thread = thread;\n"
|
||||||
|
"\tthis.author = author;\n"
|
||||||
|
"\tthis.date = date;\n"
|
||||||
|
"\tthis.text = text;\n"
|
||||||
|
"}\n\n"
|
||||||
|
"document.blogentries = new Array(\n";
|
||||||
|
|
||||||
htComments(entry) {
|
foreach (mapping entry : entries) {
|
||||||
mapping item;
|
js += "new Entry(" + entry["id"] + ","
|
||||||
string ht = "";
|
"\"" + entry["thread"] + "\","
|
||||||
|
"\"" + entry["author"] + "\","
|
||||||
write("<b>" + entry["author"] + "</b>: " + entry["text"] + "<br><br>\n");
|
+ isotime(ctime(entry["date"]), 1) + ","
|
||||||
if (entry["comments"]) {
|
"\"" + entry["text"] + "\"),\n";
|
||||||
foreach(item : entry["comments"]) {
|
|
||||||
ht += "<b>" + item["nick"] + "</b>: " + item["text"] + "<br>\n";
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ht += "no comments...<br>\n";
|
return js[..<3] + ");";
|
||||||
}
|
|
||||||
return ht;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
displayMain(last) {
|
jsonEntries(int limit, int offset) {
|
||||||
write(htMain(last));
|
return make_json(entries(limit, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
displayComments(entry) {
|
jsonExport(int limit, int offset) {
|
||||||
write(htComments(entry));
|
write(jsonEntries(limit, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jsExport(int limit, int offset) {
|
||||||
|
write(jsEntries(limit, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
rssExport(int limit, int offset) {
|
||||||
|
write(rssEntries(entries(limit, offset)));
|
||||||
|
}
|
||||||
|
|
||||||
|
htMain(int limit, int offset, string chan) {
|
||||||
|
return htmlEntries(entries(limit, offset), 0, chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayMain(int limit, int offset) {
|
||||||
|
write(htMain(limit, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
htEntry(int id) {
|
||||||
|
unless (_thread && id >= 0 && id <= sizeof(_thread) && _thread[id]) return 0;
|
||||||
|
return htmlEntries(({ _thread[id] }));
|
||||||
|
}
|
||||||
|
|
||||||
|
displayEntry(int id) {
|
||||||
|
write(htEntry(id) || "No such entry.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// wir können zwei strategien fahren.. die technisch einfachere ist es
|
||||||
|
// die reihenfolge der elemente festzulegen und für jedes ein w(_HTML_xy
|
||||||
|
// auszuspucken. flexibler wär's stattdessen wenn jede seite ein einziges
|
||||||
|
// w(_PAGES_xy ausgeben würde in dem es per [_HTML_list_threads] oder
|
||||||
|
// ähnlichem die blog-elemente per psyctext-vars übergibt ... dann kann
|
||||||
|
// es immernoch per {_HTML_head_threads} header und footer einheitlich
|
||||||
|
// halten. womöglich kann man auch nachträglich plan A in plan B
|
||||||
|
// umwandeln..... hmmm -lynX
|
||||||
|
//
|
||||||
|
displayHeader() {
|
||||||
|
w("_HTML_head_threads",
|
||||||
|
"<html><head><link rel='stylesheet' type='text/css' href='"+ STYLESHEET +"'></head>\n"+
|
||||||
|
"<body class='threads'>\n\n");
|
||||||
|
}
|
||||||
|
displayFooter() {
|
||||||
|
w("_HTML_tail_threads", "</body></html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
nntpget(cmd, args) {
|
nntpget(cmd, args) {
|
||||||
mapping item;
|
mapping item;
|
||||||
int i;
|
int i;
|
||||||
@ -671,29 +615,6 @@ default:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef STYLESHEET
|
|
||||||
# define STYLESHEET (v("_uniform_style") || "/static/examine.css")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// wir können zwei strategien fahren.. die technisch einfachere ist es
|
|
||||||
// die reihenfolge der elemente festzulegen und für jedes ein w(_HTML_xy
|
|
||||||
// auszuspucken. flexibler wär's stattdessen wenn jede seite ein einziges
|
|
||||||
// w(_PAGES_xy ausgeben würde in dem es per [_HTML_list_threads] oder
|
|
||||||
// ähnlichem die blog-elemente per psyctext-vars übergibt ... dann kann
|
|
||||||
// es immernoch per {_HTML_head_threads} header und footer einheitlich
|
|
||||||
// halten. womöglich kann man auch nachträglich plan A in plan B
|
|
||||||
// umwandeln..... hmmm -lynX
|
|
||||||
//
|
|
||||||
displayHeader() {
|
|
||||||
w("_HTML_head_threads",
|
|
||||||
"<html><head><link rel='stylesheet' type='text/css' href='"+
|
|
||||||
STYLESHEET +"'></head>\n"+
|
|
||||||
"<body class='threads'>\n\n");
|
|
||||||
}
|
|
||||||
displayFooter() {
|
|
||||||
w("_HTML_tail_threads", "</body></html>");
|
|
||||||
}
|
|
||||||
|
|
||||||
canPost(snicker) {
|
canPost(snicker) {
|
||||||
return qAide(snicker);
|
return qAide(snicker);
|
||||||
}
|
}
|
||||||
@ -702,6 +623,87 @@ mayLog(mc) {
|
|||||||
return abbrev("_notice_thread", mc) || abbrev("_message", mc);
|
return abbrev("_notice_thread", mc) || abbrev("_message", mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showWebLog() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
numEntries() {
|
numEntries() {
|
||||||
return sizeof(_thread);
|
return sizeof(_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathName() {
|
||||||
|
return psycName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// old stuff
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
_request_iterator(source, mc, data, vars, b) {
|
||||||
|
unless (canPost(SNICKER)) return 0;
|
||||||
|
sendmsg(source, "_notice_thread_iterator",
|
||||||
|
"[_iterator] blog entries have been requested "
|
||||||
|
"since creation.", ([
|
||||||
|
// i suppose this wasn't intentionally using
|
||||||
|
// MMP _count so i rename it to _iterator
|
||||||
|
"_iterator" : v("iterator")
|
||||||
|
]) );
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
listLastEntries(number) {
|
||||||
|
mapping* entries;
|
||||||
|
int i;
|
||||||
|
entries = _thread || ({ });
|
||||||
|
|
||||||
|
unless (sizeof(entries)) return 1;
|
||||||
|
|
||||||
|
i = v("iterator") || 0;
|
||||||
|
vSet("iterator", i + 1);
|
||||||
|
|
||||||
|
return entries[<number..];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
allEntries(source) {
|
||||||
|
mapping* entries;
|
||||||
|
mapping ar;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
entries = _thread || ({ });
|
||||||
|
|
||||||
|
unless (sizeof(entries)) return 1;
|
||||||
|
|
||||||
|
foreach (ar : entries) {
|
||||||
|
sendmsg(source, "_message_", "([_id]) \"[_topic]\", [_author]", ([ // ??
|
||||||
|
"_topic" : ar["topic"],
|
||||||
|
"_text" : ar["text"],
|
||||||
|
"_author" : ar["author"],
|
||||||
|
"_date" : ar["date"],
|
||||||
|
"_id" : i++,
|
||||||
|
"_nick_place" : MYNICK ]) );
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
addForum() {
|
||||||
|
// suggested protocol message for the buha forum
|
||||||
|
// (creation of a new thread)
|
||||||
|
|
||||||
|
:_target psyc://psyced.org/@buha
|
||||||
|
:_encoding utf-8
|
||||||
|
|
||||||
|
:_nick_forum morpheus
|
||||||
|
:_category Test-Forum
|
||||||
|
:_thread Test-Thread_
|
||||||
|
:_page_thread https://www.buha.info/board/showthread.php?t=1
|
||||||
|
|
||||||
|
_notice_thread
|
||||||
|
[_nick_forum] hat einen neuen Thread in [_category] erstellt: [_thread] ([_page_thread])
|
||||||
|
.
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -187,8 +187,8 @@ addEntry(text, unick, thread) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
htMain(int last) {
|
htMain(int limit, int offset) {
|
||||||
return htmlEntries(_thread, last, 1, channel);
|
return ::htMain(limit, offset, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
canPost(snicker) {
|
canPost(snicker) {
|
||||||
@ -199,6 +199,10 @@ isPublic() {
|
|||||||
return vQuery("privacy") == "public";
|
return vQuery("privacy") == "public";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showWebLog() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
qChannel() {
|
qChannel() {
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
@ -206,3 +210,12 @@ qChannel() {
|
|||||||
qHistoryGlimpse() {
|
qHistoryGlimpse() {
|
||||||
return HISTORY_GLIMPSE;
|
return HISTORY_GLIMPSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
psycName() {
|
||||||
|
ASSERT("psycName", stringp(MYNICK), MYNICK)
|
||||||
|
return MYLOWERNICK;
|
||||||
|
}
|
||||||
|
|
||||||
|
pathName() {
|
||||||
|
return regreplace(psycName(), "#", "/", 1);
|
||||||
|
}
|
||||||
|
@ -319,7 +319,7 @@ htDescription(anonymous, query, headers, qs, variant, vars) {
|
|||||||
+ (first ? "class='selected'" : "") + ">#" + channel + "</a>\n";
|
+ (first ? "class='selected'" : "") + ">#" + channel + "</a>\n";
|
||||||
contents +=
|
contents +=
|
||||||
"<div id='tab-contents-" + channel + "' "
|
"<div id='tab-contents-" + channel + "' "
|
||||||
+ (first ? "class='selected'" : "") + ">" + threads->htmlEntries(entries, 0, first, channel, anonymous ? "" : vars["_identification"] + "#" + channel) + "</div>\n";
|
+ (first ? "class='selected'" : "") + ">" + threads->htmlEntries(entries, !first, channel, anonymous ? "" : vars["_identification"] + "#" + channel, vars["_profile_url"] + "/" + channel) + "</div>\n";
|
||||||
first = 0;
|
first = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ body.threads,
|
|||||||
.Pe a {
|
.Pe a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #f33;
|
color: #f33;
|
||||||
background: black;
|
/*background: black;*/
|
||||||
}
|
}
|
||||||
.Peb a {
|
.Peb a {
|
||||||
padding: 4;
|
padding: 4;
|
||||||
@ -110,19 +110,22 @@ body.threads,
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry .title {}
|
.entry .title a {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
.entry .title .author {}
|
.entry .title .author {}
|
||||||
.entry .title .subject {}
|
.entry .title .subject {}
|
||||||
|
|
||||||
.entry .footer a,
|
.entry .footer a,
|
||||||
.entry .footer a:visited {
|
.entry .footer a:visited {
|
||||||
cursor: pointer;
|
|
||||||
color: white;
|
color: white;
|
||||||
background: transparent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry .footer a:hover,
|
.entry a {
|
||||||
.entry .footer a:visited:hover {
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.entry a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user