1

I'm trying to realise something I thought would be easy.

When an user focus on one of my contenteditable span, I want to empty it if it contains a default text.

When he loses focus, if he didn't write anything, I want to restore the default text.

Here's my code :

content.focus(function() {
    if ($(this).html() === "Text"){
        $(this).html(""); //not working
        //$(this).empty(); //not working
    }
    console.log($(this)[0]);
});
content.blur(function() {
    if ($(this).html() === ""){
        $(this).html("Text");
    }
});

It's working well when the focus is obtained by pressing tab.

Nevertheless, when the user click on the div, it's not working. It is emptying the span, but if he didn't clicked before the first letter, or after the last letter, he can't write anything.

Here's a demo.

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
Richard
  • 992
  • 1
  • 11
  • 27
  • As the "text" solution was so weird I did more investigation. I found that using `text()` is not a reliable solution as it depends on bizarre browser quirks. New solution added below. – iCollect.it Ltd Sep 11 '14 at 13:51

2 Answers2

4

The actual solution is to increase the min-width of the spans to allow the emptied span to still receive the click event being processed as it is processing the blur event e.g.

.simpletext {
    outline: none;
    min-width: 30px;
    display: inline-block;
}

Example: http://jsfiddle.net/TrueBlueAussie/10r2gasq/13/

If you want the min-width to be calculated based on content, do this instead:

http://jsfiddle.net/TrueBlueAussie/10r2gasq/14/

var content = $(".simpletext");

content.focus(function() {
    var $this = $(this);
    if ($this.html() === "Text"){
        // Set the min size to the current size before removing the text
        $this.css('min-width', $this.innerWidth());
        $this.html("");
    }
    console.log($(this)[0]);
});
content.blur(function() {
    var $this = $(this);
    if ($this.html() === ""){
        // Set the min size back to its value in the CSS
        $this.css('min-width', '');
        $this.html("Text");
    }
});

Note: Using text() is still preferable to html() but that was not a reliable solution on its own.


Something fishy:

The other answer, using text() instead of html() is actually a bit of a red-herring...

It only works differently with text() (vs html()), if the <br/> follows immediately on from the span.

e.g. only the first three entries in this example work!:

http://jsfiddle.net/TrueBlueAussie/10r2gasq/9

Basically using text() will also fail if the <br/>s are on a different lines following the spans, or if the min-width is not specified.

I am guessing that the <br/> on the same line extends the range of the <span> element when it is emptied which allows the click to propagate to the span. html() just sets innerHTML behind the scenes so gives slightly different behaviour. The behaviour of click on elements being removed is a real grey area.

I created this JSFiddle with various options to see what was going on. With the 8px min-width of spans removed none of the options work:

http://jsfiddle.net/TrueBlueAussie/10r2gasq/15/

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • +1...Brilliant man...!! This is perfect answer . :) That was complete shock to see text working and html not. explains nothing why it should work. – Milind Anantwar Sep 11 '14 at 13:51
  • must admit the why with that
    thing is weird. Replacing the br with div also works http://jsfiddle.net/Akatsukle/10r2gasq/16/
    – Richard Sep 11 '14 at 14:00
  • btw using .text() when it's not necessary is not a good idea. It is way slower than .html() as it is trying to escape the html markup. (In fact should aswell use the native dom api) – Richard Sep 11 '14 at 14:04
  • @Richard: yes, divs have a similar effect to the `
    `s on the same line (but again it is just a browser quirk so unreliable). Making the `span`s into `div`s doesn't work because of the inline-block style. If you remove the min-width it stops working again in all these cases.
    – iCollect.it Ltd Sep 11 '14 at 14:18
  • @Richard: Based on the jQuery source, `html()` is certainly a lot faster than `text()` too. Horses for courses... stick with `html` for this code and fix the min-widths (larger width or programmatic) :) – iCollect.it Ltd Sep 11 '14 at 14:18
2

Try using .text() instead of .html() everywhere in your code

sid
  • 157
  • 1
  • 11
  • 1
    thanks, it indeed solved the problem :) http://jsfiddle.net/Akatsukle/10r2gasq/3/ – Richard Sep 11 '14 at 10:41
  • 2
    But I don't understand what is the difference – Richard Sep 11 '14 at 10:42
  • +1: But I am also puzzled why this changed the behavior. Can you elaborate of the difference it causes? – iCollect.it Ltd Sep 11 '14 at 10:44
  • @TrueBlueAussie: me too :) – Milind Anantwar Sep 11 '14 at 10:44
  • @TrueBlueAussie on my browser (chrome 36 under ubuntu) with .html() I couldn't write after clicking if it was in the middle of the "Text"; I had to reclick once. With .text() it's working right away. Dunno why the behavior changed tough. – Richard Sep 11 '14 at 10:48
  • Nope... That only explains the difference in string interpretation... We all want to know why it changed the click/focus behaviour. :) – iCollect.it Ltd Sep 11 '14 at 10:53
  • Bizzarely, if I start to change the structure of the HTML, even slightly, it stops focusing the controls. The `
    ` has to be on the same line as the span (not the next line) e.g.only the first three entries in this example work!: http://jsfiddle.net/TrueBlueAussie/10r2gasq/9/) On the other 3 lines only the left 8 pixels works (because of the min-width `span` styling)
    – iCollect.it Ltd Sep 11 '14 at 13:16
  • @Milind Anantwar: Found the actual cause (see alternate answer for details). `html()` then works too. It is actually a browser quirk that allowed `text()` to fix this problem in this very specific instance so it not a reliable fix at all. – iCollect.it Ltd Sep 11 '14 at 13:47
  • @TrueBlueAussie yours is surely the perfect solution with better explanation. Just to one precaution though - I think min-width property is not supported by older browsers. e.g. IE7. Need to do some extra hacks to make it work – sid Sep 11 '14 at 14:53
  • Well thank you for giving us such an interesting puzzle. Had me intrigued. :) – iCollect.it Ltd Sep 11 '14 at 14:55