Wikipedia/Wiki.js
author ivanl
Fri, 19 Mar 2010 11:03:38 +0000
changeset 21 f7a5a40d5bc4
parent 20 918767a9c8d3
permissions -rw-r--r--
1.0rc17 Fix blog feed

// ////////////////////////////////////////////////////////////////////////////
// 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;
//}
//