--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mypackage_wrt/Forums.js Fri Apr 30 15:01:03 2010 +0100
@@ -0,0 +1,567 @@
+// ////////////////////////////////////////////////////////////////////////////
+// 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>';
+ }
+ }
+ }
+}