Friday, November 20, 2009

Homework 3

These are the parts of homework 3:

HW3 Part 3

1. We want to have selectors that can simply find all the tags we are looking for. $(“p”) should return all p tags and allow us to work with them without having to do a for loop. We can be more specific in our search for tags by specifying things like attributes: $(“p[title=’hi’]”) matches all p tags with title “hi”. These selectors return JObjects, and we can manipulate these nodes by calling JObject methods. For example, $(“p”).empty() removes all child nodes of all p tags. We would like to have methods that can change the content of the nodes, insert or remove things in or around them, replace them with something else, and do other such manipulations. We’d also like to do CSS modifications, such as changing the position or height and width of the matched elements. We’d like to have a simple way to add in events, like .hover(), which would do something when the mouse hovers over the selected elements. Other methods would add effects, such as making some elements fade and animating others. We’ll support chaining, where we can call multiple methods on the selected elements. We’d like to add in extensions like if—else to allow control-flow in our JQuery calls. We'll basically be finding and modifying nodes in a more simple way.

2. The Object-Oriented programming model is suitable for our domain. The $(target) function returns an object, the JObject, which has many built in methods that can be used to modify the target tag(s). For example, we can use $(target).addClass(class) to add a class to the matched elements. “target” can be things like ‘p.first’ (selects p tags with class “first”) and ‘p[title=”hi”]’ (selects p takes with the title “hi”). We can add as many methods for the JObject as we want, so the program will be larger but be abstracted so the code stays clean. The users don’t see how the methods are implemented; they just know that they work. They also don’t see how the $(target) function is implemented; from the programmer’s perspective, $ looks like a special keyword and target looks like an object that we are working worth, but really the $ is a function and target is the argument to that function, which returns an object. Users just need to know that $(target) retrieves all of the specified tags and returns JObjects that they can manipulate. $(target) is an abstraction for the for loop going through all the target tags.

We can combine smaller programs into larger ones by supporting chaining. For example, we can do
$(“p”).text(“woot”).wrap(“<div class = ‘line’></div>”)
$(“p”) returns JObjects that correspond to the node in the DOM. For each of these, .text(“woot”) modifies the text contents of the matched “p” elements and returns the resulting JObject. The .wrap() wraps the “p” tag with the div tag, and returns the resulting JObject. We can do as many chains as we want, and, thanks to abstraction, we don’t need to know how this is being implemented as long as we know that each method returns a JObject that we can use another method on. If we know that a chain works, we can add a method on to it without having to know what all the previous methods are doing, so all these previous methods are hidden by abstraction in this sense. Another abstraction example is that functions can be defined elsewhere and passed as arguments into some of the JObject methods, so smaller programs can be combined to become bigger ones.

HW3 Part 4

Javascript is the only really universally-supported language for client-side scripting. It is unreasonable to try to make our language work as a stand-alone scripting language. In that case, there are only really two potential options:
  1. Make our language work as a library on top on Javascript.
  2. Make our language "compile" into Javascript, as in everything will be converted into pure Javascript as opposed to needing a library to support the syntax.
Frontend:
In case 1, Javascript should handle most of the problems with internal representation, since our language would be valid Javascript. In case 2, anything could work. Most likely we would convert to an AST that can be broken down into optimized Javascript. We would have to take care to recognize actual Javascript in the midst of the code and not convert it, as people may want to use Javascript in places our language is insufficient.

The Core Language:
In case 1, the core language will simply be Javascript. All features will be some kind of sugar on top of Javascript. For example, $("a").addClass("b"); would break down to something like this in pseudocode:
find element tags "a" in document
for each element "a" add attribute "class" with value "b"
The desugaring will basically be underlying Javascript functions that will take in the statements and run the actual Javascript needed. $ is a function that returns objects, and the .methods would invoke the methods within those objects. In case 2, the entire langague will have to be completely parsed and interpreted, then formulated into valid Javascript. In a convoluted way this may still be considered "sugar".

Internal Representation:
In case 1, there aren't terribly many ways to do it. The jQuery way of doing is is creating some kind of jQuery object that responds to the appropriate methods, every time a method is called on a jQuery object. In case 2, most likely the code will be converted to an AST or maybe bytecode if we deem that advantageous.

Interpreter/Compiler:
In case 1, the code will simply be interpreted as a Javascript function call, albeit a really long one at times. In case 2, the code will be compiled into Javascript, probably after an intermediary AST step. However, it would be better not to try to do something like bytecode since that would complicate the process greatly.

Debugging:
In case 1, debugging will likely consist of using something like Firebug and the Javascript console, in other words just standard Javascript debugging tools. In case 2, similar tools can be used (if the code actually compiles) and then problems can be found that way, or well-thought-out error messages in the interpreter/compiler and test code in the language could point out flaws.

HW3 Part 1

We will implement a part of jQuery in JavaScript. Given that our only background in JavaScript is from what we learned in this class, we believe that this will be a good exercise in learning more about both Javascript and how jQuery changes how people write Javascript.

