-
Notifications
You must be signed in to change notification settings - Fork 0
/
Forums.js
493 lines (415 loc) · 15.1 KB
/
Forums.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
// ////////////////////////////////////////////////////////////////////////////
// (c)2009 Symbian Foundation, Andrew Wafaa
// ////////////////////////////////////////////////////////////////////////////
// Forums
// Forums have the following structure:
//
// Forum group list
// Forum list
// Thread list
// Message list
// All four views are based on customised RssReader. We customise two aspects:
// - Parsing XML - data is not RSS
// - Handling item selection (e.g. creating a new view for a newly selected forum)
// /////////////////////////////////////////////////////////////////////////////
// Forum groups
// response parser for forum groups
function forumGroupsResponseParser(broker, responseStatus, xmlDoc) {
if (responseStatus == 200 && xmlDoc != null) {
// node ref for iterating
var node;
// for compatibility with rss
var lastModified = new Date();
// init result items array
var items = [];
var elements = xmlDoc.getElementsByTagName("group");
for (var i = 0; i < elements.length; i++) {
var groupid = elements[i].getAttribute("id");
var grouptitle = elements[i].getAttribute("title");
items.push({ id: groupid, title: grouptitle});
}
// update was completed successfully
return { status: "ok", lastModified: lastModified, items: items };
} else {
// update failed
return { status: "error" };
}
}
// FeedPresenter implementation for forum groups
function ForumGroupsFeedPresenter(rssreader){
if (rssreader) {
this.init(rssreader);
}
}
// ForumGroupsFeedPresenter is a subclass of ButtonFeedPresenter
ForumGroupsFeedPresenter.prototype = new ButtonFeedPresenter(null);
// ForumGroupsFeedPresenter "Constructor"
ForumGroupsFeedPresenter.prototype.init = function(rssreader) {
ButtonFeedPresenter.prototype.init.call(this, rssreader);
}
// Handle the click on a specific item
ForumGroupsFeedPresenter.prototype.feedClicked = function(event){
var buttonid = event.source.id;
if (buttonid == "latestPosts") {
// show latest posts
var url = forumFeedURL;
var latestPostsView = new RssReader("Latest posts", url, new LatestPostsFeedPresenter(null), this.rssreader, null);
latestPostsView.show();
}
else {
// show forum group
var groupid = this.items[buttonid].id;
var grouptitle = this.items[buttonid].title;
var url = forumsListUrl + groupid;
var forumListView = new RssReader(grouptitle, url, new ForumsListFeedPresenter(null), this.rssreader, forumListResponseParser);
forumListView.show();
}
}
// Create and add controls to be shown before items list.
ForumGroupsFeedPresenter.prototype.addPreambleItems = function(){
var feedItemControl = new NavigationButton("latestPosts", "blueright.gif", "Latest posts");
var self = this;
feedItemControl.addEventListener("ActionPerformed", function(event) { self.feedClicked(event); });
this.rssreader.addControl(feedItemControl);
}
// ///////////////////////////////////////////////////////////////////////////
// List of forums in a group
// response parser for forum list - in a group
function forumListResponseParser(broker, responseStatus, xmlDoc) {
if (responseStatus == 200 && xmlDoc != null) {
// node ref for iterating
var node;
// for compatibility with rss
var lastModified = new Date();
// init result items array
var items = [];
// extract items for all group elements
var elements = xmlDoc.getElementsByTagName("group");
for (var i = 0; i < elements.length; i++) {
var forumid = elements[i].getAttribute("id");
var forumtitle = elements[i].getAttribute("title");
items.push({ id: forumid, title: forumtitle});
}
// update was completed successfully
return { status: "ok", lastModified: lastModified, items: items };
} else {
// update failed
return { status: "error" };
}
}
// FeedPresenter implementation for forum groups
function ForumsListFeedPresenter(rssreader){
if (rssreader) {
this.init(rssreader);
}
}
// ForumsListFeedPresenter is a subclass of ButtonFeedPresenter
ForumsListFeedPresenter.prototype = new ButtonFeedPresenter(null);
// ForumsListFeedPresenter constructor
ForumsListFeedPresenter.prototype.init = function(rssreader) {
ButtonFeedPresenter.prototype.init.call(this, rssreader);
}
// forum has been selected, create a reader showing threads in the forum
ForumsListFeedPresenter.prototype.feedClicked = function(event){
var buttonid = event.source.id;
if (buttonid == "latestPosts") {
// show latest posts
var url = forumFeedURL + "&forumids=";
// append requested forum ids
for( var i = 0; i < this.items.length; i++) {
url += this.items[i].id + ",";
}
var latestPostsView = new RssReader(
"Latest posts in " + this.rssreader.feedName,
url,
new LatestPostsFeedPresenter(null),
this.rssreader,
null);
latestPostsView.show();
}
else {
var forumid = this.items[buttonid].id;
var forumtitle = this.items[buttonid].title;
var url = forumFeedURL + forumsForumSpecQuery + forumid;
var forumListView = new RssReader(forumtitle, url, new ThreadListFeedPresenter(null), this.rssreader, null);
forumListView.show();
}
}
// Create and add controls to be shown before items list.
ForumsListFeedPresenter.prototype.addPreambleItems = function(){
var feedItemControl = new NavigationButton("latestPosts", "blueright.gif", "Latest posts in " + this.rssreader.feedName);
var self = this;
feedItemControl.addEventListener("ActionPerformed", function(event) { self.feedClicked(event); });
this.rssreader.addControl(feedItemControl);
}
// ///////////////////////////////////////////////////////////////////////////
// List of threads in a forum
// response parser for thread list is the usual rss parser
// FeedPresenter implementation for forum groups
function ThreadListFeedPresenter(rssreader){
if (rssreader) {
this.init(rssreader);
}
}
// ThreadListFeedPresenter is a subclass of ButtonFeedPresenter
ThreadListFeedPresenter.prototype = new ButtonFeedPresenter(null);
// ThreadListFeedPresenter constructor
ThreadListFeedPresenter.prototype.init = function(rssreader) {
ButtonFeedPresenter.prototype.init.call(this, rssreader);
}
// Handle the click on a specific item
ThreadListFeedPresenter.prototype.feedClicked = function(event){
var buttonid = event.source.id;
if (buttonid == "newThread") {
// extract forum id from rssreader.feedURL
var ind = this.rssreader.feedURL.indexOf(forumsForumSpecQuery);
var forumid = this.rssreader.feedURL.substring( ind + forumsForumSpecQuery.length);
var postForm = new ForumPostForm(this.rssreader, forumid);
postForm.show();
}
else {
var weburl = this.items[buttonid].url;
// extract thread id from url. looking for t=xxx
var ind1 = weburl.indexOf("?t=");
if (ind1 == -1) {
ind1 = weburl.indexOf("&t=");
}
if (ind1 != -1) {
var threadid = "";
var ind2 = weburl.indexOf("&", ind1);
if (ind2 == -1) {
threadid = weburl.substring(ind1 + 3); // ?t=
}
else {
threadid = weburl.substring(ind1 + 3, ind2); // ?t=
}
var url = forumThreadUrl + threadid;
var title = this.items[buttonid].title;
if (title.length > 30) {
title = title.substring(0, 30) + "...";
}
var threadView = new RssReader(title, url, new ThreadFeedPresenter(null), this.rssreader, threadResponseParser);
threadView.show();
}
}
}
// Create and add controls to be shown before items list.
ThreadListFeedPresenter.prototype.addPreambleItems = function(){
var feedItemControl = new NavigationButton("newThread", "blueright.gif", "Post a new thread");
var self = this;
feedItemControl.addEventListener("ActionPerformed", function(event) { self.feedClicked(event); });
this.rssreader.addControl(feedItemControl);
}
// ///////////////////////////////////////////////////////////////////////////
// List of messages in a thread
// response parser for thread list
function threadResponseParser(broker, responseStatus, xmlDoc) {
if (responseStatus == 200 && xmlDoc != null) {
// node ref for iterating
var node;
// for compatibility with rss
var lastModified = new Date();
// init result items array
var items = [];
// iterate over message elements
var elements = xmlDoc.getElementsByTagName("message");
for (var i = 0; i < elements.length; i++) {
var postid;
var threadid;
var username;
var title;
var dateline;
var pagetext;
var isdeleted;
// extract info about the post
node = elements[i].firstChild;
while (node != null) {
if ( node.nodeName == "postid" ) postid=getTextOfNode(node);
else if ( node.nodeName == "threadid" ) threadid=getTextOfNode(node);
else if ( node.nodeName == "username" ) username=getTextOfNode(node);
else if ( node.nodeName == "title" ) title=getTextOfNode(node);
else if ( node.nodeName == "dateline" ) dateline=getTextOfNode(node);
else if ( node.nodeName == "pagetext" ) pagetext=getTextOfNode(node);
else if ( node.nodeName == "isdeleted" ) isdeleted=getTextOfNode(node);
node = node.nextSibling;
}
if ( isdeleted == 1 ) continue;
items.push({
postid: postid,
threadid: threadid,
username: username,
title: title,
dateline: dateline,
pagetext: pagetext
});
}
// update was completed successfully
return { status: "ok", lastModified: lastModified, items: items };
} else {
// update failed
return { status: "error" };
}
}
// FeedPresenter implementation for forum groups
function ThreadFeedPresenter(rssreader){
if (rssreader) {
this.init(rssreader);
}
}
// ThreadFeedPresenter is a subclass of HtmlFeedPresenter
ThreadFeedPresenter.prototype = new HtmlFeedPresenter(null);
// ThreadFeedPresenter constructor
ThreadFeedPresenter.prototype.init = function(rssreader) {
HtmlFeedPresenter.prototype.init.call(this, rssreader);
}
// Handle the click on a specific item
ThreadFeedPresenter.prototype.feedClicked = function(event){
// do nothing
}
// Create a control that represents this item and add it to
// parent rss reader
ThreadFeedPresenter.prototype.show = function(item) {
// get a feed item control from the pool or create one and
// place it in the pool if there aren't enough feed item controls
var feedItemControl = new ContentPanel(null, null, null, true);
// initialize feed item control
var title = item.title;
if ( !title || title.length == 0 ) {
title = "Re:";
item.title = title;
}
feedItemControl.setCaption(bbcode2html(title));
feedItemControl.setContent(this.getContentHTMLForFeedItem(item));
feedItemControl.setExpanded(true);
// add the feed item control to the main view
this.rssreader.feedItemControls.push(feedItemControl);
this.rssreader.addControl(feedItemControl);
}
// Generate HTML content from the feed item
ThreadFeedPresenter.prototype.getContentHTMLForFeedItem = function (item){
var buf = "";
// item date
if (item.dateline != null) {
var date = new Date();
date.setTime(item.dateline*1000);
buf += "<div class=\"FeedItemDate\">" ;
if ( item.username != null ) {
buf += item.username + ", ";
}
buf += date + "</div>";
}
// item description
if (item.pagetext != null) {
var text = bbcode2html(item.pagetext);
text = text.replace(/\r\n/g, "<br>");
buf += "<div class=\"FeedItemDescription\">" + text + "</div>";
buf += "<div class=\"FeedItemLink\">";
buf += "<a href=\"JavaScript:void(0)\" onclick=\"showReplyForm("
+ item.threadid+ "," + item.postid + ", '" + item.title
+ "'); return false;\">";
buf += "<strong>Reply to this post<strong></a>"
buf += "</div>";
}
return buf;
}
// Show the reply-to-post form
function showReplyForm(threadid, postid, title) {
var replyForm = new ForumReplyForm(uiManager.currentView, threadid, postid, title);
replyForm.show();
}
// ///////////////////////////////////////////////////////////////////////////
// Latest posts - same as ThreadListFeedPresenter, only has no preamble items
// because it doesn't show one thread (so we can't post to latest items)...
// FeedPresenter implementation for latest posts
function LatestPostsFeedPresenter(rssreader){
if (rssreader) {
this.init(rssreader);
}
}
LatestPostsFeedPresenter.prototype = new ThreadListFeedPresenter(null);
// ForumGroupsFeedPresenter "Constructor"
LatestPostsFeedPresenter.prototype.init = function(rssreader) {
ButtonFeedPresenter.prototype.init.call(this, rssreader);
}
// LatestPostsFeedPresenter has no preamble items
LatestPostsFeedPresenter.prototype.addPreambleItems = function(){
}
// ///////////////////////////////////////////////////////////////////////////
// Utilities
// Forum posts can be be quite messy and include bbcodes, smilies etc.
// This function does the minimum by stripping bbcodes and such
function sanitize(text) {
var prevind = 0;
var ind = text.indexOf("[");
if ( ind == -1 ) return text;
var buf = "";
while ( ind != -1 ) {
buf += text.substring(prevind, ind);
var ind2 = text.indexOf("]", ind);
if ( ind2 != -1 ) {
prevind = ind2+1;
} else {
break;
}
ind = text.indexOf("[", prevind);
}
if ( prevind > 0 && prevind < text.length) {
buf += text.substring(prevind);
}
return buf;
}
// feeds contain bbcodes - this function should turn the bbcode markup
// to HTML
function bbcode2html(s) {
var prevind = 0;
var buf = "";
var ind = s.indexOf("[");
if ( ind == -1 ) return s;
while ( ind != -1 ) {
buf += s.substring(prevind, ind);
var ind2 = s.indexOf("]", ind); // end of tag
var fulltag = s.substring(ind+1,ind2);
var tag = fulltag;
var ind3 = s.indexOf("=", ind); // end of tag name, eg. [URL=http...]
if ( ind3 != -1 && ind3 < ind2) {
tag = s.substring(ind+1,ind3);
}
var ind4 = s.indexOf("[/"+tag+"]");
var tagContent = s.substring(ind2+1, ind4);
buf += convertTag(tag, fulltag, tagContent);
if ( ind4 != -1 ) {
prevind = s.indexOf(']',ind4) + 1;
} else {
break;
}
ind = s.indexOf("[", prevind);
}
buf += s.substring(prevind);
return buf;
}
function convertTag(tag, fulltag, tagContent) {
tag = tag.toLowerCase();
switch(tag) {
case 'b':case 'i':case 'u':case 's':case 'sup':case 'sub':case 'h1':case 'h2':case 'h3':case 'h4':case 'h5':case 'h6':case 'table':case 'tr':case 'th':case 'td':
{
return '<' + tag + '>' + tagContent + "</" + tag + ">";
}
case 'quote': return '<blockquote><i>' + tagContent + '</i></blockquote>';
case 'url': {
var eqsign = fulltag.indexOf("=");
if ( eqsign > -1 ) {
return '<div class="FeedItemLink"><a href="JavaScript:void(0)" onclick="openURL( '
+ fulltag.substring(eqsign+1)
+ '") ><i>'
+ tagContent
+ '</i></a></div>';
} else {
return '<div class="FeedItemLink"><a href="JavaScript:void(0)" onclick="openURL( '
+ tagContent
+ '") ><i>'
+ tagContent
+ '</i></a></div>';
}
}
}
}