web-dev-qa-db-fra.com

Twitter Bootstrap: imprimer le contenu de la fenêtre modale

Je développe un site utilisant Bootstrap, qui comporte 28 fenêtres modales contenant des informations sur différents produits. Je veux pouvoir imprimer les informations dans une fenêtre modale ouverte. Chaque fenêtre a une id

<!-- firecell panel & radio hub -->
           <div class="modal hide fade" id="fcpanelhub">
              <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">X</button>
                <h3>5000 Control Panel & Radio Hub</h3>
              </div>
              <div class="modal-body">
                <img src="../site/img/firecell/firecell-panel-info-1.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-panel-info-2.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-radio-hub-info-1.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-radio-hub-info-2.png" alt=""/>
              </div>
              <div class="modal-footer">
                <a href="#" class="btn" data-dismiss="modal">Close</a>
              </div>    
           </div>

Donc, si j'ajoute un nouveau bouton dans modal-footer - 'print', et que l'on clique dessus, je veux que ce modal soit imprimé. Aurais-je raison de dire que javascript serait utilisé? Si oui, comment puis-je dire à javascript de n'imprimer que le modal ouvert, et pas les autres?

Toute aide appréciée.

42
MattSull

Une autre solution

Voici une nouvelle solution basée sur Bennett McElwee répond dans la même question comme mentionné ci-dessous.

Testé avec IE 9 et 10, Opera 12.01, Google Chrome 22 et Firefox 15.0. 
Exemple jsFiddle

1.) Ajoutez ce CSS à votre site:

@media screen {
  #printSection {
      display: none;
  }
}

@media print {
  body * {
    visibility:hidden;
  }
  #printSection, #printSection * {
    visibility:visible;
  }
  #printSection {
    position:absolute;
    left:0;
    top:0;
  }
}

2.) Ajouter ma fonction JavaScript

function printElement(elem, append, delimiter) {
    var domClone = elem.cloneNode(true);

    var $printSection = document.getElementById("printSection");

    if (!$printSection) {
        $printSection = document.createElement("div");
        $printSection.id = "printSection";
        document.body.appendChild($printSection);
    }

    if (append !== true) {
        $printSection.innerHTML = "";
    }

    else if (append === true) {
        if (typeof (delimiter) === "string") {
            $printSection.innerHTML += delimiter;
        }
        else if (typeof (delimiter) === "object") {
            $printSection.appendChild(delimiter);
        }
    }

    $printSection.appendChild(domClone);
}​

Vous êtes prêt à imprimer n'importe quel élément de votre site!
Appelez simplement printElement() avec votre ou vos éléments et exécutez window.print() lorsque vous avez terminé.

Remarque: Si vous souhaitez modifier le contenu avant son impression (et uniquement dans la version imprimée), vérifiez cet exemple (fourni par waspina dans les commentaires): http://jsfiddle.net/95ezN/121/

On pourrait aussi utiliser CSS pour afficher le contenu supplémentaire dans la version imprimée (et seulement là).


Ancienne solution

Je pense que vous devez cacher toutes les autres parties du site via CSS.

Il serait préférable de déplacer tout le contenu non imprimable dans une DIV séparée:

<body>
  <div class="non-printable">
    <!-- ... -->
  </div>

  <div class="printable">
    <!-- Modal dialog comes here -->
  </div>
</body>

Et ensuite dans votre CSS:

.printable { display: none; }

@media print
{
    .non-printable { display: none; }
    .printable { display: block; }
}

Les crédits vont à Greg qui a déjà répondu à une question similaire: Imprimer <div id = "printarea"> </ div> seulement?

Il y a un problème lié à l'utilisation de JavaScript: l'utilisateur ne peut pas voir un aperçu - du moins dans Internet Explorer!

54
ComFreek

Je vous suggère d'essayer ce plugin jQuery print element

Il peut vous laisser simplement imprimer l'élément que vous avez sélectionné.

8
maxisam

Avec la solution actuellement acceptée, vous ne pouvez plus imprimer la page contenant la boîte de dialogue elle-même. Voici une solution beaucoup plus dynamique:

JavaScript:

$().ready(function () {
    $('.modal.printable').on('shown.bs.modal', function () {
        $('.modal-dialog', this).addClass('focused');
        $('body').addClass('modalprinter');

        if ($(this).hasClass('autoprint')) {
            window.print();
        }
    }).on('hidden.bs.modal', function () {
        $('.modal-dialog', this).removeClass('focused');
        $('body').removeClass('modalprinter');
    });
});

CSS:

