Grouping plugin initializations and functions into a single script - javascript

I have a very basic question about grouping (jQuery) plugin initializations-- and really any type of script-- into a single script throughout a website: in my templates, I typically have a "tools.js" file that includes various plugin initializations, click functions and the like. For the sake of ease, neatness and number of server requests, I like to keep these functions/script calls centralized in a single file, however, on certain pages, various scripts won't apply-- say, a fitvids.js script initialization that might be used on one page with a video, and not on another. Thus, I'm wondering if this is problematic in any way, i.e. can this create problems if a certain library isn't included on a given page-- but it's initialization is-- or a selector referenced in a click function is not present on a given page?
Thanks for any insight here.

In my design, I will have only shared code like plugin definitions or common utility methods shared between pages. The functional code like event handlers or plugin initialization for each page will be kept separate.
If there is a cross cutting concern in multiple pages then it will be either converted as a plugin or as a utility method which will be placed in a shared file but the actual usage will be done for each page separately.

If the selector is not present in the DOM and has a click handler in js, it should not be a problem. The reason behind is that the click function is never triggered. It is an issue if the attached handler is executed by any chance and js can't find your selector.

Related

Keep the javascript fully separated from markup on primefaces

I'm working on a web interface with the help of primefaces framework.
In that interface, one of the objectives is to have the code divided in javascript functions that do not share information between each other and they don't allow being invoked by other parts (that eases testing and reduces the number and complexity of possible use-cases).
All "parts" are encapsulated using:
(function (window, document, undefined){
var $ = window.jQuery;
// main content here
})(window,document);
The communication required between each part is minimal and the required one is made using DOM events where an object is passed between each other. (if the event is not caught, it's just a functionality that didn't act. If it caused something to break, the js does not stop working, among other reasons).
This has been working for quite a while with minimal bugs found until I had to work with jsf+primefaces.
By reading the documentation, primefaces has many XML tags that do not map to HTML tags. One of the main ones I have to work with is <p:ajax>.
This tag was many on*-like attributes whose concept works much like the HTML3's ideology of writing javascript in HTML's "on*" attributes. Still, those <p:ajax> are always attached to specific XML elements like <h:inputText> or <p:commandButton> and that's where I started looking at.
In primefaces documentation, there's information about the inline on* attributes but I was fully unable to find information about jsf or primefaces' personalized DOM events.
How it appears with primefaces, I'm forced to change the javascript code so that functions/methods can be called inline in the HTML. That would require a lot of work also because, depending on the situation, the js code might even not be there (because the feature it enables is not required for that page).
How do I make the system on primefaces such that I have my javascript fully detached from the jsf/primefaces XML (and the whole HTML output I can manage).
EDIT:
I ran out of ideas on where to look at, I'll work on looking at primefaces source code now. I may get better luck there.
EDIT:
Meanwhile I got some ideas for searching using different keywords and I found this(see: "Client Side API"):
http://courses.coreservlets.com/Course-Materials/pdf/jsf/primefaces/users-guide/p-ajaxStatus.pdf
This is near what I wanted but it seems like it does not exist for the elements I mentioned above. I'll work on continuing searching for more.
After some testing, investigation, etc... I was finally able to understand the whole story of what was happening.
Primefaces was doing everything right after all! The <p:ajax> has the correct code to send all the events it should! The problem lies in jQuery itself.
jQuery's trigger() method (and it's shortcuts) works in such way that it handles all events directly inside jQuery bubbling and calling the callbacks registered using on() (or any of the shorthands).
The main issue in jQuery is that it only resend the "click" event to the DOM because it tries to use a method in the DOM element with the same name as the event. In the DOM, (at the moment) the only situation when that happens is the "click" event. That's why I was getting the click event and not the rest of the events.
With that, the mistery and confusion was, finally, solved. uff!

Correct way to unify separate js files with several jquery (document).ready() events

