web-dev-qa-db-fra.com

Placeholder in contenteditable - focus event issue

J'ai essayé de demander ceci auparavant, sans aucune chance d'expliquer/prouver un exemple de travail où le bogue se produit. Voici donc un autre essai:

J'essaie de reproduire un effet d'espace réservé sur une DIV modifiable. Le concept de base est simple:

<div contenteditable><em>Edit me</em></div>

<script>
$('div').focus(function() {
    $(this).empty();
});
</script>

Cela peut parfois fonctionner, mais si l'espace réservé contient du HTML, ou si un autre traitement est effectué, le signe d'insertion de texte du DIV modifiable est supprimé, et l'utilisateur doit re-cliquer sur le DIV modifiable pour pouvoir commencer à taper (même s'il est toujours au point):

Exemple: http://jsfiddle.net/hHLXr/6/

Je ne peux pas utiliser de déclencheur de focus dans le gestionnaire, car cela créera une boucle d'événements. J'ai donc besoin d'un moyen de réinitialiser le curseur d'insertion dans le DIV modifiable, ou d'une autre manière de recentrer.

60
David Hellsing

Vous devrez peut-être mettre à jour manuellement la sélection. Dans IE, l'événement focus est trop tard, donc je suggère d'utiliser à la place l'événement activate. Voici du code qui fait le travail dans tous les principaux navigateurs, y compris IE <= 8 (ce qui ne sera pas le cas avec une alternative CSS uniquement):

Démo en direct: http://jsfiddle.net/hHLXr/12/

Code:

$('div').on('activate', function() {
    $(this).empty();
    var range, sel;
    if ( (sel = document.selection) && document.body.createTextRange) {
        range = document.body.createTextRange();
        range.moveToElementText(this);
        range.select();
    }
});

$('div').focus(function() {
    if (this.hasChildNodes() && document.createRange && window.getSelection) {
        $(this).empty();
        var range = document.createRange();
        range.selectNodeContents(this);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
});
24
Tim Down

Voici une solution CSS uniquement augmentant certaines des autres réponses: -

<div contentEditable=true data-ph="My Placeholder String"></div>
<style>
    [contentEditable=true]:empty:not(:focus)::before{
        content:attr(data-ph)
    }
</style>

EDIT: Voici mon extrait sur codepen -> http://codepen.io/mrmoje/pen/lkLez

EDIT2: Soyez avisé, cette méthode ne fonctionne pas à 100% pour les applications multi-lignes en raison de <br> éléments présents dans le div après avoir effectué un select-all-cut ou select-all-delete sur toutes les lignes. Crédits: - @vsync
Le retour arrière semble fonctionner correctement (au moins sur webkit/blink)

153
moje

Je viens de publié un plugin pour cela .

Il utilise une combinaison de CSS3 et JavaScript pour afficher l'espace réservé sans ajouter au contenu du div:

HTML:

<div contenteditable='true' data-placeholder='Enter some text'></div>

CSS:

div[data-placeholder]:not(:focus):not([data-div-placeholder-content]):before {
    content: attr(data-placeholder);
    float: left;
    margin-left: 5px;
    color: gray;
}

JS:

(function ($) {
    $('div[data-placeholder]').on('keydown keypress input', function() {
        if (this.textContent) {
            this.dataset.divPlaceholderContent = 'true';
        }
        else {
            delete(this.dataset.divPlaceholderContent);
        }
    });
})(jQuery);

Et c'est tout.

29
Craig Stuntz

utilisez simplement les pseudo-classes css.

span.spanclass:empty:before {content:"placeholder";}
22
amwinter

J'ai trouvé que la meilleure façon de le faire est d'utiliser l'attribut placeholder comme d'habitude et d'ajouter quelques lignes de CSS.

[~ # ~] html [~ # ~]

<div contenteditable placeholder="I am a placeholder"></div>

[~ # ~] css [~ # ~]

[contenteditable][placeholder]:empty:before {
    content: attr(placeholder);
    color: #bababa;
}

Remarque: le CSS :empty selector ne fonctionne que s'il n'y a littéralement rien entre les balises d'ouverture et de fermeture. Cela inclut les nouvelles lignes, les tabulations, les espaces vides, etc.

Codepen

8
ramo

Tout ce dont vous avez besoin est cette petite solution

[contenteditable=true]:empty:before{
  content: attr(placeholder);
  display: block; /* For Firefox */
}

Démo: http://codepen.io/flesler/pen/AEIFc

7
wp student

Voici ma façon:

Il utilise une combinaison de jQuery et CSS3. Fonctionne exactement comme l'attribut d'espace réservé html5! .

  • Se cache immédiatement lorsque vous saisissez la première lettre
  • S'affiche à nouveau lorsque vous supprimez ce que vous y avez entré

HTML:

<div class="placeholder" contenteditable="true"></div>

CSS3:

.placeholder:after {
    content: "Your placeholder"; /* this is where you assign the place holder */
    position: absolute;
    top: 10px;
    color: #a9a9a9;
}

jQuery:

$('.placeholder').on('input', function(){
    if ($(this).text().length > 0) {
        $(this).removeClass('placeholder');
    } else {
        $(this).addClass('placeholder');
    }
});

DÉMO: http://jsfiddle.net/Tomer123/D78X7/

4
surfs up

Voici le correctif que j'ai utilisé.

<div contenteditable><em>Edit me</em></div>
<script>
$('div').focus(function() {
    var target = $(this);
    window.setTimeout(function() { target.empty(); }, 10);
});
</script>

J'ai développé un plug-in jQuery pour cela. Jetez un oeil https://github.com/phitha/editableDiv

1
Phitha

Ce n'est pas une solution exacte à votre problème.

dans le jeu d'options summernote

airMode: true

l'espace réservé fonctionne de cette façon.

0
Ganesh S
var curText = 'Edit me';
$('div').focusin(function() {
    if ($(this).text().toLowerCase() == curText.toLowerCase() || !$(this).text().length) {
        $(this).empty();
    }
}).focusout(function() {
    if ($(this).text().toLowerCase() == curText.toLowerCase() || !$(this).text().length) {
        $(this).html('<em>' + curText + '</em>');
    }
});
0
thecodeparadox