Wikipedia/Wiki.js
changeset 20 918767a9c8d3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wikipedia/Wiki.js	Tue Mar 09 10:34:58 2010 +0000
@@ -0,0 +1,632 @@
+// ////////////////////////////////////////////////////////////////////////////
+// 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. 
+// ////////////////////////////////////////////////////////////////////////////
+
+
+var baseUrl = "http://en.wikipedia.org";
+
+var wikiSearchBaseUrl = "/w/api.php?format=xml&action=query&list=search&srsearch=";
+var wikiSearchOffsetQueryPart = "&sroffset=";
+var wikiSearchLimitQueryPart = "&srlimit=";
+var wikiSearchWhatQueryPart = "&srwhat=";
+
+var wikiViewPageUrlBase = baseUrl + "/w/index.php?title=";
+var wikiPrintableParam = "&printable=yes";
+
+var MENU_ITEM_READER_SEARCH = 1;
+var MENU_ITEM_HISTORY_CLEAR = 1;
+var MENU_ITEM_BOOKMARKS_CLEAR = 1;
+var MENU_ITEM_MAIN_BACK = 4;
+var MENU_ITEM_MAIN_NEXT = 5;
+var MENU_ITEM_MAIN_ADD_BOOKMARK = 6;
+var MENU_ITEM_MAIN_NAVIGATION = 7;
+var MENU_ITEM_MAIN_SEARCH = 8;
+var MENU_ITEM_MAIN_BOOKMARKS = 9;
+var MENU_ITEM_MAIN_HISTORY = 10; 
+var MENU_ITEM_MAIN_LANGUAGE =11;
+var MENU_ITEM_MAIN_UPDATES =12;
+var MENU_ITEM_MAIN_HELP = 13;
+
+var PREDICTIVE_RESULT_COUNT = 0;
+
+//var wapediaArticleBase = "http://wapedia.mobi/en/";
+
+
+//var wikiListCategoriesUrl = symbianOrgBaseUrl + "/wiki/api.php?format=xml&action=query&list=allcategories&aclimit=500&acprop=size";
+//var wikiWatchListUrl = "http://en.wikipedia.org/w/api.php?action=query&list=watchlist&wlallrev&wlprop=ids|title|timestamp|user|comment";
+//var wikiWatchListFeed = "/wiki/api.php?action=feedwatchlist&feedformat=rss";
+
+var wikiSearchOptions = [
+    { value: "title", text: "Search in title only" },
+    { value: "text", text: "Full text search" },
+];
+
+function WikiHome () {
+	RssReader.prototype.init.call(this,"Wikipedia", null /*url*/, new WikiFeedPresenter(null), null, wikiResponseParser);	
+
+	this.wikiSearchButton = new FormButton(null, "Search");
+	this.wikiSearchString = new TextField('wikiSearchString', null, "");
+
+	var bookmarksButton = new NavigationButton(null, "next.png", "Bookmarks");
+	var historyButton = new NavigationButton(null, "next.png", "History");
+	var languageButton = new NavigationButton(null, "next.png", "Language");
+
+	var self = this;
+	bookmarksButton.addEventListener("ActionPerformed", function(){wikiBookmarksView.previousView = self; wikiBookmarksView.show();});
+	historyButton.addEventListener("ActionPerformed", function(){wikiHistoryView.previousView = self; wikiHistoryView.show();});
+	languageButton.addEventListener("ActionPerformed", function(){languageSelectView.previousView = self; languageSelectView.show();});
+	
+//	this.wikiSearchString.addEventListener("KeyPressed", function(){self.predictiveSearch(0);});
+	this.wikiSearchButton.addEventListener("ActionPerformed", function(){self.search(0);});
+
+	this.addControl(new Label(null, "Search Wiki", null));
+	this.addControl(this.wikiSearchString);
+	this.addControl(this.wikiSearchButton);
+	this.addControl(bookmarksButton);
+	this.addControl(historyButton);
+	this.addControl(languageButton);
+	k.known();
+}
+
+
+WikiHome.prototype = new RssReader();
+WikiHome.prototype.wikiMainPageButton = null;
+WikiHome.prototype.wikiSearchButton = null;
+WikiHome.prototype.wikiSearchString = null;
+WikiHome.prototype.wikiSearchSelection = null;
+WikiHome.prototype.predictiveTimer = null;
+
+var lastWikiSearchWasFrom = 0;
+var lastWikiSearchResultCountWas = 0;
+
+WikiHome.prototype.search = function(from) {
+	try {
+		lastWikiSearchWasFrom = from;
+		var srstring = this.wikiSearchString.getText();
+		var url = this.formSearchUrl(srstring, from, resultsPerPage);
+		var reader = new RssReader("Wiki: " + srstring, url, new WikiFeedPresenter(null), this, wikiResponseParser);
+		reader.show();
+	}catch (X) { alert(X);}
+}
+
+WikiHome.prototype.predictiveSearch = function(from){
+	if ( this.predictiveTimer != null ) {
+		clearInterval(this.predictiveTimer);
+	}
+	var self = this;
+	this.predictiveTimer = setInterval(function() {self.doPredictiveSearch(from), 1000}); 
+}
+
+WikiHome.prototype.doPredictiveSearch = function(from) {
+	if ( this.feedUpdateBroker != undefined && this.feedUpdateBroker != null ) {
+		this.feedUpdateBroker.cancel();
+	}
+	lastWikiSearchWasFrom = from;
+	var srstring = this.wikiSearchString.getText();
+	if (srstring.length <= 1) {
+		return;
+	}
+	var url = this.formSearchUrl( srstring , from, resultsPerPage );
+	this.feedURL = url;
+	this.update(true, false);
+}
+
+
+WikiHome.prototype.formSearchUrl = function(query, offset, limit) {
+	var buf = baseUrl + wikiSearchBaseUrl + query
+	if (offset > 0) {
+		buf += wikiSearchOffsetQueryPart + offset;
+	}
+	buf += wikiSearchLimitQueryPart + limit;
+	return buf;
+}
+
+// abstract function for updating per-view menu
+// only called if window.widget is defined
+WikiHome.prototype.setupMenu = function(){
+	if ( window.widget ) {
+		menu.clear();
+		var self = this;
+		var searchMenuItem = new MenuItem("Search", MENU_ITEM_MAIN_SEARCH); 
+		searchMenuItem.onSelect = function(){wikiHomeView.show();};
+		menu.append(searchMenuItem);
+		var historyMenuItem = new MenuItem("History", MENU_ITEM_MAIN_HISTORY); 
+		historyMenuItem.onSelect = function(){wikiHistoryView.previousView = self; wikiHistoryView.show();};
+		menu.append(historyMenuItem);
+		var bookmarksMenuItem = new MenuItem("Bookmarks", MENU_ITEM_MAIN_BOOKMARKS); 
+		bookmarksMenuItem.onSelect = function(){wikiBookmarksView.previousView = self; wikiBookmarksView.show();};
+		menu.append(bookmarksMenuItem);
+		
+		addHelpMenuItems();		
+	}
+}
+
+WikiHome.prototype.focusFirst = function(){
+	// don't change focus - this is predictive search so stick with text field
+}
+
+WikiHome.prototype.show = function(){
+	View.prototype.show.call(this);
+	if (window.widget) {
+		widget.setNavigationEnabled(true);
+	}
+}
+
+
+// force right soft key to display "Exit" command
+//WikiHome.prototype.setupSoftKeys = function()  {
+//    if (window.widget) {
+//		alert("WikiHome.prototype.setupSoftKeys");
+//		menu.setRightSoftkeyLabel();
+//	}
+//}
+
+
+// //////////////////////////////////////////////////////////////
+// Article view
+function WikiListView(caption){
+	ListView.prototype.init.call(this, null, null);	
+	caption = uniDecode(caption); // can be encoded unicode 
+	var caption = new NavigationButton(1, "titlebar.png", shorten(caption, 30), true);
+	caption.addEventListener("ActionPerformed", function(){wikiHomeView.show();});
+	this.addControl(caption);
+	this.useHistoryForBackButton = 1; // used internally to identify the type 
+}
+
+WikiListView.prototype = new ListView(null,null);
+
+
+WikiListView.prototype.setupMenu = function () {
+	if ( window.widget ) {
+		menu.clear();
+		var self = this;
+		
+		var searchMenuItem = new MenuItem("Search", MENU_ITEM_READER_SEARCH); 
+		searchMenuItem.onSelect = function(){wikiHomeView.show();};
+		menu.append(searchMenuItem);
+
+		var bookmarkMenuItem = new MenuItem("Add bookmark", MENU_ITEM_MAIN_ADD_BOOKMARK); 
+		bookmarkMenuItem.onSelect = function(){wikiBookmarksView.addItem(pageBeingShown, pageBeingShownContent, pageBeingShownBase);};
+		menu.append(bookmarkMenuItem);
+
+		var backMenuItem = new MenuItem("Back", MENU_ITEM_MAIN_BACK);
+		backMenuItem.onSelect = function(){self.goBack();};
+		menu.append(backMenuItem);
+
+		if (wikiHistoryView.hasNext()) {
+			var forwardMenuItem = new MenuItem("Forward", MENU_ITEM_MAIN_NEXT);
+			forwardMenuItem.onSelect = function(){wikiHistoryView.go(1);};
+			menu.append(forwardMenuItem);
+		}
+		
+		var historyMenuItem = new MenuItem("History", MENU_ITEM_MAIN_HISTORY); 
+		historyMenuItem.onSelect = function(){wikiHistoryView.previousView = self; wikiHistoryView.show();};
+		menu.append(historyMenuItem);
+
+		var bookmarksMenuItem = new MenuItem("Bookmarks", MENU_ITEM_MAIN_BOOKMARKS); 
+		bookmarksMenuItem.onSelect = function(){wikiBookmarksView.previousView = self; wikiBookmarksView.show();};
+		menu.append(bookmarksMenuItem);
+
+		addHelpMenuItems();
+		
+	}
+
+}
+
+WikiListView.prototype.show = function(){
+	View.prototype.show.call(this);
+	if (window.widget) {
+		widget.setNavigationEnabled(true);
+	}
+}
+
+WikiListView.prototype.setupPreviousView = function() {
+	if ( uiManager.currentView.useHistoryForBackButton != undefined ) {
+		this.useHistoryForBackButton = true;
+		// this signals to uiManager that we want a back button.
+		// actual value is not used because useHistoryForBackButton = true
+		this.previousView = wikiHistoryView;
+	} else {
+		this.useHistoryForBackButton = false;
+		this.previousView = uiManager.currentView;
+	}
+}
+
+WikiListView.prototype.goBack = function() {
+	if (this.useHistoryForBackButton) {
+		wikiHistoryView.go(-1);
+	} else {
+		View.prototype.goBack.call(this);
+	}
+}
+
+
+// /////////////////////////////////////////////////////////////////////////////
+// RssReader customisations
+
+// response parser for forum groups
+function wikiResponseParser(broker, responseStatus, xmlDoc) {
+    if (responseStatus == 200 && xmlDoc != null) {
+		// for compatibility with rss
+		var lastModified = new Date();
+		
+        // init result items array
+        var items = [];
+
+		var elements = xmlDoc.getElementsByTagName("p");
+
+		for (var i = 0; i < elements.length; i++) {
+			var pagetitle = elements[i].getAttribute("title");
+            items.push({ id: ""+i, title: pagetitle});
+		}
+
+		lastWikiSearchResultCountWas = elements.length;
+        // update was completed successfully
+        return { status: "ok", lastModified: lastModified, items: items };
+    } else {
+        // update failed
+        return { status: "error" };
+    }
+}
+
+
+
+// ////////////////////////////////////////////////////////////////////////////
+// FeedPresenter implementation for full search results view
+function WikiFeedPresenter(rssreader){
+	if (rssreader) {
+		this.init(rssreader);
+	}
+}
+
+// WikiFeedPresenter is a subclass of ButtonFeedPresenter
+WikiFeedPresenter.prototype = new ButtonFeedPresenter(null);
+
+// WikiFeedPresenter "Constructor"
+WikiFeedPresenter.prototype.init = function(rssreader) {
+	ButtonFeedPresenter.prototype.init.call(this, rssreader);
+}
+
+// Handle the click on a specific item
+WikiFeedPresenter.prototype.feedClicked = function(event){
+	var buttonid = event.source.id;
+	
+	if (buttonid == "Next page") {
+		wikiHomeView.search(lastWikiSearchWasFrom + resultsPerPage);
+	}
+	else if (buttonid == "Previous page") {
+		var from = lastWikiSearchWasFrom - resultsPerPage; 
+		if ( from < 0 ) from = 0;
+		wikiHomeView.search(from);
+	}
+	else {
+		// show article
+		var title = this.items[buttonid].title;
+		wikiBrowse(title);
+	}
+}
+
+// Create and add controls to be shown before items list.
+WikiFeedPresenter.prototype.addFooterItems = function(){
+    var self = this;
+	if (lastWikiSearchResultCountWas == resultsPerPage) {
+		var nextPageButton = new NavigationButton("Next page", "next.png", "Next page");
+		nextPageButton.addEventListener("ActionPerformed", function(event){ self.feedClicked(event); });
+		this.rssreader.addFeedItemControl(nextPageButton);
+	}
+	if (lastWikiSearchWasFrom > 0) {
+		var prevPageButton = new NavigationButton("Previous page", "prev.png", "Previous page");
+		prevPageButton.addEventListener("ActionPerformed", function(event) { self.feedClicked(event); });
+		this.rssreader.addFeedItemControl(prevPageButton);
+	}
+}
+
+
+// /////////////////////////////////////////////////////////////////////////////////
+// Browse / view wiki pages in 'printable format'
+var wikiAjax;
+var pageBeingShown;
+var pageBeingShownBase;
+var pageBeingShownContent;
+var gDontAddToHistory;
+var wikiBrowseCancelled = false;
+var gViewCache = new ViewCache(10);
+
+function wikiBrowse(page, dontAddToHistory, baseUrl) {
+	pageBeingShown = page;
+	if ( baseUrl != undefined && baseUrl != null ){
+		pageBeingShownBase = baseUrl;
+	} else {
+		pageBeingShownBase = wikiViewPageUrlBase;
+	}
+	//alert("page=" + pageBeingShown + ", baseUrl=" + pageBeingShownBase);
+	if ( dontAddToHistory != undefined || dontAddToHistory == true) {
+		gDontAddToHistory = true;
+	} else {
+		gDontAddToHistory = false;
+	}
+	wikiBrowseCancelled = false;
+	var t = page.replace(/_/g, ' ');
+	var v = gViewCache.getView(t);
+	if ( v != undefined && v != null ) {
+		v.setupPreviousView();
+		v.show();
+		return;
+	}
+	try {
+		pageBeingShownContent = null;
+		uiManager.showNotification(-1, "wait", "Loading page...", -1);
+		if (page) {
+		
+			wikiAjax = new Ajax();
+			
+			wikiAjax.onreadystatechange = function(){
+				wikiPageDownloadStateChanged();
+			};
+			
+			//		var url = wikiViewPageUrlBase  + encodeURIComponent(page) + wikiPrintableParam; 
+			var url = pageBeingShownBase + encodeURIComponent(page) + wikiPrintableParam;
+			//alert("url: " + url);
+			//		var url = wapediaArticleBase + page 
+			// initiate the request
+			wikiAjax.open("GET", url, true);
+			wikiAjax.send(null);
+			
+			if (window.widget) {
+				menu.setRightSoftkeyLabel("Cancel", function(){
+					wikiBrowseCancel();
+				});
+			}	
+			
+		}
+	} catch(xx) { alert(xx);}
+}
+
+function wikiBrowseCancel() {
+	wikiBrowseCancelled = true;
+	wikiAjax.abort();
+}
+
+function wikiPageDownloadStateChanged() {
+	if ( wikiBrowseCancelled ) {
+		return;
+	}
+    if (wikiAjax.readyState == 4) {
+		uiManager.hideNotification();
+		try {
+			showWikiPage(pageBeingShown, wikiAjax.responseText);
+		}catch(xx) { alert(xx);}
+	}
+}
+
+function showWikiPage(title, html){
+	// ensure no underscores
+	title = title.replace(/_/g, ' ');
+	title = uniDecode(title);
+	pageBeingShown = title;
+	pageBeingShownContent = html;
+	if (false == gDontAddToHistory) {
+		wikiHistoryView.addItem(title, html, pageBeingShownBase);
+	}
+	var start = html.indexOf('<div id="bodyContent">');
+	var end = findDivEnd(html, start);
+	var pageView = new WikiListView(pageBeingShown);
+	var text = html.substring(start, end);
+//	text = stripExtStyle(text);
+//	text = modWikiBox(text, 'class="box"');
+//	text = modWikiBox(text, 'class="vertical-navbox');
+//	text = modWikiBox(text, 'class="infobox"');
+	text = stripStylesFromTag(text, "table", "box"); 
+	text = stripStylesFromTag(text, "table", "infobox"); 
+	text = stripStylesFromTag(text, "table", "navbox"); 
+	text = stripStylesFromTag(text, "table", "vertical-navbox"); 
+	text = stripStylesFromTag(text, "div", "thumbinner");
+	// replace inline float: right;
+	text = text.replace(/float: right|float:right/g, "clear:both; width: 95%; display:block");
+	text = text.replace(/clear:right|clear: right/g, "");
+	text = modWikiLinks(text);
+	
+	var docModel = ParseIntoDocModel(text);
+	var preamble = new ContentPanel(null, "Overview", docModel.preface, true, true);
+	pageView.addControl(preamble);
+	for (var i = 0; i < docModel.sections.length; i++) {
+		if ( docModel.sections[i].caption == "Contents" ) {
+			continue;
+		}
+		var control = new ContentPanel(
+			null, 
+			docModel.sections[i].caption, 
+			docModel.sections[i].content, 
+			true, false); // foldable & expanded
+		pageView.addControl(control);
+	}
+	pageView.setupPreviousView();
+	gViewCache.addView(title,pageView);
+	pageView.show();
+}
+
+// ///////////////////////////////////////////////////////////////////////
+// Parsing and modding HTML to fit
+
+function modWikiLinks(text) {
+//	var tmp = text;//.replace(/ src="/g, ' src="http://www.wikipedia.org');
+	// images sorted. now links
+	var tmp = text.replace(/65em/g, '100%');
+	var strToLookFor = ' href="/wiki/'; //index.php/';
+
+//	var tmp = text.replace(/ src="/g, ' src="http://wapedia.mobi');
+//	// images sorted. now links
+//	var strToLookFor = ' href="/en/';
+
+	var from = 0;
+	var ind = tmp.indexOf(strToLookFor);
+	var buf ="";
+	while ( ind > 0 ) {
+		buf = buf + tmp.substring(from, ind);
+		// extract page name
+		var ind2 = tmp.indexOf('"', ind + strToLookFor.length);
+		var pageName = tmp.substring(ind + strToLookFor.length, ind2);
+		buf += " style=\"text-decoration: underline;\""
+		buf += " href=\"JavaScript:void(0)\"";
+		buf += " onclick=\"event.stopPropagation();wikiBrowse(uniDecode('" + pageName.replace(/'/g, "\'") + "')); return false;\"";
+		from = ind2;
+		ind = tmp.indexOf(strToLookFor, from);
+	}
+	buf = buf + tmp.substring(from);
+	return buf; 
+}
+
+function stripExtStyle(text) {
+	var ret = text.replace(/style=\".+?\"/g, "");
+	return ret;
+}
+
+function stripStylesFromTag(text, tag, style) {
+	var key = "<" + tag + " ";
+	var ind = text.indexOf(key);
+	if ( ind == -1 ) return text;
+	var buf = "";
+	var prevind = 0;
+	while(ind != -1 ) {
+		var ind2 = text.indexOf(">", ind);
+		if ( ind2 == -1 ) {
+			// something's wrong, return unedited
+			return text; 
+		}
+		var tag = text.substring(ind, ind2+1);
+		if ( style != undefined ) {
+			if ( tag.indexOf(style) != -1 ) {
+				tag = stripExtStyle(tag);
+			}
+		} else {
+			tag = stripExtStyle(tag);
+		}
+		buf += text.substring(prevind, ind);
+		buf += tag;
+		prevind = ind2+1;
+		ind = text.indexOf(key, prevind );
+	}
+	buf += text.substring(prevind);
+	return buf;
+}
+
+function findDivEnd(text, from) {
+	var openDivCount = 1;
+	var divind = text.indexOf("<div", from+1);
+	var cdivind = text.indexOf("</div", from+1);
+	var pos = from;
+	while ( openDivCount > 0 && divind > 0 && cdivind > 0 ) {
+		pos = Math.min(divind, cdivind);
+		if ( pos == divind ) {
+			openDivCount ++;
+		}
+		if ( pos == cdivind ) {
+			openDivCount --;
+		}
+		divind = text.indexOf("<div", pos+1);
+		cdivind = text.indexOf("</div", pos+1);
+	}
+	return pos;
+}
+
+
+
+function DocModel(){
+	this.preface = null;
+	this.sections = new Array();
+}
+
+
+function DocSection(caption, content) {
+	this.caption = caption;
+	this.content = content;
+}
+
+
+function ParseIntoDocModel(text) {
+	var model = new DocModel(); 
+	var ind = text.indexOf("<h2");
+	if ( ind == -1 ) {
+		model.preface = text;
+		return model;
+	}
+	
+	model.preface = text.substring(0,ind);
+	while (ind > 0) {
+		text = text.substring(ind);
+		ind = 0;
+		var ind2 = text.indexOf("</h2>");
+		var caption = text.substring(ind+4, ind2);
+		text = text.substring(ind2+5);
+		ind = text.indexOf("<h2");
+		var endind = ind;
+		if ( endind == -1 ) {
+			endind = text.length-1;
+		}
+		var content = text.substring(0,endind);
+		var section = new DocSection(caption, content);
+		model.sections.push(section);
+	}
+	return model;
+}
+
+
+
+
+
+
+
+// also for vertical-navbox,
+// clx = 'class="box"' 
+//function modWikiBox(text, clx) {
+//	var ind = text.indexOf(clx);
+//	if ( ind == -1 ) return text;
+//	var buf = "";
+//	var prevind = 0;
+//	while(ind != -1 ) {
+//		var ind2 = text.lastIndexOf("<table ", ind);
+//		if ( ind2 == -1 ) {
+//			// something's wrong, return unedited
+//			return text; 
+//		}
+//		var substr = text.substring(ind2+1, ind);
+//		if (substr.indexOf(">") == -1 && substr.indexOf("<") == -1 ) {
+//			// got it
+//			buf += text.substring(prevind, ind2 + 7);
+//		} else {
+//			// not it
+//			buf += text.substring(prevind, ind);
+//		}
+//		prevind = ind;
+//		ind = text.indexOf(clx, prevind + 1);
+//	}
+//	buf += text.substring(prevind);
+//	return buf;
+//}
+//
+//function modDivs(text, clx) {
+//	var key = "<div " + clx;
+//	var ind = text.indexOf(key);
+//	if ( ind == -1 ) return text;
+//	var buf = "";
+//	var prevind = 0;
+//	while(ind != -1 ) {
+//		var ind2 = text.indexOf(">", ind);
+//		if ( ind2 == -1 ) {
+//			// something's wrong, return unedited
+//			return text; 
+//		}
+//		buf += text.substring(prevind, ind + key.length);
+//		prevind = ind2;
+//		ind = text.indexOf(key, prevind );
+//	}
+//	buf += text.substring(prevind);
+//	return buf;
+//}
+//
+