inicio mail me! sindicaci;ón

A Wiki written in haXe

A while ago now, i writ a piece about haXe, a language and compiler which pits itself as a “toolbox for the web developer”.

Now i thought haXe was a great idea, with a great potential for consolidating the mess that is web development. But at the time, i couldn’t find any examples of its full use out in the field.

That was until today, when i discovered MyMiniCity!

I have heard that MyMiniCity is the first example of a web based game completely written using haXe. The back-end appears to run on mod_neko, while the front-end uses a mix of JavaScript and Flash, both compiled using haXe (from what i can tell at least).

Getting to the point…

Now i shall get to the point. I was so impressed with MyMiniCity that i decided to have a go at writing a Wiki in haXe. This pretty much took me most of the day as i had to make heads and tails of haXe’s library’s.

In any case, ended up with something which kind of works. For the code, see overleaf.

<!-more->

The code

Beware! this code ain’t pretty. But it works for the most part. Note that you might also have to make a dummy file called “macros.mtt”.

index.hxml


-cp /usr/lib/haxe/lib/mtwin/1,2,6
-neko Index.n
-main Index

Index.hx



// Main web application class.

import mtwin.web.Handler;

class Page extends neko.db.Object {
public var id : Int;
public var name : String;
public var content : String;

public var last_edited : Date;

public function toHTML() : String
{
return mtwin.text.Text2Xhtml.transform(content);
}

public static var manager = new neko.db.Manager<Page>(Page);
}

class Index {
// mtwin.web.Request represents the current http request with url, parameters, etc...
static var request : mtwin.web.Request;
// for this example we will use mtwin.templo XHTML template engine
static public var template : mtwin.templo.Loader;
// this is some dynamic template context for templo
static public var context : Dynamic;

// Instance vars
static var cnx : neko.db.Connection;

public static function main(){
mtwin.templo.Loader.BASE_DIR = "/Users/jamesu/Projects/Experiments/haxe/web/";
mtwin.templo.Loader.TMP_DIR = "/tmp/";
context = Reflect.empty();
template = null;

request = new mtwin.web.Request();

// connect to database
cnx = neko.db.Mysql.connect({
host : "localhost",
port : 3306,
database : "HaxeWiki",
user : "root",
pass : "",
socket : null
});

neko.db.Manager.cnx = cnx;
neko.db.Manager.initialize();

// creates the main application handler
var handler = new WikiHandler();

// little check to avoid index.n in path
var level = if (request.getPathInfoPart(0) == "index.n") 1 else 0;

// start processing the request starting from specified path info part
handler.execute(request, level);

// if the templo template is defined, we execute it
if (template != null){
neko.Web.setHeader("Context-Type", "text/html; charset=UTF-8");
neko.Lib.print(template.execute(context));
}

// close database connection
neko.db.Manager.cleanup();
cnx.close();
}
}

class WikiHandler extends Handler<String> {

public function new(){
super();

// Edit page
free("edit", "editpage.mtt", doEditWikiPage);
}

// Overide execute so we can process wiki pages
override public function execute( request:mtwin.web.Request, ?pathLevel:Int ){
if (pathLevel == null)
pathLevel = 0;

var part = request.getPathInfoPart(pathLevel);

this.request = request;
this.level = pathLevel;

if (part == "")
part = "default";

part = part.toLowerCase();
initialize();

// Check for special wiki pages
if (actions.exists(part)){
actions.get(part)();
return;
}

doWikiPage(part);
}

function doWikiPage(title: String){
var context = Index.context;

// Search for wiki page in database
var wikipages = Page.manager.search({name : title}, true);
var wikipage : Page = wikipages.isEmpty() ? null : wikipages.first();

if (wikipage == null)
{
context.wikipage = new Page();
context.wikipage.name = title;
context.wikipage.content = '';
context.wikipage_new = true;
prepareTemplate("editpage.mtt");
}
else
{
context.wikipage = wikipage;
prepareTemplate("viewpage.mtt");
}
}

function doEditWikiPage(){
var context = Index.context;

var realtitle = request.get('name').toLowerCase();
var wikipages = Page.manager.search({name : realtitle}, true);
var wikipage : Page = wikipages.isEmpty() ? null : wikipages.first();

if (wikipage == null)
{
context.wikipage_new = true;
wikipage = new Page();
wikipage.name = realtitle;
}
else
{
context.wikipage_new = false;
}
context.wikipage = wikipage;

if (request.get('content') != null)
wikipage.content = request.get('content');

// Skip rest if not POST'ing
if (neko.Web.getPostData() == null)
return;

if (context.wikipage_new)
{
// Make page
wikipage.last_edited = Date.now();

wikipage.insert();
neko.Web.redirect("/" + wikipage.name);
}
else
{
// Edit page
wikipage.last_edited = Date.now();

wikipage.update();
neko.Web.redirect("/" + wikipage.name);
}
}

// same as above
override function prepareTemplate( t:String ){
Index.template = new mtwin.templo.Loader(t);
}
}


database.sql

MySQL schema.

CREATE TABLE Page (
id int(10) unsigned NOT NULL auto_increment,
name varchar(40) NOT NULL,
content TEXT NOT NULL DEFAULT '',
last_edited datetime default NULL,
PRIMARY KEY (id)
);

viewpage.mtt



<html>
<head>
<title>Viewing page ::wikipage.name::</title>
</head>

<body>
<h1>::wikipage.name::</h1>
<div id="content">
::raw wikipage.toHTML()::
</div>
<p><a href="/edit?name=::wikipage.name::">Edit page</a> (Last edited : ::wikipage.last_edited::)</p>
</body>
</html>

editpage.mtt


<html>
<head>
::if (!wikipage_newl)::
<title>Editing page ::wikipage.name::</title>
::else::
<title>New page</title>
::end::
</head>

<body>
<h1>Edit page</h1>
<form method="post" action="/edit">
<input type="hidden" name="name" value="::wikipage.name::"/>
<textarea name="content" rows="10" cols="50">::wikipage.content::</textarea>
::if !wikipage_new::
<input type="submit" value="Edit"/>
::else::
<input type="submit" value="Save"/>
::end::
</form>
</body>
</html>

Instructions

Assuming you have got haXe installed, but never got the web stuff working you might want to do the following:

  1. sudo haxelib install mtwin
  2. cd /usr/lib/haxe/lib/mtwin/1,2,6/mtwin/templo
  3. sudo haxe temploc.hxml
  4. sudo cp temploc /usr/bin/

Then something like this should suffice to get the wiki code running:

  1. mysql -u root HaxeWiki < database.sql
  2. haxe index.hxml
  3. nekotools server -rewrite

And you can make wiki

  • [haXe] - Présentation à 24C3

    Si vous avez ne savez pas ce qu'est haXe ou Neko, ou encore que vous avez besoin de savoir un peu plus avant d'y consacrer du temps, ce qui suit devrait vous intéresser. Nicolas Cannasse était en Allemagne fin décembre pour présenter son bébé.
blog comments powered by Disqus