I have a very large project that has several external javascript files that I would like to unify in a single large one to optimize server load.
The problem is that many of these scripts have they own (document).ready() events that targets element that are only available on that page.
Unifying everything would put a lot of (different) (document).ready() in a single file and most of them will target elements that are not on the page, is this a problem?
What is the correct way to approach this?
EDIT: Clarification: I mean unify hundreds of javascript file included in they own tag in a single file, so I can minify it.
It sounds to me like you have a different javascript file included on each page and you want to consolidate them together.
If that is what you are trying to do then the simplest way is to just concatenate all the javascript into a single file. It is fine to have multiple ready calls in the same file. Also jQuery should not error if elements are not present on the page so long as you use jQuery methods to do things (for example $('.element').show() would be fine, but $('.element')[0].style.display = 'block'; would error if the element is not present on that page.
Putting them all together could have unexpected consequences though if you have things that you only want to apply to specific pages. One way to handle this would be to check which page you are on before attaching specific events. You can do this by checking for specific elements on the page like
// check if element is present and visible
if ($('.element').is(':visible')) {
// now we are on this specific page so let's do everything
// specific to this page here
}
or
// checks for presence of element
if ($('.element').length) {
}
Or you could use an id or other means to differentiate.
You could now make one $(document).ready(init); call at the bottom of your javascript and the init function could decide what needs to be initialized for that page.
Hope this helps!
I'm not quite clear on the question (where some of the elements are not on the page) but jQuery is specifically designed to have multiple $(function () {}) (short cut for document ready) calls in a page and have them run at the correct time.
I tend to add a check in to see if the elements I want jQuery to interact with actually exist before I start using them.
Having said that, a lot of standard jQuery stuff will just silently fail if the elements it's operating on aren't there, which is usually the desired behaviour. There are a few plugins though that output warnings to the console if they fail. On modern browsers this is not a problem, but on IE without the debug bar installed, it results in a full error, which is obviously not desired at all.
You don't need to have multiple (document).ready() blocks, you should be able to keep all of your code inside a single (document).ready() block. The code will target only the items that correspond to the selector, so you should be fine.
On a side note, you need to make sure you won't have different objects from different pages which have the same id, class or other attributes - if a single JS file corresponds to all of these pages and there are multiple elements on different pages that have the attribute that your JS selector matches with, you'll have un-desired (if the project is too complex, hard-to-identify) side-effects.

Completely remove Javascript

I have a website that has a fixed menu, header, etc. and loads the main content area via AJAX based on the menu clicks.
These "pages" rely on a lot of Javascript and CSS which are individual for each page. Since a user can potentially visit many pages, I want to unload the page-specific JS and CSS. The CSS was straight-forward, but removing the <script> tags does not remove the loaded Javascript (I can still call functions defined in it).
How can I really "remove" the JS? I don't want the memory overhead, or to have to worry about name clashes between pages.
You can load your functions into a page specific object. This will require you to make all your page specific calls though that object. When you want to unload the page, make that object point to something else (say null). Now you don't have references to the object, and it will be cleaned up by the runtime. (Assume nobody else points to it. This is trivial to enforce.)
My understanding (from this post on Perfection Kills) is that you can only completely remove javascript function declarations if they were created using eval(). If that is the case, you can remove the function by calling
delete funcName;
If the function was not created using eval(), the best you can do is redefine it. There are numerous examples of that. Here's one: javascript function redefinition

Best way to execute Javascript on an anchor

Generally, there are 3 ways (that I am aware of) to execute javascript from an <a/> tag:
1) Use onclick():
hello
2) Directly link:
hello
3) Or attach externally:
// In an onload event or similar
document.getElementById('hello').onclick = window.alert('Hello');
return false;
<a id="hello" href="#">hello</a>
I am actually loading the link via AJAX, so #3 is basically out. So, is it better to do #1 or #2 or something completely different? Also, why? What are the pitfalls that I should be aware of?
Also of note, the anchor really doesn't link anywhere, hence the href="#", I am using a so the styles conform as this is still an object to be clicked and a button is inappropriate in the context.
Thanks
If you are loading the content via ajax and need to hook up event handlers, then you have these choices:
Put a javascript handler in your HTML with your option 1) or 2). In my mind option 1) is a cleaner way of specifying it, but I don't think there's a mountain of difference between 1) or 2) - they both do essentially the same thing. I'm not a fan of this option in general because I think there's value in keeping the markup and the code separate.
After loading the content with ajax, call some local code that will find and hook up all the links. This would be the same kind of code you would have in your page and execute on DOMReady if the HTML had been static HTML in your page. I would use addEventListener (falling back to attachEvent) to hook up this way as it more cleanly allows multiple listeners for a single object.
Call some code after you load the content with ajax that finds all the links and hooks up the clicks to some generic click handler that can then examine meta data in the link and figure out what should be done on that click based on the meta data. For example, this meta data could be attributes on the clicked link.
When you load the content, also load code that can find each link individually and hook up an appropriate event handler for each link much the way one would do it if the content was just being loaded in a regular page. This would meet the desire of separating HTML from JS as the JS would find each appropriate link and hook up an event handler for it with addEventListener or attachEvent.
Much like jQuery .live() works, hook up a generic event handler for unhandled clicks on links at the document level and dispatch each click based on some meta data in the link.
Run some code that uses an actual framework like jQuery's .live() capability rather than building your own capability.
Which I would use would depend a little on the circumstances.
First of all, of your three options for attaching an event handler, I'd use a new option #4. I'd use addEventListener (falling back to attachEvent for old versions of IE) rather than assigning to onclick because this more cleanly allows for multiple listeners on an item. If it were me, I'd be using a framework (jQuery or YUI) that makes the cross browser compatibility invisible. This allows complete separation of HTML and JS (no JS inline with the HTML) which I think is desirable in any project involving more than one person and just seems cleaner to me..
Then, it's just a question for me for which of the options above I'd use to run the code that hooks up these event listeners.
If there were a lot of different snippets of HTML that I was dynamically loading and it would be cleaner if they were all "standalone" and separately maintainable, then I would want to load both HTML and relevant code at the same time so have the newly loaded code handle hooking up to it's appropriate links.
If a generic standalone system wasn't really required because there were only a few snippets to be loaded and the code to handle them could be pre-included in the page, then I'd probably just make a function call after the HTML snippet was loaded via ajax to have the javascript hook up to the links in the snippet that had just been loaded. This would maintain the complete separation between HTML and JS, but be pretty easy to implement. You could put some sort of key object in each snippet that would identify which piece of JS to call or could be used as a parameter to pass to the JS or the JS could just examine the snippet to see which objects were available and hook up to whichever ones were present.
Number 3 is not "out" if you want to load via AJAX.
var link = document.createElement("a");
//Add attributes (href, text, etc...)
link.onclick = function () { //This has to be a function, not a string
//Handle the click
return false; //to prevent following the link
};
parent.appendChild(link); //Add it to the DOM
Modern browsers support a Content Security Policy or CSP. This is the highest level of web security and strongly recommended if you can apply it because it completely blocks all XSS attacks.
The way that CSP does this is disabling all the vectors where a user could inject Javascript into a page - in your question that is both options 1 and 2 (especially 1).
For this reason best practice is always option 3, as any other option will break if CSP is enabled.
I'm a firm believer of separating javascript from markup. There should be a distinct difference, IMHO, between what is for display purposes and what is for execution purposes. With that said, avoid using onclick attribute and embedding javascript:* in a href attribute.
Alternatives?
You can include javascript library files using AJAX.
You can setup javascript to look for changes in the DOM (i.e. if it's a "standard task", make the anchor use a CSS class name that can be used to bind a specific mechanism when it's later added dynamically. (jQuery does a great job at this with .delegate()))
Run your scripts POST-AJAX call. (Bring in the new content, then use javascript to [re]bind the functionality) e.g.:
function ajaxCallback(content){
// add content to dom
// search within newly added content for elements that need binding
}

