I want to talk about the evolution of "paginator" - such a component to navigate through the pages of the news feed (or a list of selected events or anything else) and share one trick that allows you to install fewer handlers for homogeneous components or not to install a handler for new items each time. via Ajax request.
The paginator component is a set of links with page numbers that in some div immerse the result of some ajax request. At the same time, the ajax request returns not only the content, but also the links themselves for switching to other pages, so that for each download, handlers were set for each download, for this, the corresponding script tag came along with the links.
When I came to the project, it looked like this:
<!-- -->
<span class="paginator"><a href="#{%num%}">{%num%}</a></span>
<span class="prevnext"><a href="#{%num_min%}"></a><a href="#{%num_max%}"></a></span>
Now I regret that I did not keep this masterpiece exactly ... but for the first time my hair just stood on end from this. And it was not once on the main page, but in several sections it was replicated by copying and pasting.
')
The first thought how to overcome this mess was to combine handlers and get rid of class selectors. The second is to make a universal code that could have been in a separate js-file and applied on any page of the site through a one-line call. The first was solved without problems, the second was clearly not worth it, because it turned out seven lines of code, which is embarrassing to put in a separate file. But even if they were removed, the problem of re-running the script with each boot would not solve it:
<!-- -->
<div id="pages">
<span class="paginator"><a href="#{%num%}">{%num%}</a></span>
<span class="prevnext"><a href="#{%num_min%}"></a><a href="#{%num_max%}"></a></span>
</div>
In addition to the lack of copy-paste and repeated execution each time the page is loaded, this solution also has the disadvantage that it is not controlled by data, that is, the path and the target element are strictly written in the code. It is clear that here it is a page, and the data from the code are separated by several lines, but I still wanted to do it “by mind”, so that the data from the code was stored separately and there was no need to install handlers with each page load. The result is such a small classic - its copy is created when the page is loaded, just in $ (document) .ready
;function CPaginator( $, settings )
{
///////////////////////////////////////////////////////////////////////////////////////////
function onPageSelect( e )
{
var dash = this.href.indexOf('#');
var dashslash = this.href.indexOf('#/');
var path;
if ( -1 != dashslash ) path = this.href.substring(dashslash+1);
if ( -1 != dash && -1 == dashslash ) path = window.location.pathname;
if ( path && this.name != "page=" )
{
var rel = this.rel;
var target = $(rel||settings.defaultTarget).html("loading...");
$.post( path, this.name, function( msg ) { target.html( msg ); });
}
if ( e.preventDefault )
e.preventDefault();
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////
function catchPaginatorClick( ev )
{
if ( !ev ) ev = window.event;
var target = ev.srcElement || ev.target;
return ( target && target.name && -1 != target.name.indexOf('page=') ) ? onPageSelect.call( target, ev ) : true;
}
///////////////////////////////////////////////////////////////////////////////////////////
function constructor()
{
document.onclick = catchPaginatorClick;
}
///////////////////////////////////////////////////////////////////////////////////////////
constructor();
}
And the links themselves now look like this:
<a href="#" name="page={%num%}" rel="div.main_left_content">{%num%}
And after they are loaded from the newly arrived ajax file, no handlers should be installed.
In the link itself in href, you can write the path after the lattice where the post-request will be followed by data, rel (although this contradicts the original purpose of this attribute) indicates the selector of the element where the result will be written, and the arguments for the request are stored in name.
A handler for the click event is placed on the entire document, and now it does not matter how many items are on a page, how or when they were loaded - they do not need to install handlers for each person personally. The handler itself, as soon as possible, must determine whether the click on the link for which the specific work logic has been prepared, or whether the event refers to another element for which it is necessary to allow the browser to work through the default logic.
Thanks to onPageSelect.call, the event source element in this and the actual event in the first argument are passed to the function. After the source properties are parsed, the ajax-post request itself goes and it will return false from the handler and preventDefault is executed in those browsers where this method is defined. Without these lines, the browser will try to follow the link, and even if it looks like # / dir / 7 /, a characteristic click will be heard in IE that appears when opening a new page.
In general, according to TRIZ, the ideal object is such that it does not exist, but its function is fulfilled. Here something like this happened that there are no handlers hung directly on the constantly overloaded elements, but their function is performed. Here you can ask, why do the server work logic such that page transition controls return from there each time? I can only answer this by the fact that managers are driven by deadlines, bugs come decently and there is no time to refactor the server, so you have to adjust
If that, those long comments between class methods do not fall into the production environment and will be cut by the YUI compressor
PS: the first post on Habré
PPS: All sorts of wishes and suggestions on style and content are welcome, because I still have something to tell (and I want to do it in the best way)