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:
- sudo haxelib install mtwin
- cd /usr/lib/haxe/lib/mtwin/1,2,6/mtwin/templo
- sudo haxe temploc.hxml
- sudo cp temploc /usr/bin/
Then something like this should suffice to get the wiki code running:
- mysql -u root HaxeWiki < database.sql
- haxe index.hxml
- nekotools server -rewrite
And you can make wiki