How to implement an Enterprise-grade JavaScript "framework" for web designers?

I have been tasked with improving the current mess that is our JavaScript "strategy"; we're an online shopping company and my boss has given me time to do this properly. He is very keen on keepin this modular and increase the reusability of the components.
Our HTML is being rendered with JSP and we have lots of custom tags writing out, for example, information about products without the web designers needing to worry about it.
Now, we want to do similar things with JavaScript. The web designers should be given a set of custom tags, like, say,
<foo:draggable>
... some HTML here ...
</foo:draggable>
that will wrap the HTML in a <div> with a drag bar at the top and a close button.
My idea is to mark the div with a unique namespaced CSS class name, like foo_draggable, and then put all my functions in a single JS file. That JS file then sees if there are elements with the CSS class foo_draggable in the DOM and if it finds any it will attach the required event handlers.
However, I am worried about scaling problems, and wondering whether it is a good idea to have lots of selector queries running when they quite often aren't going to be used.
The first alternative would be to initiate each draggable item explicitly but that would mean putting <script> tags all over the place. The second approach would be to not put all UI function in one file but rather just download the ones I need, but that would mean lots more HTTP requests and slower page load speed.
Has anyone got experience with this?
What about having two classnames?
<div class='foo fooDragable'></div>
<div class='foo fooSortable'></div>
You add the class 'foo' to all your elements that require javascript modification.
Your javascript has to check the dom only once for foo.
var $foo = $('.foo');
Afterwards you can search within this array which should be way smaller than the complete dom.
var $dragAble = $foo.filter('.fooDragable');
Have you considered or taken a look to JSF? I know it's a major change if you aren't using JSF yet. But there are lot of ready-to-use JSF component libaries with an ajaxical sauce, for example RichFaces, IceFaces, PrimeFaces, etc. It's almost a waste of time to create components/tags for it yourself.
Alternatively you can replace all Javascripts to use the great jQuery JS framework.
Depending on how many separate components you have, the extra overhead of running the selectors might not be a big deal. You can initialize all the components just the once, when the page is loaded. Anything that's not present on the page simply won't get initialized, and will incur no further overhead. In most JavaScript frameworks, selecting by classname (or tag name) is pretty fast. It's only the complex selectors, which aren't natively supported by the browser, that are slow.
If you have a few commonly used components, and then a set of less commonly used ones, it may be worth splitting those up. Keep the commonly used components in a single JavaScript file (minified, served with compression and aggressive caching), and load that in every page, regardless of whether it's needed or not. Caching will ensure it's only downloaded once, and it'll only be one small HTTP request. For the less common components, keep them in separate files (ideally, one per component), and add a script tag on pages that use them.
I'm not entirely familiar with how JSP works, but it might be possible to do this automatically - if a tag is included in the document, add a script tag for foo_widget.js in the document header, or something like that.

Categories

Resources