@media print {
    body.modalprinter * {
        visibility: hidden;
    }

    body.modalprinter .modal-dialog.focused {
        position: absolute;
        padding: 0;
        margin: 0;
        left: 0;
        top: 0;
    }

    body.modalprinter .modal-dialog.focused .modal-content {
        border-width: 0;
    }

    body.modalprinter .modal-dialog.focused .modal-content .modal-header .modal-title,
    body.modalprinter .modal-dialog.focused .modal-content .modal-body,
    body.modalprinter .modal-dialog.focused .modal-content .modal-body * {
        visibility: visible;
    }

    body.modalprinter .modal-dialog.focused .modal-content .modal-header,
    body.modalprinter .modal-dialog.focused .modal-content .modal-body {
        padding: 0;
    }

    body.modalprinter .modal-dialog.focused .modal-content .modal-header .modal-title {
        margin-bottom: 20px;
    }
}

Exemple:

<div class="modal fade printable autoprint">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <p>One fine body&hellip;</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary" onclick="window.print();">Print</button>
      </div>
    </div><!-- /.modal-content -->
  </div><!-- /.modal-dialog -->
</div><!-- /.modal -->
8
dtrunk

Voici une option utilisant une extension JQuery que j'ai créée à partir du code waspinator dans les commentaires de la réponse acceptée:

jQuery.fn.extend({
    printElem: function() {
        var cloned = this.clone();
        var printSection = $('#printSection');
        if (printSection.length == 0) {
            printSection = $('<div id="printSection"></div>')
            $('body').append(printSection);
        }
        printSection.append(cloned);
        var toggleBody = $('body *:visible');
        toggleBody.hide();
        $('#printSection, #printSection *').show();
        window.print();
        printSection.remove();
        toggleBody.show();
    }
});

$(document).ready(function(){
    $(document).on('click', '#btnPrint', function(){
        $('.printMe').printElem();
    });
});

JSFiddle: http://jsfiddle.net/95ezN/1227/

Cela peut être utile si vous ne souhaitez pas que cela s'applique à chaque impression et que vous le fassiez simplement sur votre bouton d'impression personnalisé (ce qui était mon cas).

6
bostero2

Il s'agit d'une solution révisée qui fonctionnera également pour les fenêtres modales rendues à l'aide d'un modèle Grails, dans lequel vous pouvez avoir le même modèle modal appelé plusieurs fois (avec des valeurs différentes) dans le même corps. Ce fil m'a énormément aidé, alors j'ai pensé le partager au cas où d'autres utilisateurs de Grails s'y retrouveraient.

Pour ceux qui sont curieux, la solution acceptée ne fonctionnait pas pour moi car je rendais un tableau; chaque ligne a un bouton qui ouvre une fenêtre modale avec plus de détails sur l'enregistrement. Cela a conduit à la création de plusieurs divs printSection et à leur impression superposées. Par conséquent, je devais réviser le JS pour nettoyer la div après l’impression.

CSS

J'ai ajouté ce CSS directement à mon gsp modal, mais l'ajouter au parent a le même effet .

<style type="text/css">
   @media screen {
        #printSection {
           display: none;
        }
   }

   @media print {
        body > *:not(#printSection) {
           display: none;
        }
        #printSection, #printSection * {
            visibility: visible;
        }
        #printSection {
            position:absolute;
            left:0;
            top:0;
        }
   }
</style>

L'ajouter à la CSS au niveau du site a tué la fonctionnalité d'impression dans d'autres parties du site. Je l'ai tiré de la réponse acceptée de ComFreak (basée sur Bennett McElwee answer ), mais elle a été modifiée à l'aide de la fonctionnalité ': not' de la réponse de fanfavorite sur Print <div id = printarea> </ div> seulement? J'ai opté pour l'affichage plutôt que pour la visibilité, car mon corps invisible masquait la création de pages vierges supplémentaires, ce qui était inacceptable pour mes utilisateurs.

js

Et ceci à mon code javascript, corrigé de la réponse acceptée de ComFreak à cette question.

function printDiv(div) {    
    // Create and insert new print section
    var elem = document.getElementById(div);
    var domClone = elem.cloneNode(true);
    var $printSection = document.createElement("div");
    $printSection.id = "printSection";
    $printSection.appendChild(domClone);
    document.body.insertBefore($printSection, document.body.firstChild);

    window.print(); 

    // Clean up print section for future use
    var oldElem = document.getElementById("printSection");
    if (oldElem != null) { oldElem.parentNode.removeChild(oldElem); } 
                          //oldElem.remove() not supported by IE

    return true;
}

Je n'avais pas besoin d'ajouter des éléments, j'ai donc supprimé cet aspect et modifié la fonction pour imprimer spécifiquement une div. 

