Unobtrusive Javascript Obfuscates Event Handling - javascript

You know what I liked best about obtrusive javascript? You always knew what it was going to do when you triggered an event.
<a onclick="thisHappens()" />
Now that everybody's drinking the unobtrusive kool-aid it's not so obvious. Calls to bind events can happen on any line of any number of javascript file that get included on your page. This might not be a problem if you're the only developer, or if your team has some kind of convention for binding eventhandlers like always using a certain format of CSS class. In the real world though, it makes it hard to understand your code.
DOM browsers like Firebug seem like they could help, but it's still time consuming to browse all of an element's event handler properties just to find one that executes the code you're looking for. Even then it usually just tells you it's an anonymous function() with no line number.
The technique I've found for discovering what JS code gets executed when events are triggered is to use Safari's Profiling tool which can tell you what JS gets executed in a certain period of time, but that can sometimes be a lot of JS to hunt through.
There's got to be a faster way to find out what's happening when I click an element. Can someone please enlighten me?

Check out Visual Event... it's a bookmarklet you can use to expose events on a page.

If you're using jQuery you can take advantage of its advanced event system and inspect the function bodies of event handlers attached:
$('body').click(function(){ alert('test' )})
var foo = $('body').data('events');
// you can query $.data( object, 'events' ) and get an object back, then see what events are attached to it.
$.each( foo.click, function(i,o) {
alert(i) // guid of the event
alert(o) // the function definition of the event handler
});
Or you could implement your own event system.

To answer your question, try using the Firebug command line. This will let you use JavaScript to quickly grab an element by an ID, and then iterate through its listeners. Often, if used with console.log, you'll even be able to get the function definitions.
Now, to defend the unobtrusive:
The benefit I find in unobtrusive JavaScript is that it is a lot easier for me to see the DOM for what it is. That said, I feel that it is generally bad practice to create anonymous functions (with only few exceptions). (The biggest fault I find with JQuery is actually in their documentation. Anonymous functions can exist in a nether-world where failure does not lead to useful output, yet JQuery has made them standard.) I generally have the policy of only using anonymous functions if I need to use something like bindAsListener from Prototype.
Further, if the JS files are properly divided, they will only be addressing one sub-set of the DOM at a time. I have an "ordered checkbox" library, it is in only one JS file which then gets re-used in other projects. I'll also generally have all of the methods of a given sub-library as member methods of either a JSON object or a class and I have one object/class per js file (just as if I were doing everything in a more formalized language). If I have a question about my "form validation code", I will look at the formValidation object in formvalidation.js.
At the same time, I'll agree that sometimes things can become obtuse this way, especially when dealing with others. But disorganized code is disorganized code, and it is impossible to avoid unless you are working by yourself and are a good programmer.
In the end, though, I would rather deal with using /* */ to comment out most of two or three js files to find misbehaving code, then go through the HTML and remove the onclick attributes.

Calling it "kool-aid" seems unfair. DOM Level 2 events solve specific problems with inline event handling, like the conflicts that always result. I don't look back to writing code to use window.onload that has to check whether someone else has assigned it before, and sometimes having it overriden by accident or out of sloppiness. It also ensures a better separation of the structure (HTML) and behaviour (JS) layers. All in all, it's a good thing.
Regarding debugging, I don't think there's any way to solve the event handlers being anonymous functions, other than nagging the authors to use named functions where possible. If you can, tell them that it produces more meaningful call stacks and makes the code more maintainable.

One thing: you shouldn't be able to see what will happen in JavaScript by looking at the HTML code. What nuisance is that? HTML is for structure.
If you want to check what events are bound to certain elements, there's a bookmarklet called visual event for now, and firebug 1.6 (IIRC) will have some sort of event inspector.

Related

javascript - using function calls in html - bad or good?

