Tuesday, December 22, 2009

Jaxer in Aptana

I downloaded version 2.02 of Aptana Studio; it is supposed to have Jaxer in it. I cannot find it.

I have looked at many sites for using Jaxer, I am unable to do step 1 in any of these sites. They all refer to some button or menu in Aptana that is grayed out or that I do not have.

I found a good site at IBM that details how to install Jaxer as a stand-alone server on Windows.

It used a simple example demonstrating how to use a callback; of course, it failed. It turns out that the file that it is trying to access, http://update.aptana.com/update/jaxer/win32/version.txt, cannot be accessed.

I created a file on my own server that will report some number in the correct format: .0.9. Now the example works.

I have found the framework for Jaxer. The query string is in Jaxer.parsedUrl.queryparts.

Functions can be run on the server, client or both. A property of the Function object can be used to allow a server function to be called from the client: functionName.proxy = true. The runat property of the script can also be set to server-proxy, which sets the proxy property to true for all functions in the script block.

I have found an excellent introduction to using Jaxer.

Use Jaxer.request.currentFolder to get the absolute path to the current folder.

Use Jaxer.Dir.resolve to get an absolute path to a relative reference.
Jaxer.Dir.resolve(Jaxer.request.currentFolder + "/posts")

Unobtrusive JavaScript does not set event handlers in the HTML tags. Use JavaScript to set the handlers. If the tag is used, then it removes all other handlers.

form.submit is called when a form is submitted programatically, not by clicking a submit button.
form.addEventListener("submit", handler, bool) is called when a submit button in the form is called. The same effect as using onLoad, but onLoad can only register one event.

When overriding submit, it is good to store the old submit method. The new method will not have the default behavior of submitting the form; call the old method to submit the form. This also has an advantage of allowing the current method to be canceled without canceling the entire event. Once an event is canceled using event.preventDefault, it is not possible to enable it again.


<html>
<head>
<title>Submit Events, Handlers and Prototypes</title>
<script type="text/javascript">

function submitFromScript() {
//There is no event object, but 'this' points to the form.
alert("Submitted by calling submit from a script: this = " + this);
//call the original, if it has been set.
if (this.submitPrototype) this.submitPrototype();
}

function submitFromSubmitButton(event) {
alert("Submitted by clicking a submit button in a form");
}

function submitFromWindowSubmitButton(event) {
alert("Submitted by clicking a submit button in a form, caught by window event");
}

function submitFromHandler(event) {
alert("Submitted by clicking submit button and overriding the submit handler for the form");
if (this.submitHandler) this.submitHandler();
}

// Function to change the content of t2
function modifyText(event) {
var t2 = document.getElementById("t2");
alert("modify t2: " + t2);
t2.firstChild.nodeValue = "three";
}

// Function to add event listener to t
function load() {
alert("load")

HTMLFormElement.prototype.submitPrototype = HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = submitFromScript;

var el = document.getElementById("frmPost");
el.submitHandler = el.submit;
el.submit = submitFromHandler;

el.addEventListener("submit", submitFromSubmitButton, false);
el.addEventListener("submit", modifyText, false);

}

window.addEventListener("load", load, false);

</script>
</head>
<body>
<form id="frmPost">
<input type="button" onClick="document.getElementById('frmPost').submit();" value="Submit by Script">
<input type="submit" value="Submit Button">
</form>
<table id="t">
<tr><td id="t1">one</td></tr>
<tr><td id="t2">two</td></tr>
</table>
</body>
</html>


The event handler code should always be run in the client. If it needs to run server code, then it should call a proxy on the server.

When using jQuery and Prototype, they have a conflict with $(). Use jQuery.noConflict() to allow the Prototype definition to prevail.

$(id) only works on the server. Add a function on the client that does the same thing:
function $(id) {
return window.document.getElementById(id);
}


The blog example from this site has errors when accessing files. Use resolve and combine to translate to a path that can be read by the native file system.
Jaxer.Dir.resolve(Jaxer.Dir.combine(Jaxer.request.documentRoot, "blog/posts"));