HTML (gsp)

Et le modèle modal. Ceci affiche l’en-tête et le corps modaux et exclut le pied de page où se trouvaient les boutons .

<div class="modal-content">
    <div id="print-me"> <!-- This is the div that is cloned and printed -->
        <div class="modal-header">
            <!-- HEADER CONTENT -->
        </div>
        <div class="modal-body">
             <!-- BODY CONTENT -->
        </div>
    </div>
    <div class="modal-footer">
                                 <!-- This is where I specify the div to print -->
        <button type="button" class="btn btn-default" onclick="printDiv('print-me')">Print</button>
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
    </div>
</div>

J'espère que cela aide quelqu'un!

4
Kara Johnson

Je viens d'utiliser un peu de jQuery/javascript:

html:

<h1>Don't Print</h1>

<a data-target="#myModal" role="button" class="btn" data-toggle="modal">Launch modal</a>

<div class="modal fade hide" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"      aria-hidden="true">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
     <h3 id="myModalLabel">Modal to print</h3>
  </div>
  <div class="modal-body">
    <p>Print Me</p>
  </div>
  <div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <button class="btn btn-primary" id="printButton">Print</button>
  </div>
</div>

js:

$('#printButton').on('click', function () {
if ($('.modal').is(':visible')) {
    var modalId = $(event.target).closest('.modal').attr('id');
    $('body').css('visibility', 'hidden');
    $("#" + modalId).css('visibility', 'visible');
    $('#' + modalId).removeClass('modal');
    window.print();
    $('body').css('visibility', 'visible');
    $('#' + modalId).addClass('modal');
} else {
    window.print();
}

});

voici le violon

3
alexoviedo999

Voici une solution sans Javascript ni plugin - juste quelques classes CSS et une classe supplémentaire dans le balisage . Cette solution utilise le fait que BootStrap ajoute une classe au corps lorsqu'une boîte de dialogue est ouverte. Nous utilisons cette classe pour ensuite cacher le corps et n’imprimer que le dialogue.

Pour nous assurer que nous pouvons déterminer le corps principal de la page, nous devons tout contenir dans le contenu de la page principale d'un div. J'ai utilisé id = "mainContent". Exemple de mise en page ci-dessous - avec une page principale et deux boîtes de dialogue

<body>
 <div class="container body-content">

  <div id="mainContent">
       main page stuff     
  </div>
  <!-- Dialog One -->
  <div class="modal fade in">
   <div class="modal-dialog">
    <div class="modal-content">
          ...
    </div>
   </div>
  </div>

  <!-- Dialog Two -->
  <div class="modal fade in">
   <div class="modal-dialog">
    <div class="modal-content">
          ...
    </div>
   </div>
  </div>

 </div>
</body>

Ensuite, dans nos requêtes de support d'impression CSS, j'utilise display: none pour masquer tout ce que je ne veux pas afficher - c'est-à-dire le contenu principal lorsqu'une boîte de dialogue est ouverte. J'utilise également une classe spécifique noPrint à utiliser sur toutes les parties de la page qui ne doivent pas être affichées, par exemple les boutons d'action. Ici, je cache aussi les en-têtes et les pieds de page. Vous aurez peut-être besoin de le modifier pour obtenir exactement ce que vous voulez.

@media print {
    header, .footer, footer {
        display: none;
    }

    /* hide main content when dialog open */
    body.modal-open div.container.body-content div#mainContent {
        display: none;
    }

    .noPrint {
        display: none;
    }
}
0
Peter Kerr

Je faisais face à deux problèmes Problème 1: tous les champs venaient les uns après les autres et Problème 2 un espace blanc au bas de la page lorsqu’on utilisait l’impression contextuelle.

J'ai résolu ceci par

rendant affiche aucun à tous les éléments body * la plupart d'entre eux ont une visibilité cachée, ce qui crée de l'espace, donc évite la visibilité cachée

    @media print {
        body * {
           display:none;
        width:auto;
        height:auto;
        margin:0px;padding:0px; 
        }
        #printSection, #printSection * {
            display:inline-block!important;
        }
        #printSection {
            position:absolute;
            left:0;
            top:0;  
            margin:0px; 
            page-break-before: none;
            page-break-after: none;
            page-break-inside: avoid;      
        }
#printSection .form-group{

      width:100%!important;
      float:left!important;
      page-break-after: avoid;
    }
#printSection label{
        float:left!important;
        width:200px!important;
        display:inline-block!important;
      }

#printSection .form-control.search-input{
        float:left!important;
        width:200px!important;
        display: inline-block!important;
      }
}
0
Nadeemmnn Mohd