recipes-printthis.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // jshint ignore: start
  2. /*
  3. * printThis v1.9.0
  4. * @desc Printing plug-in for jQuery
  5. * @author Jason Day
  6. *
  7. * Resources (based on) :
  8. * jPrintArea: http://plugins.jquery.com/project/jPrintArea
  9. * jqPrint: https://github.com/permanenttourist/jquery.jqprint
  10. * Ben Nadal: http://www.bennadel.com/blog/1591-Ask-Ben-Print-Part-Of-A-Web-Page-With-jQuery.htm
  11. *
  12. * Licensed under the MIT licence:
  13. * http://www.opensource.org/licenses/mit-license.php
  14. *
  15. * (c) Jason Day 2015
  16. *
  17. * Usage:
  18. *
  19. * $("#mySelector").printThis({
  20. * debug: false, * show the iframe for debugging
  21. * importCSS: true, * import page CSS
  22. * importStyle: false, * import style tags
  23. * printContainer: true, * grab outer container as well as the contents of the selector
  24. * loadCSS: "path/to/my.css", * path to additional css file - us an array [] for multiple
  25. * pageTitle: "", * add title to print page
  26. * removeInline: false, * remove all inline styles from print elements
  27. * printDelay: 333, * variable print delay
  28. * header: null, * prefix to html
  29. * footer: null, * postfix to html
  30. * base: false, * preserve the BASE tag, or accept a string for the URL
  31. * formValues: true * preserve input/form values
  32. * canvas: false * copy canvas elements (experimental)
  33. * doctypeString: '...' * enter a different doctype for older markup
  34. * });
  35. *
  36. * Notes:
  37. * - the loadCSS will load additional css (with or without @media print) into the iframe, adjusting layout
  38. *
  39. * jshint onevar: false, smarttabs: true, devel: true
  40. */
  41. ;
  42. (function($) {
  43. var opt;
  44. $.fn.printThis = function(options) {
  45. opt = $.extend({}, $.fn.printThis.defaults, options);
  46. var $element = this instanceof jQuery ? this : $(this);
  47. var strFrameName = "printThis-" + (new Date()).getTime();
  48. if (window.location.hostname !== document.domain && navigator.userAgent.match(/msie/i)) {
  49. // Ugly IE hacks due to IE not inheriting document.domain from parent
  50. // checks if document.domain is set by comparing the host name against document.domain
  51. var iframeSrc = "javascript:document.write(\"<head><script>document.domain=\\\"" + document.domain + "\\\";</s" + "cript></head><body></body>\")";
  52. var printI = document.createElement('iframe');
  53. printI.name = "printIframe";
  54. printI.id = strFrameName;
  55. printI.className = "MSIE";
  56. document.body.appendChild(printI);
  57. printI.src = iframeSrc;
  58. } else {
  59. // other browsers inherit document.domain, and IE works if document.domain is not explicitly set
  60. var $frame = $("<iframe id='" + strFrameName + "' name='printIframe' />");
  61. $frame.appendTo("body");
  62. }
  63. var $iframe = $("#" + strFrameName);
  64. // show frame if in debug mode
  65. if (!opt.debug) $iframe.css({
  66. position: "absolute",
  67. width: "0px",
  68. height: "0px",
  69. left: "-600px",
  70. top: "-600px"
  71. });
  72. // $iframe.ready() and $iframe.load were inconsistent between browsers
  73. setTimeout(function() {
  74. // Add doctype to fix the style difference between printing and render
  75. function setDocType($iframe,doctype){
  76. var win, doc;
  77. win = $iframe.get(0);
  78. win = win.contentWindow || win.contentDocument || win;
  79. doc = win.document || win.contentDocument || win;
  80. doc.open();
  81. doc.write(doctype);
  82. doc.close();
  83. }
  84. if(opt.doctypeString){
  85. setDocType($iframe,opt.doctypeString);
  86. }
  87. var $doc = $iframe.contents(),
  88. $head = $doc.find("head"),
  89. $body = $doc.find("body"),
  90. $base = $('base'),
  91. baseURL;
  92. // add base tag to ensure elements use the parent domain
  93. if (opt.base === true && $base.length > 0) {
  94. // take the base tag from the original page
  95. baseURL = $base.attr('href');
  96. } else if (typeof opt.base === 'string') {
  97. // An exact base string is provided
  98. baseURL = opt.base;
  99. } else {
  100. // Use the page URL as the base
  101. baseURL = document.location.protocol + '//' + document.location.host;
  102. }
  103. $head.append('<base href="' + baseURL + '">');
  104. // import page stylesheets
  105. if (opt.importCSS) $("link[rel=stylesheet]").each(function() {
  106. var href = $(this).attr("href");
  107. if (href) {
  108. var media = $(this).attr("media") || "all";
  109. $head.append("<link type='text/css' rel='stylesheet' href='" + href + "' media='" + media + "'>");
  110. }
  111. });
  112. // import style tags
  113. if (opt.importStyle) $("style").each(function() {
  114. $(this).clone().appendTo($head);
  115. });
  116. // add title of the page
  117. if (opt.pageTitle) $head.append("<title>" + opt.pageTitle + "</title>");
  118. // import additional stylesheet(s)
  119. if (opt.loadCSS) {
  120. if( $.isArray(opt.loadCSS)) {
  121. jQuery.each(opt.loadCSS, function(index, value) {
  122. $head.append("<link type='text/css' rel='stylesheet' href='" + this + "'>");
  123. });
  124. } else {
  125. $head.append("<link type='text/css' rel='stylesheet' href='" + opt.loadCSS + "'>");
  126. }
  127. }
  128. // print header
  129. if (opt.header) $body.append(opt.header);
  130. if (opt.canvas) {
  131. // add canvas data-ids for easy access after the cloning.
  132. var canvasId = 0;
  133. $element.find('canvas').each(function(){
  134. $(this).attr('data-printthis', canvasId++);
  135. });
  136. }
  137. // grab $.selector as container
  138. if (opt.printContainer) $body.append($element.outer());
  139. // otherwise just print interior elements of container
  140. else $element.each(function() {
  141. $body.append($(this).html());
  142. });
  143. if (opt.canvas) {
  144. // Re-draw new canvases by referencing the originals
  145. $body.find('canvas').each(function(){
  146. var cid = $(this).data('printthis'),
  147. $src = $('[data-printthis="' + cid + '"]');
  148. this.getContext('2d').drawImage($src[0], 0, 0);
  149. // Remove the mark-up from the original
  150. $src.removeData('printthis');
  151. });
  152. }
  153. // capture form/field values
  154. if (opt.formValues) {
  155. // loop through inputs
  156. var $input = $element.find('input');
  157. if ($input.length) {
  158. $input.each(function() {
  159. var $this = $(this),
  160. $name = $(this).attr('name'),
  161. $checker = $this.is(':checkbox') || $this.is(':radio'),
  162. $iframeInput = $doc.find('input[name="' + $name + '"]'),
  163. $value = $this.val();
  164. // order matters here
  165. if (!$checker) {
  166. $iframeInput.val($value);
  167. } else if ($this.is(':checked')) {
  168. if ($this.is(':checkbox')) {
  169. $iframeInput.attr('checked', 'checked');
  170. } else if ($this.is(':radio')) {
  171. $doc.find('input[name="' + $name + '"][value="' + $value + '"]').attr('checked', 'checked');
  172. }
  173. }
  174. });
  175. }
  176. // loop through selects
  177. var $select = $element.find('select');
  178. if ($select.length) {
  179. $select.each(function() {
  180. var $this = $(this),
  181. $name = $(this).attr('name'),
  182. $value = $this.val();
  183. $doc.find('select[name="' + $name + '"]').val($value);
  184. });
  185. }
  186. // loop through textareas
  187. var $textarea = $element.find('textarea');
  188. if ($textarea.length) {
  189. $textarea.each(function() {
  190. var $this = $(this),
  191. $name = $(this).attr('name'),
  192. $value = $this.val();
  193. $doc.find('textarea[name="' + $name + '"]').val($value);
  194. });
  195. }
  196. } // end capture form/field values
  197. // remove inline styles
  198. if (opt.removeInline) {
  199. // $.removeAttr available jQuery 1.7+
  200. if ($.isFunction($.removeAttr)) {
  201. $doc.find("body *").removeAttr("style");
  202. } else {
  203. $doc.find("body *").attr("style", "");
  204. }
  205. }
  206. // print "footer"
  207. if (opt.footer) $body.append(opt.footer);
  208. setTimeout(function() {
  209. if ($iframe.hasClass("MSIE")) {
  210. // check if the iframe was created with the ugly hack
  211. // and perform another ugly hack out of neccessity
  212. window.frames["printIframe"].focus();
  213. $head.append("<script> window.print(); </s" + "cript>");
  214. } else {
  215. // proper method
  216. if (document.queryCommandSupported("print")) {
  217. $iframe[0].contentWindow.document.execCommand("print", false, null);
  218. } else {
  219. $iframe[0].contentWindow.focus();
  220. $iframe[0].contentWindow.print();
  221. }
  222. }
  223. // remove iframe after print
  224. if (!opt.debug) {
  225. setTimeout(function() {
  226. $iframe.remove();
  227. }, 1000);
  228. }
  229. }, opt.printDelay);
  230. }, 333);
  231. };
  232. // defaults
  233. $.fn.printThis.defaults = {
  234. debug: false, // show the iframe for debugging
  235. importCSS: true, // import parent page css
  236. importStyle: false, // import style tags
  237. printContainer: true, // print outer container/$.selector
  238. loadCSS: "", // load an additional css file - load multiple stylesheets with an array []
  239. pageTitle: "", // add title to print page
  240. removeInline: false, // remove all inline styles
  241. printDelay: 333, // variable print delay
  242. header: null, // prefix to html
  243. footer: null, // postfix to html
  244. formValues: true, // preserve input/form values
  245. canvas: false, // Copy canvas content (experimental)
  246. base: false, // preserve the BASE tag, or accept a string for the URL
  247. doctypeString: '<!DOCTYPE html>' // html doctype
  248. };
  249. // $.selector container
  250. jQuery.fn.outer = function() {
  251. return $($("<div></div>").html(this.clone())).html();
  252. }
  253. })(jQuery);