// ////////////////////////////////////////////////////////////////////////////
// Symbian Foundation Example Code
//
// This software is in the public domain. No copyright is claimed, and you
// may use it for any purpose without license from the Symbian Foundation.
// No warranty for any purpose is expressed or implied by the authors or
// the Symbian Foundation.
// ////////////////////////////////////////////////////////////////////////////
// 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
var feedItemControl;
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);
}
//// // FeedPresenter implementation for forum groups
function ForumsSettingsFeedPresenter(rssreader){
if (rssreader) {
this.init(rssreader);
}
}
// ForumsListFeedPresenter is a subclass of ButtonFeedPresenter
ForumsSettingsFeedPresenter.prototype = new ButtonFeedPresenter(null);
// ForumsListFeedPresenter constructor
ForumsSettingsFeedPresenter.prototype.init = function(rssreader) {
ButtonFeedPresenter.prototype.init.call(this, rssreader);
}
// forum has been selected, create a reader showing threads in the forum
ForumsSettingsFeedPresenter.prototype.feedClicked = function(event){
var buttonid = event.source.id;
var firstboot =true;
var forumid = this.items[buttonid].id;
var forumtitle = this.items[buttonid].title;
if(myforumid){firstboot=false;}
feedItemControl.setText(forumtitle + ": " + forumid);
ForumControl.setText("Forum: " + forumtitle);
myforumid=forumid;
myforumtitle=forumtitle;
if (firstboot){
forum_reader = new RssReader(myforumtitle, forumFeedURL + forumsForumSpecQuery + myforumid, new ThreadListFeedPresenter(null), bugzilla, null);
forum_reader.show();
savePreferences();
} else {
settings.show();
}
}
// Create and add controls to be shown before items list.
ForumsSettingsFeedPresenter.prototype.addPreambleItems = function(){
feedItemControl = new Label(null, "Choosen forum:");
var self = this;
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+"]", ind2);
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();
var param = null;
var eqsign = fulltag.indexOf("="); // onclick=\"openURL('" + item.url + "');
if (eqsign > -1) {
param = fulltag.substring(eqsign+1);
}
switch(tag) {
case '*': return bbcode2html(tagContent);
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 + '>' + bbcode2html(tagContent) + "</" + tag + ">";
}
case 'font': return '<font face="'+param+'">' + bbcode2html(tagContent) + '</font>';
case 'size': return '<font size="'+param+'">' + bbcode2html(tagContent) + '</font>';
case 'color': return '<font color="'+param+'">' + bbcode2html(tagContent) + '</font>';
case 'left': return '<div align="left">' + bbcode2html(tagContent) + '</div>';
case 'right': return '<div align="right">' + bbcode2html(tagContent) + '</div>';
case 'center': return '<div align="center">' + bbcode2html(tagContent) + '</div>';
case 'list':{
tagContent = tagContent.replace(/\[\*\]/g, "<br>• ");
return bbcode2html(tagContent); // todo
}
case 'php':
case 'code':
case 'html':{
var escaped = tagContent.replace(/</g, "<").replace(/>/g, ">");
return '<div class=codebox><pre>' + escaped + '</pre></div>';
}
case 'quote': return '<div class=codebox><b>Quote:</b><br><i>' + tagContent + '</i></div>';
case 'url': {
if ( eqsign > -1 ) {
return "<div class=\"FeedItemLink\"><a href=\"JavaScript:void(0)\" onclick=\"openURL( '"
+ param
+ "')\" ><i>"
+ tagContent
+ '</i></a></div>';
} else {
return "<div class=\"FeedItemLink\"><a href=\"JavaScript:void(0)\" onclick=\"openURL( '"
+ tagContent
+ "')\" ><i>"
+ tagContent
+ '</i></a></div>';
}
}
}
}