A life in the day

3/31/2007

Overlabel with JQuery

Filed under: — Scott Sauyet @ 2:24 pm

I’ve been playing with JQuery lately, and when I found a need to use the wonderful little accessible compact form script by Mike Brittain, I thought I’d try to duplicate it with JQuery’s simpler syntax. This is my first attempt at anything close to a JQuery plugin. It works for me, as you can see on the test page.

Here’s the code I wrote (Update: There is an updated version in the comments.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
jQuery.fn.overlabel = function() {
    this.each(function(index) {
        var label = $(this); var field;
        var id = this.htmlFor || label.attr('for');
        if (id && (field = document.getElementById(id))) {
            var control = $(field);
            label.addClass("overlabel-apply");
            if (field.value !== '') {
                label.css("text-indent", "-1000px");
            }
            control.focus(function () {label.css("text-indent", "-1000px");}).blur(function () {
                if (this.value === '') {
                    label.css("text-indent", "0px");
                }
            });
            label.click(function() {
                var label = $(this); var field;
                var id = this.htmlFor || label.attr('for');
                if (id && (field = document.getElementById(id))) {
                    field.focus();
                }
            });
        }
    });
};

And it would be called like this:

1
2
3
$(document).ready(function() {
    $("label.overlabel").overlabel();
});

I’m wondering whether there are some simplifications to this that a more experienced JQuery user could explain, though. I feel as though it’s still too wordy, and that it spends too much time switching between the DOM elements and the JQuery ones.

In any case, if you are interested in this (public domain) plugin, you can grab a zip here, or just go straight to the Javascript source.

111 Responses to “Overlabel with JQuery”

  1. Abba Says:

    Nice work. Just so you know the comment box on your site breaks the faux columns in ff 1.5 at least.

  2. Scott Sauyet Says:

    Oops. Just upgraded to Wordpress 2 and didn’t even notice that the stylesheet is no longer working. Ugggh.

    Thanks. Gotta find a few minutes…

  3. Jon Lesser Says:

    This is just what I was looking for. Thanks!

  4. Scott Sauyet Says:

    Glad you could use it. If you grab the code from the demo page rather than what’s displayed in the post you will get something that plays better with non-JQuery libraries. (”$” is not used in the global scope.)

  5. Dave Methvin Says:

    Hey Scott, here’s a thought on another way to write it. I can’t say it would be faster, but it gets you thinking about how jQuery chaining can be your friend when it comes to brevity. (Wordpress may mangle this…)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    (function($){
    $.fn.overlabel = function() {
        this.each(function(){
            var label = $(this);
    	$("#"+(this.htmlFor || label.attr('for') || "ID-NOT-FOUND"))
    		.focus(function(){ label.css("text-indent", "-1000px"); })
    		.blur(function(){ this.value || label.css("text-indent", "0px"); })
    		.trigger("focus").trigger("blur")
    		.length && 
    			label.addClass("overlabel-apply");
        });
    }
    })(jQuery);
  6. Scott Sauyet Says:

    Yes, that’s exactly the sort of clean-up I expected more experienced JQuery users could supply. I haven’t tested it yet, but it looks very succinct and will add at least one technique to my personal Javascript repertoire.

    I have one question, though. Why this bit:

    9
    10
    
    		.length && 
    			label.addClass("overlabel-apply");

    instead of just calling addClass() directly. Is there some performance hit?

    Thanks,

    — Scott

  7. Dave Methvin Says:

    I assumed you only wanted the overlabel-apply class on labels that had
    matching form elements, so I had the selector default to #ID-NOT-FOUND if
    the FOR attribute wasn’t present or the ID mentioned in it didn’t exist. The
    selector won’t select anything for that case, the .length will be 0 and the
    chained methods (focus, blur, triggger) won’t apply to any elements. By
    making the addClass dependent on the length being non-zero (it will either
    be 0 or 1 since we’re selecting an ID) the class is only added if there was
    an element matching the ID in the FOR attribute.

    One other thing I should have mentioned is that the trigger of focus/blur on
    each element might interact with fancy form handling such as validators, so
    you’d probably want to do overlabel early in your .ready() handler before
    initializing those kind of functions.

    Thanks for translating this idea to jQuery by the way, I found it in a
    search because I needed this functionality.

  8. Scott Sauyet Says:

    Oh of course, I see. It’s exactly the same technique that I hadn’t used
    before being applied again, but I missed it this time. The technique
    I’ve never used is simply to replace a simple “if” clause with an “||”,
    e.g. replacing this:

    if (this.value === ”) {
    label.css(”text-indent”, “0px”);
    }

    with

    this.value || label.css(”text-indent”, “0px”);

    One other thing I should have mentioned is that the trigger of focus/blur on each element might interact with fancy form handling such as validators, so you’d probably want to do overlabel early in your .ready() handler before initializing those kind of functions.

    I haven’t used it in that environment yet, but will probably do so this
    month, so thanks for the heads-up.

    Thanks for translating this idea to jQuery by the way, I found it in a search because I needed this functionality.

    The translation was pretty easy. But when I went searching, I couldn’t
    find anything. When I posted this entry, several people pointed me to
    other implementations of similar ideas. Google really is only so much
    help…

    Thanks again.

  9. Dave Methvin Says:

    I love Javascript’s || and && operators. First of all, they are
    short-circuit so that they stop as soon as they get a non-false answer, and
    they return the actual value rather than a simple true/false the way C++
    does for example.

    For the purposes of determining truth, a false value is (undefined), (NaN),
    boolean false, numeric 0, or the empty string. No conversion is done on the
    value before checking, so “false” or “0″ do not evaluate to false because
    they are non-empty strings.

    That rewrite above takes advantage of both of those things. At the point
    where it’s run, we know it’s working with a form element such as a text box.
    That means this.value will always be a string, so it will only evaluate to
    false if the string is empty. That means it has to evaluate the label.css()
    to see if the entire statement is true or false, which is just what we want
    for the case where the string is empty.

  10. Scott Sauyet Says:

    Fans of functional languages might run screaming at this use of side effects in a conjunction, but it makes a great deal of sense for shortening up code.

    I use the short-circuited nature of || and && all the time, but I’m coming from a Java background, and often forget the broader nature of true/false in JS. It’s a very nice technique.

  11. Zach Leatherman Says:

    Great plugin!

    You might want to add a textarea to your examples just to comfort the end user that it does indeed work with textareas as well.

    I made a small modification to this script to make it work with JSF-compatible id’s, a la formId:formFieldId, which is supported using the escaping features built into jQuery 1.1.3.

    Use
    var id = this.htmlFor || label.attr(’for’) || “ID-NOT-FOUND”;
    $(”#”+id.replace(/\:/,’\\:’))

    instead of

    $(”#”+(this.htmlFor || label.attr(’for’) || “ID-NOT-FOUND”))

    Hope that helps someone.

  12. ZAP Says:

    Very nice script! Simple, useful, and efficient. Thanks for sharing!

    Question: Is there an easy way to remove the overlabels of specific form fields? I have a form with billing and shipping address sections and a “Ship to Billing” checkbox that calls a JavaScript function that copies the billing info to the shipping fields and disables those fields. This doesn’t cause the overlabels to register that there is now content in each of those fields, however, so the label text stays there and makes the form data very hard to read.

  13. Scott Sauyet Says:

    Very nice script! Simple, useful, and efficient. Thanks for sharing!

    Thanks. I haven’t thought much about this since I wrote it, and the variation proposed by another poster might be a better bet.

    Question: Is there an easy way to remove the overlabels of specific form fields?

    This wasn’t built to be removed, but if your Javascript function can be easily altered then you can simply call focus() then blur() on the form field. In the demo, for instance, you might do

    1
    
           $("#username-field").val("Fred").focus().blur();

    That should work. If you can’t change the JS function, let me know and we’ll see something can be added…

  14. ZAP Says:

    The original version you created is working fine for me, so I’m happy with that. And your suggestion to focus and blur each field worked like a charm. I was even able to chain disabling of each form field after changing the value and removing the overlabel like so: $(”#s1_Name”).val(frm.Name.value).focus().blur().attr(”disabled”,”disabled”);

  15. Scott Sauyet Says:

    Great! I’m glad this worked for you.

    Please let me know if you run into any problems with it.

  16. Scott Sauyet Says:

    Thanks. I can’t really claim much credit, just the conversion of someone else’s technique to jQuery. But I’m glad you like it.

  17. Aristotle Pagaltzis Says:

    Thanks for providing a model to work from. Here’s my version:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    ( function($) {
        $.fn.overlabel = function() {
            this.filter('label[for]').each( function() {
                var label = $( this );
                var id = label.attr( 'for' );
                var field = document.getElementById( id );
     
                if(!field) return;
     
                label.addClass('overlabel-apply');
     
                var hide_label = function() { label.css('text-indent', '-1000px') };
                var show_label = function() { this.value || label.css('text-indent', '0px') };
     
                $( field ).focus( hide_label ).blur( show_label ).each( show_label );
     
                return;
            } );
        };
    } )(jQuery);


    In contrast to Dave Methvin’s variant, this code works without falling back on made-up bogus ID values and is, I believe, much more readable.

    The major win was when it occurred to me that I could remove the duplication between conditionally showing the label right now and conditionally showing the label in the blur handler by using each, because each invokes its function with field assigned to this, thus making the same code reusable for both cases. (Assigning the other closure to hide_label is not necessary, but makes the whole thing read more nicely and look more symmetric.)

    Another minor improvement is the use of filter to avoid manual checks for whether there is a for attribute on the label.

    This is tested and works for me.

    My clean-ups don’t have much to do with jQuery-specific experience, btw – I don’t even have a whole lot of it. I just obsessed over each and every line of code until the last trace of loathsome complexity was gone.

  18. Scott Sauyet Says:

    Perfect!

    This was written because I needed it for a project and didn’t want the overhead of the original technique when I was using JQuery to otherwise simplify my Javascript. It was a naive port of the original, and I was never happy with the code, but I haven’t gone back to clean it up. Although I like Dave Methvin’s shortening of the code, and I learned something from it, I haven’t adopted it in my own use, because it still came across as mysterious.

    Yours is very clean, and I’m very impressed. I think I’ll adopt it for my own use. Is it okay if I post it as the official plug-in version?

    Thanks for sharing it.

  19. Aristotle Pagaltzis Says:

    Yeah, “mysterious” is the first thing I thought about his code too… I just didn’t want to be that forward, heh.

    It’s fine to post mine as the official version – I’d just ask to be credited, since this is essentially a rewrite. But I wouldn’t have gotten to the same place without working off your version, so I’m not going to claim it’s all mine. I dunno – choose a way to handle this that you feel is fair.

    Btw, here’s a jQuery experience issue: turns out that this:

    1
    2
    3
    4
    5
    
    ( function($) {
        $.fn.overlabel = function() {
            // ...
        };
    } )(jQuery);

    … is better written as this:

    1
    2
    3
    4
    5
    
    jQuery.fn.extend( {
        overlabel: function() {
            // ...
        }
    } );
  20. Scott Sauyet Says:

    It’s fine to post mine as the official version – I’d just ask to be credited, since this is essentially a rewrite.

    I certainly wouldn’t do it without giving full credit. The only question to me was whether this excellent rewrite should simply replace my plug-in or whether you would prefer to post an entirely separate one. Either is fine, but I think it’s worth having this version listed on the plug-in page.

    So what is the advantage of the “.extend()” version above?

  21. Aristotle Pagaltzis Says:

    I would post the rewrite separately, to preserve the context for the comments on this post, and then point the plug-in page to the new post, so people looking for such a plug-in aren’t given a choice of two versions when one of them is universally preferable.

    As forextend, mostly it’s just the idiomatic way for jQuery plugins. It does have a small objective advantage in that it’s more declarative. But it forgot that I have $( this ) and $( field ) in the function, and these would have to be written as jQuery( ... ) instead, so I wouldn’t change the style after all.

  22. Scott Sauyet Says:

    I guess the question is whether you would like to post a new plug-in to replace http://jquery.com/plugins/project/overlabel or would prefer that I simply point that one to the code you’ve written. Since I’m going to switch to this code, I don’t see any need to maintain the original version.

  23. Aristotle Pagaltzis Says:

    I could make a page on my site for the plug-in if you think that’s OK?

  24. Scott Sauyet Says:

    Of course. Let me know when it’s done, and I’ll point people there. Perhaps we can simply replace the links on the plug-in page to point there.

  25. Guy Fraser Says:

    Hi All,

    I’ve been fiddling around with the short “chained” version of this script and come up with a new version as follows:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    (function($){
    $.fn.overlabel = function() {
        this.each(function(){
            var label = $(this);
            var id = this.htmlFor || label.attr('for') || "NO-ID";
            $("#"+id.replace(/\:/,'\\:'))
                    .parent().addClass("overlabel-wrapper").end()
    		.focus(function(){ label.css("text-indent", "-1000px"); })
    		.blur(function(){ this.value || label.css("text-indent", "0px"); })
    		.trigger("focus").trigger("blur")
    		.length && 
    			label.addClass("overlabel-apply");
        });
    }
    })(jQuery);

    So, what have I done?

    a) I’ve included the compatibility hack for JSF forms as per Zach’s suggesion - it’s still fast and just extends compatibility with markup used in existing forms.

    b) I’ve replaced “ID-NOT-FOUND” with “NO-ID” - still obvious what it does, but shorter so saves electrons.

    c) Automatically add a class to the element that contains the label/input (which no longer has to be a div) so that the raw HTML doesn’t need to have the class defined.

    This just makes working with some existing forms a lot easier, especially those that place each field in an li or span, etc.

    The CSS becomes:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    .overlabel-apply {
      color:#999;
      cursor:text;
      left:5px;
      position:absolute;
      top:1px; /* I use bold labels hence only 1px, normal weight labels would use 3px */
      z-index:1;
    }
    .overlabel-wrapper {
     position: relative;
    }

    Note: I’ve not floated the wrappers as per the original example just to keep the CSS small. To get the single line form as per the original example, just change the wrapper css to the following:

    1
    2
    3
    4
    5
    
    .overlabel-wrapper {
      float:left;
      margin-right:3px;
      position:relative;
    }

    c) You will no doubt have noticed that I’ve put the styles and their properties in alphabetical order - I find this improves readability when you are in a rush to do something at 5am (as it is here in the UK) and are wading through a HUGE CSS file heh.

    d) With this approach we can remove the “overlabel” class from the labels and the id’s from the divs (which also no longer need to be divs).

    I know the code isn’t as readable to anyone who doesn’t do a lot of chaining, but it’s fast and compact. For projects that need lots of JS, having each component part as compact as possible is really important IMHO.

    You could still include the “overlabel” class on labels if you wanted to use a selector like:

    1
    2
    3
    
    jQuery(function(){
     jQuery("label.overlabel").overlabel();
    });

    But if you’re working with existing form markup you would probably use something more like:

    1
    2
    3
    
    jQuery(function(){
     jQuery("form.myForm label").overlabel();
    });

    So, where next…

    We’ll obviously I’d like to see the chained version become the official version. It’s more compact and more flexible at the same time.

    It might be interesting to see if the formatting of the labels could be based on the formatting of the input/textarea - eg. the font properties, line height and padding could all be taken from the input/textarea and the only thing that the developer would need to change is the colour of the label.

    Comments?

  26. Aristotle Pagaltzis Says:

    How is the chained version “more” flexible? There is nothing about those improvements that makes them hard to incorporate into the clean version:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    ( function( $ ) {
        $.fn.overlabel = function() {
            this.filter( 'label[for]' ).each( function() {
                var label = $( this );
                var id = label.attr( 'for' );
                var field = document.getElementById( id ) ||
                    document.getElementById( id.replace( /\:/, '\\:' ) ); // hack for JSF forms
     
                if(!field) return;
     
                label.addClass( 'overlabel-apply' );
     
                var hide_label = function() { label.css( 'text-indent', '-1000px' ) };
                var show_label = function() { this.value || label.css( 'text-indent', '0px' ) };
     
                $( field ).
                    parent().addClass( 'overlabel-wrapper' ).end().
                    focus( hide_label ).blur( show_label ).each( show_label );
     
                return;
            } );
        };
    } )( jQuery );

    I improved upon the JSF hack here because there’s certainly perfectly good markup that’s not generated by JSF but has colons in IDs; so if the code is to actually “extend compatibility with markup used in existing forms,” it needs to deal with both cases. I also commented the hack so someone who looks at it two years from now will know what the heck that cruft is for.

  27. Scott Sauyet Says:

    I don’t think the “JSF hack” is necessary here. Isn’t that just a workaround for jQuery’s other use of the (perfectly legal) colon character in an id? That is, jQuery would recognize $("#my-id:first-child") as pointing to the element with id “my-id” but only if it is the first child element of its parent. But if you have an element with the id “my-id:first-child”, which is legal XHTML, jQuery’s call above wouldn’t find it. Instead you need to escape the colon with a backslash, and in order to do that in a JS string you need a second backslash escaping the first one. A bit ugly, but at least it leaves us with the flexibility to have CSS-like selectors. But won’t document.getElementById("my-id:first-child") fetch the item with exactly that id anyway without any sort of hack?

    BTW, Aristotle, have you set up your plug-in somewhere yet? I’d really like to point mine to it.

    — Scott

  28. Aristotle Pagaltzis Says:

    Oh! I completely misread what the hack was for. I read it as saying that JSF outputs IDs where the colons are backslashed in the markup – please don’t ask what made me think that, because I have no idea. So yeah, the hack is unnecessary in my version.

    I don’t have a page yet! Sorry. I think I’ll go make one right now, or else it will slip below the fold of my backlog again…

  29. Guy Fraser Says:

    OK, I like the revised readable version more than my updated chained version. It’s far easier to read and understand. Great work Aristotle!

    P.S. Did you spot my “cursor: text” style setting for the label - it ensures that when you mouse over the search box the cursor will be the same as when the box is focussed (just “feels” nicer IMHO).

  30. Guy Fraser Says:

    I forgot to mention - would it be possible to return the jQuery object - this would allow chaining, eg. I might want to do something like this:

    jQuery(”#form3 label”).overlabel().css(”color”,”green”);

    Ideally the jQuery object returned by overlabel() would only include the labels that have actually been processed.

  31. Scott Sauyet Says:

    Ideally the jQuery object returned by overlabel() would only include the labels that have actually been processed.

    Are there other plug-ins that work like this? This would violate my basic assumption that the jQuery object returned is the same one I’ve chosen with my selectors. But I agree that it would be best to return the jQuery object.

  32. Guy Fraser Says:

    Well, there are two options…

    1. Make it clear in docs that returned jQuery obj is filtered to just those labels that are processed. The return would be:

        return this.filter("label.overlabel-apply");

    (or maybe just build a new list within the .each()…?)

    To apply stuff to just the processed labels, the developer could:

        $(whatever).overlabel().whatever();

    The developer could call .end().end() to undo the two filters (label[for] and label.overlabel-apply), eg:

        $(whatever).overlabel().end().end().whatever();

    2. Return the original list prior to any filteres, eg:

        return this.end(); // undo the label[for] filter

    With this option the developer could

        $(whatever).overlabel().filter("label.overlabel-apply").whatever();

    —-

    I’m not sure which would be best. Option 2 would lead to more transparent code, albeit a little wasteful due to the extra filter.

    Note: My example of setting colour to green was terrible because you’d just do that using the CSS for .overlabel-apply heh.

  33. Aristotle Pagaltzis Says:

    Scott: I’m actually reluctant to make a page yet because you have comments on your site and I don’t (yet)! And the discussion here keeps turning up interesting bits. Returning the jQuery object is actually something I thought I should add. But I hadn’t thought about returning a list of only the processed elements, and that is a handy option! As for whether to return the selection filtered or unfiltered – how about letting the user choose?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    ( function( $ ) {
        $.fn.overlabel = function( do_return_filtered ) {
            var selection = this.filter( 'label[for]' ).map( function() {
                var label = $( this );
                var id = label.attr( 'for' );
                var field = document.getElementById( id );
     
                if(!field) return;
     
                label.addClass( 'overlabel-apply' );
     
                var hide_label = function() { label.css( 'text-indent', '-10000px' ) };
                var show_label = function() { this.value || label.css( 'text-indent', '0px' ) };
     
                $( field ).
                    parent().addClass( 'overlabel-wrapper' ).end().
                    focus( hide_label ).blur( show_label ).each( show_label );
     
                return this;
            } );
     
            return do_return_filtered ? selection : selection.end();
        };
    } )( jQuery );

    This way you can pass an optional true argument to the function. If you do, the object you get will contain just the processed nodes; if you call the method without parameters or with a false parameter, the selection remains the same. (All it took to achieve this is changing each() to map() and changing return to return this at the end of the anonymous function.)

    Actually, now that I think about it, there’s some more control we could give the user:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    
    ( function( $ ) {
        $.fn.overlabel = function( arg ) {
            var opt = {
                label_class:   'overlabel-apply',
                wrapper_class: 'overlabel-wrapper',
                hide_css:      { 'text-indent': '-10000px' },
                show_css:      { 'text-indent': '0px' },
                filter:        false
            };
     
            if( 'Object' == typeof arg )
                for( key in arg ) opt[ key ] = arg[ key ];
            else
                opt.filter = !!arg;
     
            var selection = this.filter( 'label[for]' ).map( function() {
                var label = $( this );
                var id = label.attr( 'for' );
                var field = document.getElementById( id );
     
                if(!field) return;
     
                label.addClass( opt.label_class );
     
                var hide_label = function() { label.css( opt.hide_css ) };
                var show_label = function() { this.value || label.css( opt.show_css ) };
     
                $( field ).
                    parent().addClass( opt.wrapper_class ).end().
                    focus( hide_label ).blur( show_label ).each( show_label );
     
                return this;
            } );
     
            return opt.filter ? selection : selection.end();
        };
    } )( jQuery );

    Now the user can either pass true to get back the filtered selection, or false (or just nothing) to get back the original selection – or pass a parameter object to customise any part of the CSS to taste.

  34. Scott Sauyet Says:

    I’d been thinking along the same lines as the last one, adding configuration parameters.

    I don’t personally find any need for the filtered return, but I like the added flexibility for those who do. (My own comment in response to Guy’s last one disappeared — my own damn blog!) I don’t see any good reason to overload the args variable, though. The filter parameter could simply be an attribute of args. That would chop off a few lines and make it easier to document.

  35. Aristotle Pagaltzis Says:

    Hmm, you are right, there isn’t much reason to overload it. The config object should just be another optional parameter, and I shouldn’t have put the filtering flag in there at all. Then I can also unbork the variable names:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    $.fn.overlabel = function( do_return_filtered, override ) {
        var config = {
            label_class:   'overlabel-apply',
            wrapper_class: 'overlabel-wrapper',
            hide_css:      { 'text-indent': '-10000px' },
            show_css:      { 'text-indent': '0px' },
            filter:        false
        };
     
        if( override ) for( key in override ) config[ key ] = override[ key ];

    The rest of the references to opt must be changed, of course, as must the name of the flag variable on the return line. Much nicer.

    It does mean that if you want to pass a config hash, you must say whether you want your selection filtered or not, but if you pass a config hash you’re already taking a verbosity hit anyway, so the extra positional parameter is not a big burden.

  36. Benjam Says:

    You both are having great ideas with this, but one thing I would like to see is an updated demo page.

    I am having difficulties getting this little function to work on my page.

    One thing I noticed, is that one must replace all instances of opt. with config. when using the latest version (posted by Aristotle on 2007-10-05).

    Also, what is the wrapper_class for, and what would be a suitable CSS declaration that would enable this to work?

  37. Benjam Says:

    Oops, forgot to read the rest of that last comment before posting, forgive my config. to opt. statment.

    One other thing I noticed, is that the filter part of the config object is moot now, isn’t it? Due to the do_return_filtered argument?

    Anywho… let me know when I can view an updated demo page.

    Thanks.

  38. Guy Fraser Says:

    The recommended way to do default settings is shown on a jQuery tutorial:

    1
    2
    3
    4
    5
    
     jQuery.fn.foobar = function(options) {
       var settings = jQuery.extend({
         value: 5, name: "pete", bar: 655
       }, options);
     };

    http://docs.jquery.com/Tutorials:Getting_Started_with_jQuery

    Whilst Aristotle’s settings will do much the same thing (and probably be faster) it might be worth sticking to the documented method as more people will be familiar with it….?

  39. Scott Sauyet Says:

    I will try to create an updated version over the weekend. I’ve been letting this play out as Aristotle said he’d be creating a new plugin page for it. At this point, though, even with Aristotle’s rewrite, the whole thing has become a group effort. I will combine all the ideas listed above and create a simple demo.

  40. Damir Secki Says:

    Hello folks!
    great team work!

    I’ve done something on my own but it’s not even remotely similar and useful as what you’ve done boys. I have only one problem with this whole approach…

    If I use this On my log-in form firefox (or the browser) wont be able to remember the values of the fields for me, to log in next time… so next time instead of having already filled fields with my user name and password the fields will be filled with overlabel values… and this is not a very big deal… but its a setback to write the login data all over again…

    are there any workarounds this?

  41. Damir Secki Says:

    ups, never mind… it seems I’ve spoken too soon :)

  42. Scott Sauyet Says:

    Although I never really considered this, it seems to just work, at least the original version. I’ll keep it in mind when I try to put all this together this weekend. But as far as I can tell, that shouldn’t be an issue at all. Firefox puts a value in this field before any of our manipulation. And that manipulation always checks for a value. I’ll have to check if it works in other browsers too.

    Have you tested somewhere and found this not working?

  43. Scott Sauyet Says:

    And I’ve responded too soon! :-)

    Glad it’s working.

  44. Guy Fraser Says:

    Don’t forget the cursor:text in the css for processed labels :)

  45. Scott Sauyet Says:

    I’m afraid I didn’t find the time this weekend to do an update. I will do it as soon as I can find a spare hour or two.

  46. Guy Fraser Says:

    Just been reading this: http://www.learningjquery.com/2007/10/a-plugin-development-pattern

    So the plugin could become something like:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    
    ( function( $ ) {
     
        // plugin definition
        $.fn.overlabel = function( options ) {
     
            // calculate main options (without metadata)
            var main_opts = $.extend( {}, $.fn.overlabel.defaults, options );
     
            var selection = this.filter( 'label[for]' ).map( function() {
     
                var label = $( this );
                var id = label.attr( 'for' );
                var field = document.getElementById( id );
     
                if ( !field ) return;
     
                // if metadata is present, extend main_opts
                var opts = $.meta ? $.extend( {}, main_opts, label.data() ) : main_opts;
     
                label.addClass( opts.label_class );
     
                var hide_label = function() { label.css( opts.hide_css ) };
                var show_label = function() { this.value || label.css( opts.show_css ) };
     
                $( field ).
                     parent().addClass( opts.wrapper_class ).end().
                     focus( hide_label ).blur( show_label ).each( show_label );
     
                return this;
     
            } );
     
            return opts.filter ? selection : selection.end();
        };
     
        // publicly accessible defaults
        $.fn.overlabel.defaults = {
     
            label_class:   'overlabel-apply',
            wrapper_class: 'overlabel-wrapper',
            hide_css:      { 'text-indent': '-10000px' },
            show_css:      { 'text-indent': '0px', 'cursor': 'text' },
            filter:        false
     
        };
     
    } )( jQuery );

    Things I’ve done:

    1. Non-destructively determine settings (main_opts) when the overlabel function is called, before entering the map() block.

    2. If metadata plugin is available, non-destructively extend main_opts to include element-level settings

    3. Made default settings publicly accessible - you can now easily override the settings via $.fn.overlabel.defaults

    4. Added cursor:text to the show_css to ensure good usability :p

    NB: I’ve not tested the updates heh.

  47. Scott Sauyet Says:

    I’m glad I haven’t found the time to put all this together! :-) This is looking just about perfect.

    By the way, I know that there is no obvious way to format code. This is a mostly unused blog, but when I get some time, I’ll see if I can document how to do it. For now, you might try what I do, which is to add:

    1
    2
    3
    
    <blockquote style="font-size: 125%;"><pre lang="javascript" line="1">
    // code here
    < /pre>< /blockquote>
  48. Guy Fraser Says:

    Found a slight bug and made another tweak based on feedback elsewhere…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    
    ( function( $ ) {
     
        // plugin definition
        $.fn.overlabel = function( options ) {
     
            // build main options before element iteration
            var opts = $.extend( {}, $.fn.overlabel.defaults, options );
     
            var selection = this.filter( 'label[for]' ).map( function() {
     
                var label = $( this );
                var id = label.attr( 'for' );
                var field = document.getElementById( id );
     
                if ( !field ) return;
     
                // build element specific options
                var o = $.meta ? $.extend( {}, opts, label.data() ) : opts;
     
                label.addClass( o.label_class );
     
                var hide_label = function() { label.css( o.hide_css ) };
                var show_label = function() { this.value || label.css( o.show_css ) };
     
                $( field ).
                     parent().addClass( o.wrapper_class ).end().
                     focus( hide_label ).blur( show_label ).each( show_label );
     
                return this;
     
            } );
     
            return opts.filter ? selection : selection.end();
        };
     
        // publicly accessible defaults
        $.fn.overlabel.defaults = {
     
            label_class:   'overlabel-apply',
            wrapper_class: 'overlabel-wrapper',
            hide_css:      { 'text-indent': '-10000px' },
            show_css:      { 'text-indent': '0px', 'cursor': 'text' },
            filter:        false
     
        };
     
    } )( jQuery );

    1. Renamed “main_opts” to just “opts” - this also fixed a bug on the “return …” line.

    2. Renamed the element-specific opts to “o” - shorter and also seems more visually distinct from the main “opts”

  49. Guy Fraser Says:

    One final mod (I hope!) for readability:

    25
    26
    27
    
                $( field ).
                     parent().addClass( o.wrapper_class ).end().
                     focus( hide_label ).blur( show_label ).each( show_label );

    Becomes:

    25
    26
    27
    
                $( field )
                     .parent().addClass( o.wrapper_class ).end()
                     .focus( hide_label ).blur( show_label ).each( show_label );

    I’ve moved the .’s to make it clearer that parent() and focus() aren’t global functions for anyone doing a cursory glance through the code. Having the “.” at the start of those two lines (rather than the end of the preceding line) just makes it more obvious that it’s a continuation of the chain IMHO.

  50. Guy Fraser Says:

    Hi Scott,

    Did you ever get chance to push this in to SVN and release?

  51. Scott Sauyet Says:

    Hi Guy,

    I don’t have a public SVN server to push this to. I’ve been a bit out of touch with JQuery for the last two months, so I don’t know what’s going on. Is there an SVN server I can use for posting non-official plug-ins?

    But no, I haven’t had any time at all in the last few weeks.

    — Scott

  52. Guy Fraser Says:

    I believe the jQuery site has one (plus associated bug tracker, etc.), but no idea how to use it :s

  53. Mark Montague Says:

    I’ve been trying out the final version of this script, and it works pretty well but seems to have the following bug: if the text field begins with some text in it, the overlabel is shown on top of the text. I can’t quite see how to fix that; anyone else?

  54. Scott Sauyet Says:

    Yes, this looks like a regression. This should fix it:

    25
    26
    27
    
                $( field )
                     .parent().addClass( o.wrapper_class ).end()
                     .focus( hide_label ).blur( show_label ).each( hide_label ).each( show_label      );
  55. Mark Montague Says:

    That did fix it - great! I’m having one further problem with this script, and it seems like a harder one: in Safari 2 (but not Safari 3), if you click on the text of the overlabel, nothing happens. If you click in the blank space next to it, the overlabel disappears and the text input area receives focus, as it should. So it seems that somehow the overlabel is catching the click event instead of the text field. Any ideas?

  56. Scott Sauyet Says:

    Unfortunately, with no Mac to test on, I’m not sure how to chase this down. I have a Win32 version of Safari, but it’s version 3, and everything seems to work there. I wonder if we could create a test case using only CSS and ask the good folks on the CSS-Discuss list…

  57. Guy Fraser Says:

    I’m guessing that the event is not bubbling or for some reason the label is swallowing the click.

  58. Aristotle Pagaltzis Says:

    Aha, that’s why the original function added an onclick handler to the label element. I removed that in my refactor because keeping it made things messier and I didn’t understand what purpose it might possibly serve, seeing as clicking the label should focus the form element anyway. I guess it needs to be added back in… oh well.

  59. Ellen Says:

    I’m a little confused after reading all this … have all the rewrites been incorporated into the plugin? What is the final code that I am supposed to use?

    Thank you

  60. Scott Sauyet Says:

    I’m sorry, I never seem to get back to putting together a decent demo. I think the current state of play is the following:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    
    ( function( $ ) {
     
        // plugin definition
        $.fn.overlabel = function( options ) {
     
            // build main options before element iteration
            var opts = $.extend( {}, $.fn.overlabel.defaults, options );
     
            var selection = this.filter( 'label[for]' ).map( function() {
     
                var label = $( this );
                var id = label.attr( 'for' );
                var field = document.getElementById( id );
     
                if ( !field ) return;
     
                // build element specific options
                var o = $.meta ? $.extend( {}, opts, label.data() ) : opts;
     
                label.addClass( o.label_class );
     
                var hide_label = function() { label.css( o.hide_css ) };
                var show_label = function() { this.value || label.css( o.show_css ) };
     
                $( field )
                     .parent().addClass( o.wrapper_class ).end()
                     .focus( hide_label ).blur( show_label ).each( hide_label ).each( show_label );
     
                return this;
     
            } );
     
            return opts.filter ? selection : selection.end();
        };
     
        // publicly accessible defaults
        $.fn.overlabel.defaults = {
     
            label_class:   'overlabel-apply',
            wrapper_class: 'overlabel-wrapper',
            hide_css:      { 'text-indent': '-10000px' },
            show_css:      { 'text-indent': '0px', 'cursor': 'text' },
            filter:        false
     
        };
     
    } )( jQuery );

    Please let me know if that doesn’t work for you.

  61. Mike Brittain Says:

    Well done! I’m glad you’re finding good use for it, and extending this technique further than I have.

  62. Nick Carroll Says:

    Hey Scott,

    I fixed the bug that Mark Montague (Comment #55) raised. Safari seems to fire off the form Autofill event after the JQuery ready event. So if you call the overlabel function with:

    $(document).ready(function() {
    $(”label.overlabel”).overlabel();
    });

    Then in Safari, since the Autofill hasn’t added any text to the form input field, the overlabel plugin will think the input fields are empty and display the labels over them. Then Safari triggers the Autofill event and adds the previously entered text (eg username and password) into the form fields. This gives the undesirable effect of overlapping text in the form field.

    To get around this problem you have to call the overlabel plugin with the following:

    $(window).load(function() {
    $(”label.overlabel”).overlabel();
    })

    This waits until the page is fully loaded and Safari’s Autofill event finishes before calling the overlabel plugin.

    Cheers,
    Nick.

  63. Ian Bryce Says:

    I was having trouble with the Label overlapping each other. i’ve over come this by removing in the CSS left:3px and replacing this with padding:0 0 0 3px

    This fixed the problem for both IE and FF whilst using the blueprint CSS framework.

  64. Scott Sauyet Says:

    @Nick, that makes sense. I’ll change it as soon as I get a free moment.

    @Ian, I haven’t seen that issue, but I’ll take a look. It’s certainly a clear enough solution.

  65. Wayne Elgin Says:

    Nice work.

    Have you thought about extending this so that implicit labels also work?
    http://www.w3.org/TR/html401/interact/forms.html#idx-label-1

    I also second the need for a clarifying post or just updating the jQuery plugin page with an up-to-date download link for the script. Parsing through all of the comments confuses me about which direction the current code went.

    -Wayne

  66. Ryan Says:

    To everyone: Thanks for all the hard work. I look forward to using this script.

    I’m using the version from comment #60 and having some problems getting it to work (labels appearing in the top left corner of my screen).

    Would be awesome to have a demo that shows not only the latest version of the script, but also the appropriate markup and css to use.

    Thanks!

  67. Phil Says:

    Nice work everyone :)

    One thought though - it seems as though the assumption has been made that the label will be in the same container as the textbox, so the wrapper is applied to the textbox’s parent rather than the labels parent.

    I’m a bit of a jQuery novice so I won’t get my hands dirty - just my throwing my 2 cents in!

  68. Tim Büthe Says:

    Hi,

    the zip download link (http://scott.sauyet.com/Javascript/Demo/Overlabel/Overlabel.zip) gives a 404

    regards,
    Tim

  69. Nikon Says:

    I would like to see is an updated demo page.

  70. Riad Marrakech Says:

    awesome plugin

  71. Evan Carroll Says:

    Man i wish there was a working demo of the new version.. this isn’t working for me at all.

  72. Evan Carroll Says:

    scratch that the demo is up to date just not the original post

  73. Aurélien Geron Says:

    Hi,

    I just wanted to let you know that I wrote a very similar plugin also based on the overlabel technique, but based on the prototype framework instead of jquery.

    You can download it here:
    http://github.com/ageron/labelinput/

    Cheers!

  74. Aaron Says:

    Great plugin! I’m having one issue though. When you have multiple logins saved for a site and Firefox autofills one of the logins, the overlabel continues to display over the filled-in password. As far as I know, the autofill doesn’t trigger any events on the fields. Anyone know of any good fixes?

    The workaround I’m using right now is to tie to the focus event of the username field and start a check every second for a value in the password field. If it finds one it hides the label. When the username is blurred the check stops. It works but I wish there was a better solution.

  75. Scott Sauyet Says:

    Do you have an example url? I can’t duplicate this. Perhaps at start a call to $(”selector”).focus().blur() in a timeout on startup would do…

  76. Craig Says:

    I looked and what you did and wrote a plugin that’s does the exact same thing in a slightly different way. Instead of moving the label over the input, I chose to hide the label and copy the html() into the input’s value attribute.

    Here’s my version:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    (function($) {
        $.fn.overlabel = function() {
            this.filter('label[for]').each(function() {
                var $label = $(this);
                var $field = $('input[id="' + $(this).attr('for') + '"]');
     
                if(!$field) return;
     
                var hide_label = function() { 
                	if ($field.val() == $label.html() || $field.val() == "")
                	{
                		$field.val(""); 
                		$field.removeClass('overlabel_shown');
                	}
                };
                var show_label = function() {
                	if ($field.val() == $label.html() || $field.val() == "")
                	{
                		$field.val($label.html());
                		$field.addClass('overlabel_shown') 
                	}
                };
     
                $label.hide();
     
                $field.focus(hide_label).blur(show_label).each(show_label);
     
                return;
            });
        };
    })(jQuery);
  77. GouMs Says:

    Hi Guys,

    Nice discussion about best ways to do a watermark using jQuery !
    I’m using a similar pluggin that I wrote myself, and was looking around the web to find a fix for my problem wich is the same than Aaron (post #75).

    Reproduce it as easy as this:
    - Make a login form with overlabel (email + password).
    - Log in and allow firefox to remember your email and password.
    - Log out
    - Reload the page
    - Type the begining of your email address, and select it in the list that firefox is showing.
    –> The password field is automaticaly filled and the label stay over the input value !

    I can’t find the event to use to fix that :s

    Is anyone having an idea?

    Cheers

  78. GouMs Says:

    About my last comment:

    I tried to hang arround with “DOMAttrModified” but I figured out that the value of an input field is actually not a DOM attribute. The actual is only use to set the default value, and is not change when a user or a script update the value of the field.

    So I tried with “DOMControlValueChanged” but nothing conclusive.. I don’t know if this event is really working yet in the common browsers… Does anyone know about it?

    Regards.

  79. Scott Sauyet Says:

    @Craig: This is an interesting alternative. It is slightly simpler, which is nice, but it has one minor hole that I can see: If the user wants to type the same value as is displayed in the label, she’s not going to see it as an entered value but as an overlabeled-style field. This is not a big deal, I imagine, but it could be disconcerting.

  80. Scott Sauyet Says:

    @GouMS: Yes, I see what you’re talking about too. I haven’t found a solution yet, but I’ll keep looking.

  81. GouMs Says:

    @Craig: I haven’t tried your script, but is it working with password fields? I know that it’s one of the major concern about watermark that are not using the overlabel method…

    @Scott: Thanks, let me know if you find anything. By the way it’s very nice to see that more than 2 years after posting this thread, you are still updating the script and helping people to handle it!

    Cheers

  82. Scott Sauyet Says:

    @GouMs: Well, I don’t get to follow the jQuery group regularly; I figure this fairly minor plug-in is at least one way I can give back to the community.

  83. Cheryl Says:

    This is an excellent help to me, looks very stylish and nice. I’m also having the problem with autofilled-passwords causing a label overlap. Could any of you gentlemen give me some kind of workaround here? I just want the labels to disappear when the fields are filled in. I work with PHP (and only cut-and-paste with Jquery and javascript), so some of your posts are kinda over my head. Any help would be appreciated.

  84. Scott Sauyet Says:

    @Cheryl: Is that happening only in Firefox? And only when there are several passwords stored for the field? If so, that’s the issue that several people have pointed out and it’s one for which no one has yet found a solution. We’ll keep looking, though. Sorry.

  85. sunny Says:

    Hi, Can someone give me a step by step on how to do this. As in what files i need to insert which codes in to create the overlabel. im so confused by it all. so something more simple would go better. my email is kumar017@hotmail.com if u want to email it me.

    Thanks. Sunny

  86. Vicky Says:

    Hi guys,
    I’m having a conflict problem with Overlabel and UI Datepicker. When I select the date, the label and the date are meshed together. So it clears when I first click on the input box, but when I go to select a date from the pop-up calendar, the label returns. Any idea on how to fix this? I figured it has something to do with the fact that the input is dynamic and not directly within the input box.

  87. Scott Sauyet Says:

    I haven’t seen this, but it’s not terribly surprising. Do you have a test page somewhere?

    Something like overlabel would make a good extension to the Datepicker, I think. But I don’t know that code at all to suggest how it might best be incorporated.

  88. Scott Says:

    If you’re having issues with jQuery UI Datepicker and using this technique insert “change( hide_label )” before “.focus( hide_label ).blur( show_label ).each( hide_label ).each( show_label );” and it will solve your issues.

  89. Tchat Says:

    Great plugin :)

    Thanks for working :)

  90. Alexander Says:

    hi!

    Maybe this will be helpfull for someone:

    (function ($) {

    $.fn.WaterMark = function (watermarkText, watermarkCSS) {

    return this.each(function () {

    var $M = $(”label[for]=” + $(this).name);

    if ($M.length == 0) {
    $(”")
    .attr(”for”, $(this)[0].name)
    .attr(”innerHTML”, watermarkText)
    .addClass(watermarkCSS)
    .css(”position”, “absolute”)
    .css(”width”, $(this)[0].clientWidth)
    .css(”height”, $(this)[0].clientHeight)
    .css(”padding”, “3px”)
    .insertBefore(”#” + $(this)[0].name);
    }

    var doOnFocus = function () { $(”label[for]=” + $(this)[0].name).fadeOut(”fast”); };

    var doOnBlur =
    function () {

    if (!this.value) {
    $(”label[for]=” + this.name).fadeIn(”slow”);
    }
    };

    $(this)
    .focus(doOnFocus)
    .blur(doOnBlur);
    });

    };

    })(jQuery);

    using:

    $(document).ready(function () {

    $(’#SendText’).WaterMark(”mail us if you have any suggessions”, “some”);

    });

  91. Alexander Says:

    $(””)

    after
    if ($M.length == 0) {

    must be
    $(”")

  92. Alexander Says:

    $(”<label/>”)

  93. Mike Metcalf Says:

    Wrote an alternative jQuery script that removes class dependency and adds a dim state on focus. Click my name for the link.

  94. Scott Sauyet Says:

    @Mike

    I like the dim state a lot. I never considered doing that.

    But I’m not sure what you mean by “the class dependency”. The version that’s been developed here uses CSS for styling. I wouldn’t want to remove that feature.

    I’m also curious as to why you choose to link the label and the input control by DOM ordering (using “prev”) when there is already a semantically meaningful link between them in the label’s “for” tag.

    One more thing, I just realized, too. Yours looks as though it will act very oddly if JS is off. Have you tested that?

  95. Mike Metcalf Says:

    @Scott

    Glad you like the dim state. By class dependency I just meant you don’t need to manually add the overlabel class to the labels you want to use the script on. It works, but I’m definitely a novice when it comes to jQuery. I would be interested to see how you might use your existing plugin to integrate a dim state. I’ve used your plugin many times, so thanks for your work.

    Mike

  96. HCG Diet Says:

    hxivltdpuu, Oral hcg, zlUmSxo, [url=http://australiahcgdrops.com/]Mushrooms on hcg diet[/url], runPkPF, http://australiahcgdrops.com/ Hcg diet dangers dr oz, zELzQmH.

  97. freefallstage.com Says:

    A few years ago, one of our local residents, Mac Vorce, who is also a bicycle enthusiast petitioned for the
    development of bicycle paths and trails. Celebrity impersonations, musical
    gags, and the use of props are just some of
    the things that you could do in your routine. He hosted Comedy Central’s’The Man Show’ as well as the ubiquitous
    pseudo-porn for the sexually crippled, ‘Girls Gone Wild’,
    both solely and shamelessly for financial gain.

  98. bathroom renovation designs Says:

    Wow loads of fantastic advice!

  99. www.commentgagnerdelargentsurlenet.com Says:

    Hi, its good post concerning media print, we all be familiar with
    media is a impressive source of information.

  100. Internet Traffic Formula Review Says:

    I am extremely inspired along with your writing skills and
    also with the layout for your weblog. Is that this a paid subject or did you modify
    it yourself? Anyway stay up the excellent high quality writing,
    it’s uncommon to see a nice blog like this one these days..

  101. http://www.Youtube.com/watch?v=55Hm0otvuGU Says:

    Thank you for the auspicious writeup. It in fact was once a leisure
    account it. Glance advanced to more brought agreeable
    from you! However, how can we communicate?

  102. Grow Taller 4 Idiots Review Says:

    Thank you for any other informative site. Where else may I get
    that type of information written in such a perfect way?
    I’ve a challenge that I am just now operating on,
    and I’ve been at the look out for such information.

  103. เกมส์สร้างบ้าน Says:

    I will immediately seize your rss as I can not to
    find your email subscription link or newsletter service.
    Do you have any? Please permit me recognise so that I may just
    subscribe. Thanks.

  104. mailotPl Says:

    Greetings from Ohio! I’m bored to death at work so I decided to check out your site on my iphone during lunch break. I really like the knowledge you present here and can’t wait to take a look when I get home. I’m shocked at how fast your blog loaded on my cell phone .. I’m not even using WIFI, just 3G .. Anyways, great site! [url=http://www.cwstudio.it/fr/maillotdefootpascher/]Maillot de foot pas cher 2014 2015[/url] I will immediately seize your rss as I can’t to find your e-mail subscription hyperlink or e-newsletter service. Do you have any? Kindly permit me understand in order that I could subscribe. Thanks. [url=http://www.masciabrunelli.it/fr/maillotpsg/]maillot psg 2014[/url] Saved as a favorite, I like your web site!

  105. Mattie Says:

    you are in reality a just right webmaster. The web site loading pace
    is amazing. It kind of feels that you are doing any unique trick.
    Furthermore, The contents are masterpiece. you have done a wonderful process in this matter!

  106. https://twitter.com/OneTwoTrade Says:

    Incredible! This blog looks just like my old one!
    It’s on a entirely different topic but it has pretty much the same page layout and
    design. Superb choice of colors!

  107. Columbus Says:

    It was hard to find your website in google. I found
    it on 22 position, you should build a lot of quality
    backlinks , it will help you to get more visitors.
    I know how to help you, just type in google - k2 seo tips

  108. Lorenzo Says:

    I read a lot of interesting content here.
    Probably you spend a lot of time writing, i know
    how to save you a lot of work, there is an online tool that creates readable, SEO friendly articles in minutes, just search in google - laranitas free content
    source

  109. Wilton Megeath Says:

    Hi, the whole thing is going sound here and ofcourse every one is sharing information, that’s
    in fact good, keep up writing.

  110. app Says:

    Hello, I think your blog might be having browser compatibility issues.
    When I look at your blog site in Firefox, it looks fine but when opening in Internet Explorer,
    it has some overlapping. I just wanted to give you a quick heads up!
    Other then that, very good blog!

  111. search results Says:

    Nice post. I was checking continuously this blog and I’m impressed!
    Extremely helpful info specifically the ultimate phase :) I maintain such information a lot.
    I used to be seeking this particular info for a long
    time. Thank you and good luck.

Leave a Reply

Powered by WordPress