Here is the modified file that works on a PC.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Write Blog</title>
<script src="lib/prototype/prototype.js" runat="server" type="text/javascript">
</script>
<script src="lib/showdown/showdown.js" runat="server" type="text/javascript">
</script>

<script runat="client" type="text/javascript">

function $(id) {
return window.document.getElementById(id);
}

function onSubmit(evt) {
var newPost = $("txaPostText").value;

if (newPost.length == 0) {
alert("You haven't entered anything.");
}
else {
if (save(newPost)) {
//add the new post
formatPost(newPost);
$("txaPostText").clear();
}
else {
alert("An error occurred. Couldn't save your post.");
}
}
//stop the form from submitting
evt.preventDefault();

$("txaPostText").focus();

}

function onLoad(){
$('frmPost').addEventListener('submit', onSubmit, false);
}

if (window.addEventListener) {
window.addEventListener("load", onLoad, false);
}
</script>
<script runat="server" type="text/javascript">

function serverLoad(){
//create the main posts <DIV>

var posts_div = document.createElement('div');
posts_div.id = 'posts';
document.body.appendChild(posts_div);

var path = Jaxer.Dir.resolve(Jaxer.Dir.combine(Jaxer.request.documentRoot, "blog/posts"));
if (!Jaxer.Dir.exists(path)) {
formatPost("Path does not exist: " + path);
return;
}
var dir = new Jaxer.Dir(path);
var files = dir.readDir().map(function(file){
var post = Jaxer.File.read(Jaxer.Dir.combine(dir.path, file.leaf));
formatPost(post);
});
}

window.addEventListener("serverload", serverLoad, false);

var formatPost = (function(showdown){
return function(content){
var post_div = document.createElement('div');
Element.extend(post_div);
post_div.innerHTML = showdown.makeHtml(content);

// insert new post in the main div
$('posts').appendChild(post_div);
}
})(new Showdown.converter());

function save(text){
try {
var path = Jaxer.Dir.resolve(Jaxer.Dir.combine(Jaxer.request.documentRoot, "blog/posts"));
Jaxer.Log.info(path);
var dir = new Jaxer.Dir(path);
//get the last post number
var lastFileNo = (dir.readDir()).length;
path = Jaxer.Dir.resolve(Jaxer.Dir.combine(dir.path, (lastFileNo + 1) + ".txt"));
Jaxer.Log.info(path);
Jaxer.File.write(path, text);

return true;
}
catch (e) {
Jaxer.Log.error(e);

return false;
}
}
save.proxy = true;
</script>
</head>
<body>
<h1>The Blog Page that Writes Files</h1>
<form id="frmPost" action="">
<textarea rows="10" cols="40" id="txaPostText"></textarea>
<input id="btnPost" type="submit" value="Submit Post"/>
</form>
</body>
</html>

While exploring the Aptana resources, I found that there is a new forum site. The old site has a lot of references to Jaxer, but the new site does not. The jaxer.org site references the old forum, but there is link in the old to the new.

The new forum site has a page for forum for App Studio that has an article on manual plugins. On the link for the Jaxer plugin, I followed these instructions and was able to add Jaxer to Aptana Studio 2.0.2.

Installing this Plugin via Aptana or Eclipse

1. From the Help menu, select Install New Software... to open an Install pop-up window.
2. In the Work with: text box of the Install window, type the URL http://update15.aptana.org/jaxer/25739/ for the update site, and hit the Enter key.
3. In the populated table below, check the box next to the name of the plug-in, and click the Next button.
4. Click the Next button to go to the license page.
5. Choose the option to accept the terms of the license agreement, and click the Finish button.

More things are working now. I am writing test code to see if everything works. I now have access to the samples.

The API shows there is a data object in Jaxer, but it is called clientData.
Jaxer.Cache is Jaxer.CacheManager.
Jaxer.SendOptions does not exist.

Followers