Using angular brings lot of weird style of code. For example I always thought that this
<button onclick="myFunction()">Click me</button>
style I should not ever use, except when I would be lazy and want quick and dirty code. And I never used such style in projects and also I even thinked that this is bad.
Now when I see angular
here is the example:
<div enter="loadMoreTweets()">Roll over to load more tweets</div>
which is from there
http://www.thinkster.io/pick/IgQdYAAt9V/angularjs-directives-talking-to-controllers
which is good style by the tutorial. I dont get it. So then it means earlier example with onclick is also perfectly good? Then why nobody uses it at least these days when people use lot of jquery for example?
Let me cite from a book Angular, by Brad Green & Shyam Seshardi
Chapter 2 ... A Few Words on Unobtrusive JavaScript
The idea of unobtrusive JavaScript has been interpreted many ways, but the rationale
for this style of coding is something along the following lines:
Not everyone’s browser supports JavaScript. Let everyone see all of your content and use your app without needing to execute code in the
browser.
Some folks use browsers that work differently. Visually impaired folks who use screen-readers and some mobile phone users can’t use
sites with JavaScript.
Javascript works differently across different platforms. IE is usually the culprit here. You need to put in different event-handling
code depending on the browser.
These event handlers reference functions in the global namespace. It will cause you headaches when you try to integrate other libraries
with functions of the same names.
These event handlers combine structure and behavior. This makes your code more difficult to maintain, extend, and understand.
In most ways, life was better when you wrote JavaScript in this style.
One thing that was not better, however, was code complexity and
readability. Instead of declaring your event handler actions with the
element they act on, you usually had to assign IDs to these elements,
get a reference to the element, and set up event handlers with
callbacks...
...
In Angular, we decided to reexamine the problem.
The world has changed since these concepts were born...
... for most inline event handlers Angular has an equivalent in the form of
ng-eventhandler="expression" where eventhandler would be replaced by
click, mousedown, change, and so on. If you want to get notified when
a user clicks on an element, you simply use the ng-click directive
like this:
<div ng-click="doSomething()">...</div>
Is your brain saying “No, no, no! Bad, bad, bad!”? The good news is
that you can relax.
These directives differ from their event handler predecessors in that
they:
Behave the same in every browser. Angular takes care of the differences for you.
Do not operate on the global namespace. The expressions you specify can
To get more details, read the book: http://www.amazon.com/AngularJS-Brad-Green/dp/1449344852
EXTEND
Following the discussion in comments, I would like to add a more explanation.
As stated here: Wikipedia - AngularJS:
Angular is a framework, which goal is to augment browser-based applications with model–view–controller (MVC) capability, in an effort to make both development and testing easier
The Model–view–controller, a short extract from wikipedia:
A controller can send commands to the model to update the model's state (e.g., editing a document). It can also send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document).
A model notifies its associated views and controllers when there has been a change in its state. This notification allows views to update their presentation, and the controllers to change the available set of commands. In some cases an MVC implementation might instead be "passive," so that other components must poll the model for updates rather than being notified.
A view is told by the controller all the information it needs for generating an output representation to the user. It can also provide generic mechanisms to inform the controller of user input.
Summary:
The most important part here, is the fact, that View can publish the Controllers actions to the user. And this is exactly what the Function calls in HTML do represent.
This is a misunderstanding:
Using angular brings lot of weird style of code. For example I always thought that this
<button onclick="myFunction()">Click me</button>
style I should not ever use, except when I would be lazy and want quick and dirty code. And I never used such style in projects and also I even thinked that this is bad.
It is perfectly valid to use that style of code if you can decide what event handler to attach to the button when you render the HTML code. With jQuery we see many dynamically attached event handlers because many times the elements themselves are dynamically inserted or whether to attach an event listener or what to attach is dynamically decided.

How to have your user script deal with functions and elements that don't exist yet?

