views:

194

answers:

7

The problem: I have a jQuery heavy page that has a built in admin interface. The admin functions only trigger when an admin variable is set. These functions require a second library to work properly and the second file is only included if the user is an admin when the page is first created. The functions will never trigger for normal users and normal users do not get the include for the second library.

Is it bad to reference a function does not exist in the files currently included even if that function can never be called? (does that make sense :)

Pseudocode:

header: (notice that admin.js is not included)

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

script.js: (admin functions referenced but can't be executed)

admin = false; // Assume this

$(".something").dblclick(function(){
 if(admin)
  adminstuff(); // Implemented in admin.js (not included)
 else
  userstuff();
});

Ideas: I suppose two separate files for users and admins could be used but I feel that would be an overly complicated solution (don't want to maintain two large files with only a few lines of difference). The only reason I include a reference to the admin function in this file is I need to attach it to page elements that get refreshed as a part of the script. When jQuery refreshes the page I need to reattach function to interactive elements.

The Question: I want to keep things very simple and not have to include file I don't have to if they will not be used by the user. Is this a good way to do this or should I be going another route?

+2  A: 

I don't think it matters. If it makes you feel better, you can make an empty stub function.

Nosredna
Or even implement a stub function that threw or logged a specific error... Just in case the "never" in "this code will never be hit" proved to be an alias for "rarely".
Shog9
+1  A: 

I don't think there's a dogmatic answer to this in my opinion. What you're doing is...creative. If you're not comfortable with it, that could be a sign to consider other options. But if you're even less comfortable with those then that could be a sign this is the right thing (or maybe the least wrong thing) to do. Ultimately you could mitigate the confusion by commenting the heck out of that line. I wouldn't let yourself get religious over best practices. Just be willing to stand by your choice. You've justified it to me, anyway.

kmorris511
+3  A: 

Good question. It shouldn't cause any JavaScript problems.

Other things to consider: you are potentially exposing your admin capabilities to the world when you do this, which might be useful to hackers. That's probably not much of a concern, but it is something to be aware of.

See also:

Why can I use a function before it’s defined in Javascript?

BarelyFitz
+7  A: 

The code should operate without error, since the admin functions without implementation will not be called. The only thing that is really being wasted is bandwidth to transmit the admin code that is not used.

However, let me caution against security through obscurity. If the user were to view this code and see that there are admin functions that they cannot access, they might get curious and try to download the "admin.js" file and see what these functions do. If your only block to keeping admin functions from being performed is to stop including the file, then some crafty user will probably quickly find a way to call the admin functions when they should not be able to.

If you already do server side authentication/permissions checking for the admin function calls just ignore my previous paragraph :-)

Doug
I believe how many great replies I got while just away to make some tea. I am replying to this one but I want to thank all of you very much! :)This answers my question perfectly! As an aside I do server side checking of permissions on all queries.
Urfe
+1 for mentioning the security ramifications.
Chad Ruppert
+4  A: 

Personally, I would bind (or re-bind) the event in admin.js:

$(function() {

$(".something").dblclick(function(){
  adminstuff();
});

});

function adminstuff()
{
  // ...
}

That way, the adminstuff() call and the function will not be visible to "normal" users.

Philippe Leybaert
This seems like a great alternative solution as I already have a doUpdates() binding function that is called when the page content is changed by the script. This could be done creatively with little to no duplicate code. Very cool!
Urfe
+1  A: 

Javascript is dynamic - it shouldn't care if the functions aren't defined.

If you put your admin functions in a namespace object (probably a good practice anyway), you have a couple of options.

  1. Check for the existence of the function in the admin object
  2. Check for the existence of the admin object (possibly replacing your flag)
  3. Have an operations object instead, where the admin file replaces select functions when it loads. (Even better, use prototypical inheritance to hide them.)
Justin Love
Your number three option sounds exactly like the best thing to do. I had no idea Javascript had this ability! :)
Urfe
+1  A: 

I think you should be wary that you are setting yourself up for massive security issues. It is pretty trivial in firebug to change a variable such as admin to "true", and seeing as admin.js is publically accessible, its not enough to simple not include it on the page, as it is also simple to add another script tag to the page with firebug. A moderately knowledgeable user could easily give themselves admin rights in this scenario. I don't think you should ever rely on a purely client side security model.

micmcg
Every time the server is queried the user's permissions are checked. Changing admin to true in the script and including admin.js would only show a few canned tool-tips and show a few edit buttons. Attempting to interact with anything would throw errors when those interactions hit the server. All I am giving away to the curious are small snippets of the admin interface. Anything that could effect security is done on the server-side and a users credentials are checked first.
Urfe