1. Traversing through the DOM to modify, add, and remove HTML nodes using JavaScript can be tedious. Finding certain tags and modifying their corresponding nodes and attributes is doable using JavaScript, but it can take too many steps and generate messy code. This is especially true when we want to do something to all instances of a particular tag, such as wrapping them with more markup.
Here is a snippet of ugly JavaScript code found on http://articles.sitepoint.com/article/jquery-javascipt-designers :
function fancyRules() {
if (!document.getElementsByTagName) return;
var hr = document.getElementsByTagName("hr");
for (var i=0; i<hr.length; i++) {
var newhr = hr[i];
var wrapdiv = document.createElement('div');
wrapdiv.className = 'line';
newhr.parentNode.replaceChild(wrapdiv, newhr);
wrapdiv.appendChild(newhr);
}
}
window.onload = fancyRules;
This is what it does: when the page loads, look through all the tags for the tag “hr”. Then for each of them, make a node “div” with a class “line” and wrap the div around the hr. We see that we have to create a new element, call the parent node of the “hr” tag, replace the child of that node, and append the resulting node back to where the “hr” tag was. All of this is within a for loop since we want to do this to every “hr” tag. If we want to, say, do another wrap or perform other such modifications to the node, even more messy code would be required.
We would like to make this more simple. We want an easy way to access HTML nodes and do multiple modifications to them and/or their attributes. In this case, it would be efficient if we just supply one command to get all the “hr” tags (automatic looping) and call a method that uniformly does the wrapping without having to create new elements and variables, and replacing nodes. We’d also like to use abstraction mechanisms mentioned in part 3 that would make programming easier.

2. Experienced programmers may not find it difficult to write this code. However, it is definitely more time consuming, and since so much code is required to do this one task, it is easy to make a mistake, and finding bugs within such long code can be challenging. Doing multiple modifications would require more and more bookkeeping: as seen in the above code, new variables need to be defined to keep track of the nodes we are working with. It can be hard to keep track of which variable does what, especially if we want to do many modifications to the nodes. Beginner programmers can easily make mistakes in all parts of this code, since there are many function calls and fields (e.g., getElementsByTagName(), createElement(), className, replaceChild(), appendChild() ) that the programmer may not be familiar with and passing around of several variables.

3. JavaScript is designed to traverse and modify DOMs, and there really isn’t another language out there that can do it this well. Also, JavaScript is used in millions of web pages, so it would be hard to make everyone switch over to another language to avoid this problem. The best solution is to implement something using proper JavaScript syntax so that users could easily import it into their scripts and use the added functionality. There isn’t really any other language that can do client-side scripting beside JavaScript, and writing a whole new language would be more difficult. Therefore, we would like to make changes by extending the language.

Thursday, November 19, 2009

HW3 Part 2

Since we are just writing a simpler version of jQuery, there is no better language to analyze than jQuery itself.

1. Code Example:
<html>
<head>
<title>qqScript</title>
<style type="text/css">
.under { text-decoration: underline }
</style>

<script type="text/javascript" src="jquery.js"></script>

<script type="text/javascript">
$(document).ready(function(){
$("p > span").hover(function() {
$(this).addClass("under");
},function() {
$(this).removeClass("under");
});
});
</script>
</head>

<body>
<a href="http://jquery.com/">jQuery</a>
<p>This was a <span>triumph</span>.</p>
</body>

</html>
This is a simple jQuery example that demonstrates multiple abilities. Analyzing the code:
$(document).ready(...);
This jQuery code targets the document DOM-node, and executes the method ready. Ready according to documentation basically means "execute the body when it is done loading, but don't wait for images", as opposed to window.onLoad as normally used in Javascript, which waits for everything to finish loading.
$("p > span").hover(onstate,offstate);
The target for this is some kind of selector, which will target any span tag that is a child of a paragraph tag. The hover method takes two arguments, a function to execute for the hover on state, and a function to execute when the mouse leaves the on state. In the above example, it will apply a CSS class that underlines the span when it is hovered.

2. Implementation:

In mixed Javascript and pseudocode:
function $(target){
obj = (find target in DOM);
return JObject(obj);
}

function JObject(obj){
this.target = obj
this.ready = function(block){
(invoke block when obj is loaded)
}
this.hover = function(hover,unhover){
(invoke hover when obj is hovered, and unhover when it is no longer hovered)
}
...
}
All jQuery statements are in something of this form:
$(target).method(args);
I've briefly looked over the source code without really understanding anything in it, but I can deduce that $ is, strangely, the name of a Javascript function. It is given an argument target, and from there returns some JObject that responds to method. All of jQuery's methods should be defined somewhere inside JObject.

Something I'm not too clear on is when something like this happens (as in the hover example above):
$(this).method(args);
I'm not too clear what this would reference in a normal Javascript scenario. It is possible that jQuery has some sort of check built in that redirects this to what it should be, or equally likely that it works fine without tampering. It turns out that this is handled normally by Javascript.