When writing user scripts for various websites I often come across the problem of dealing with elements or JS functions that don't exist yet at the time of execution. I'd like to know how to get to those functions or elements.
An obvious solution is a setTimeout, but that's very inelegant. I've also experimented with the various events like DOMContentLoaded and window.onload, but I often find that these events are still too early, due to content and code being dynamically generated/loaded afterwards.
Make sure that whatever you're loading emits an event, that you can hook into.
If you're loading a script file you can hook into the onload event. If you do an AJAX call you can hook into the onreadystatechange event.
These are some useful native events.
You can also make more custom events by using Promises.
var modules = {/* */};
var foo = modules.load("foo"); // returns a promise
foo.done(function (foo_module) {
// we now have the foo-module
});
requirejs might be worthwhile to look at, just to see how they do things.
As for promises, this is a good read: What’s so great about JavaScript Promises?
Make sure you're not doing something wrong before jumping to conclusions. Like, remember that user scripts in Chrome for example, are sandboxed, and you'll need to jump through a hoop or two to even access code on the target page. For small scripts, I suggest the "Location Hack". https://stackoverflow.com/a/5006952/125938

JavaScript Hacking

I am trying to figure out any and all ways to prevent CSS modification and DOM modification of specific elements. I understand this might not be completely possible or that a talented developer could get around it, however, I am not so concerned about people potentially getting around it, I just want to stop newbies. In particular those using jQuery. An example would be to delete certain properties on prototype objects etc..
But why you need/want this? If you want to "protect" your code, you can use some JavaScript minifier as Google Closure Compiler or YUI compressor. They will rewrite your script and it will be difficult to read by a human. Nowadays, with tools like Firebug and Grease Monkey it's almost impossible to do what you want.
Don't use CSS or JavaScript :p Depend completely on server side checks etc.
You cannot stop anyone from messing with your javascript or your objects in the page. The way the browser is designed, your code and objects in your page are simply not protected. Everything from bookmarklets to javascript entered at a console to browser plug-ins can mess with your page and code and variables. That is the architecture of a browser.
What you can do is make things a little more difficult such that a little more work is required for some things. Here are a couple of things you could do:
Obfuscating/compressing/minimizing your code will do things like remove comments, remove whitespace, remove some linebreaks, shorten variable names, etc... That does not prevent anyone from modifying things, but does make it more work to understand and figure out.
Putting variables inside closures and not using globals. This makes it harder to directly modify variables from outside of your scripts.
Keep all important data and secrets on your server. Use ajax calls to ask the server to carry out operations using that data or secrets such that the important information is never available in the browser client.
You cannot keep anyone from modifying the DOM. There simply are no protections against that. Your code can check the DOM and refuse to operate if the DOM has been messed with in non-standard ways. But, of course, the code would then be modified to remove that check too.
If you are looking for a jquery specific solution a crude approach will involve altering the jQuery ($) function and replacing it with a custom one that delegates to the original function only if the provided selector does not match the element you want to secure.
(function(){
jQueryOrig = jQuery;
window.jQuery = window.$ = function(){
if (jQueryOrig("#secure").is(arguments[0])) {
throw new Error("Security breach");
} else return jQueryOrig.apply(this, arguments);
}
}());
Of course people using direct DOM manipulation would not be affected.
Also, if you are actually including arbitrary third party code in your production code, you should take a look at Caja ( http://code.google.com/p/google-caja/ ), which limits users to a subset of javascript capabilities. There is a good explanation regarding Caja here : http://due-diligence.typepad.com/blog/2008/04/web-20-investor.html .
This is possible but requires that the JS file to always be loaded from your server. Using observers you can lock CSS properties and using the on DOM remove/add listeners you can lock it to a parent. This will be enough to discourage most modification.
You can actually go a step further and modify core javascript functions making it nearly impossible to modify the DOM without loading the JS file locally or through a proxy. Further security can be added by doing additional domain checks to make sure the JS file is loaded from where it is supposed to be loaded from.
You can make everything in Flash. In Chrome, there's even a bug that prevents users from opening a console if the flash element has focus (not sure how exactly this works, but you can see an example at http://www.twist-cube.com or http://www.gotmilk.com). Even if users do manage to get a console open (which isn't that hard...), still about all you can do is change the shape of the element.

Controlling the order that event handlers / listeners are executed in

Once again the IE Monster has hit me with an odd problem.
I'm writing some changes into an asp.net site I inherited a while back. One of the problems is that in some pages there are several controls that add Javascript functions as handlers to the onload event (using YUI if that matters). Some of those event handlers assume certain other functions have been executed.
This is well and good in Firefox and IE7 as the handlers seem to execute in order of registration. IE8 on the other hand does this backwards.
I could go with some kind of double-checking approach but given the controls are present in several pages I feel that'd create even more dependencies. So I've started cooking up my own queue class that I push the functions to and can control their execution order. Then I'll register an onload handler that instructs the queue to execute in my preferred order.
I'm part way through that and have started wondering 2 things:
Am I going OTT?
Am I reinventing the wheel?
Anyone have any insights? Any clean solutions that allow me to easily enforce execution order?
I could not find any Standard that would define the call-order of events. This is not an issue this is pure anarchy :D
Also there's hundreds of independent implementations of this pattern, so it is unlikely that they would behave coherently anytime soon.
So yes you're off on your own.
The cleanest and most compatible approach I have, involves registering just one event-handler :D That way the native order becomes irrelevant.
Now the trick is to add your own predictable event-management on top of that - using a library, extending with nodeJS's version for example, depending on your requirements.
Note that JS gives you the freedom to just override the prototype-derived functions, so another possibility is something like this:
function eventify(element){
element._event = {}
element.on = element.addListener = function(evt,fn){ ... }
element.off = element.removeListener = function(evt,fn){ ... }
element.emit function(evt,args...){ ... do it the right way ... }
}
So maybe you are a little off track in considering queues and locking-mechanisms :)

How to listen to elements method calls in Javascript

I would like to listen to method calls.
For example, when an element is appended by anything to the document, I would like to be passed that element to act on it, like:
//somewhere
aParent.appendChild(aChild);
//when the former, a function I defined as listener is called with the aChild as argument
Does anybody know how to do that?
don't know if that's possible with the core functions, but you could always create your own functions, for the actions you want to monitor:
function AppendChild(oParent, oChild) {
// your stuff on oParent
// append oChild
oParent.appendChild(oChild)
}
or, maybe, modify the actual appendChild(), but that would be tricky...
I know that the Dojo Toolkit provides this functionality. You can some explanation here - jump to the section that says "Connecting Functions to One Another". If you are interested, you can look at the source of dojo.connect to see what's going on.
In Firefox you could rewrite Node.prototype.appendChild to call your own function (saving the original appendChild first, then calling it within) to perform additional actions.
Node.prototype._appendChild = Node.prototype.appendChild;
Node.prototype.appendChild = function myFunct(el){....; this._appendChild(el);}
Internet Explorer doesn't implement these interfaces (but there might be a workaround floating around, maybe using .htc..). IE8 will have Element instead of Node.
What you're describing is Aspect Oriented programming. In AOP parlance, your "join point" would be element.appendChild(), and your "advice" is the function that you would like to execute (before and/or after) every matching join point executes.
I've been keenly interested in possibilties for JavaScript AOP this for some time, and I just found this Aspect Oriented Programming and javascript, which looks promising without needed to adopt a big old API. -- I'm really glad that you brought this up. I have uses for this, like temporary logging, timing code segments, etc.
Multiple browsers handle the DOM in different ways, and unfortunately the way IE handles things is not as powerful as the way Mozilla does. The easiest way to do it is by using a custom function like the one that Filini mentioned.
However you could also wrap the different browsers DOM objects in a facade and use it for all element access. This is a bit more work but you would then be able to handle all the browsers in the same way and be able to add/remove listeners with ease. I'm not sure if it would be anymore useful than the custom functions, but worth a look at.

Categories