(function() { var global = {}; global.version = "4.2.4"; global.issueTrackingUrl = "https://github.com/qoomon/Jira-Issue-Card-Printer"; global.isDev = document.currentScript == null; global.isProd = !global.isDev; window.addEventListener("error", function(event) { var error = event.error; console.log("ERROR: " + error.stack); if (global.isProd) { ga('send', 'exception', { 'exDescription': error.message, 'exFatal': true }); } }); // load jQuery if (window.jQuery === undefined) { appendScript('//ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js'); } // wait untill all scripts loaded appendScript('https://qoomon.github.io/void', function() { init().then(function(){ main(); }).catch(function(cause){ console.log("ERROR " + JSON.stringify(cause,2,2)); alert("Sorry somthing went wrong. Please create an issue at " + global.issueTrackingUrl); }); }); function main() { console.log("Run...") // determine application if (jQuery("meta[name='application-name'][ content='JIRA']").length > 0) { console.log("App: " + "Jira"); global.appFunctions = jiraFunctions; } else if (/.*pivotaltracker.com\/.*/g.test(document.URL)) { console.log("App: " + "PivotalTracker"); global.appFunctions = pivotalTrackerFunctions; } else if (/.*trello.com\/.*/g.test(document.URL)) { console.log("App: " + "Trello"); global.appFunctions = trelloFunctions; } else if (/.*\/youtrack\/.*/g.test(document.URL)) { console.log("App: " + "YouTrack"); global.appFunctions = youTrackFunctions; } else { alert("Unsupported app. Please create an issue at " + global.issueTrackingUrl); return; } //preconditions if (jQuery("#card-print-overlay").length > 0) { alert("Print Card already opened!"); return; } // collect selcted issues var issueKeyList = global.appFunctions.getSelectedIssueKeyList(); if (issueKeyList.length <= 0) { alert("Please select at least one issue."); return; } // open print preview jQuery("body").append(printPreviewElement()); jQuery("#card-print-overlay").prepend(printOverlayStyleElement()); var printFrame = jQuery("#card-print-dialog-content-iframe"); var printWindow = printFrame[0].contentWindow; printWindow.addEventListener("resize", function() { redrawCards(); }); printWindow.matchMedia("print").addListener(function() { redrawCards(); }); jQuery("#rowCount").val(readCookie("card_printer_row_count", 2)); jQuery("#columnCount").val(readCookie("card_printer_column_count", 1)); //jQuery("#font-scale-range").val(readCookie("card_printer_font_scale",1)); jQuery("#single-card-page-checkbox").attr('checked', readCookie("card_printer_single_card_page", 'true') == 'true'); jQuery("#hide-description-checkbox").attr('checked', readCookie("card_printer_hide_description", 'false') == 'true'); jQuery("#hide-assignee-checkbox").attr('checked', readCookie("card_printer_hide_assignee", 'true') == 'true'); jQuery("#hide-due-date-checkbox").attr('checked', readCookie("card_printer_hide_due_date", 'false') == 'true'); jQuery("#hide-status-checkbox").attr('checked', readCookie("card_printer_hide_status", 'true') == 'true'); jQuery("#card-print-dialog-title").text("Card Printer " + global.version + " - Loading issues..."); renderCards(issueKeyList).then(function() { jQuery("#card-print-dialog-title").text("Card Printer " + global.version); //print(); }); if (global.isProd) { ga('send', 'pageview'); } } function init() { var promises = []; console.log("Init...") addStringFunctions(); addDateFunctions(); global.hostOrigin = "https://qoomon.github.io/Jira-Issue-Card-Printer/"; if (global.isDev) { console.log("DEVELOPMENT"); global.hostOrigin = "https://rawgit.com/qoomon/Jira-Issue-Card-Printer/develop/"; } global.resourceOrigin = global.hostOrigin + "resources/"; if (global.isProd) { initGoogleAnalytics(); } promises.push(httpGetCORS(global.hostOrigin + "card.html").then(function(data){ global.cardHtml = data; })); promises.push(httpGetCORS(global.hostOrigin + "card.css").then(function(data){ global.cardCss = data.replace(/https:\/\/qoomon.github.io\/Jira-Issue-Card-Printer\/resources/g, global.resourceOrigin); })); promises.push(httpGetCORS(global.hostOrigin + "printPreview.html").then(function(data){ global.printPreviewHtml = data })); promises.push(httpGetCORS(global.hostOrigin + "printPreview.css").then(function(data){ global.printPreviewCss = data.replace(/https:\/\/qoomon.github.io\/Jira-Issue-Card-Printer\/resources/g, global.resourceOrigin); })); return Promise.all(promises); } function print() { var printFrame = jQuery("#card-print-dialog-content-iframe"); var printWindow = printFrame[0].contentWindow; var printDocument = printWindow.document; if (global.isProd) { ga('send', 'event', 'button', 'click', 'print', jQuery(".card", printDocument).length); } printWindow.print(); } function renderCards(issueKeyList) { var promises = []; var printFrame = jQuery("#card-print-dialog-content-iframe"); var printWindow = printFrame[0].contentWindow; var printDocument = printWindow.document; printDocument.open(); printDocument.write("
"); jQuery("head", printDocument).append(cardElementStyle()); jQuery("body", printDocument).append(""); jQuery("#preload", printDocument).append(""); console.log("load " + issueKeyList.length + " issues..."); jQuery.each(issueKeyList, function(index, issueKey) { var card = cardElement(issueKey); card.attr("index", index); card.hide(); card.find('.issue-id').text(issueKey); jQuery("body", printDocument).append(card); promises.push(global.appFunctions.getCardData(issueKey).then(function(cardData) { console.log("cardData: " + JSON.stringify(cardData,2,2)); if (global.isProd) { ga('send', 'event', 'card', 'generate', cardData.type); } fillCard(card, cardData); redrawCards(); card.show(); })); }); console.log("wait for issues loaded..."); return Promise.all(promises).then(function() { console.log("...all issues loaded."); jQuery(printWindow).load(function() { console.log("...all resources loaded."); }); console.log("wait for resources loaded..."); printDocument.close(); }).catch(function(cause){ console.log("ERROR " + JSON.stringify(cause)) });; } function redrawCards() { styleCards(); scaleCards(); cropCards(); resizeIframe(jQuery("#card-print-dialog-content-iframe")); } function fillCard(card, data) { //Key card.find('.issue-id').text(data.key); //Type card.find(".issue-icon").attr("type", data.type); //Summary card.find('.issue-summary').text(data.summary); //Description if (data.description) { card.find('.issue-description').html(data.description); } else { card.find(".issue-description").addClass("hidden"); } //Assignee if (data.assignee) { if (data.avatarUrl) { card.find(".issue-assignee").css("background-image", "url('" + data.avatarUrl + "')"); } else { card.find(".issue-assignee").text(data.assignee[0].toUpperCase()); } } else { card.find(".issue-assignee").addClass("hidden"); } //Due-Date if (data.dueDate) { card.find(".issue-due-date").text(data.dueDate); } else { card.find(".issue-due-box").addClass("hidden"); } //Attachment if (data.hasAttachment) {} else { card.find('.issue-attachment').addClass('hidden'); } //Story Points if (data.storyPoints) { card.find(".issue-estimate").text(data.storyPoints); } else { card.find(".issue-estimate").addClass("hidden"); } //Epic if (data.superIssue) { card.find(".issue-epic-id").text(data.superIssue.key); card.find(".issue-epic-name").text(data.superIssue.summary); } else { card.find(".issue-epic-box").addClass("hidden"); } //QR-Code var qrCodeUrl = 'https://chart.googleapis.com/chart?cht=qr&chs=256x256&chld=L|1&chl=' + encodeURIComponent(data.url); card.find(".issue-qr-code").css("background-image", "url('" + qrCodeUrl + "')"); } function styleCards() { var printFrame = jQuery("#card-print-dialog-content-iframe"); var printWindow = printFrame[0].contentWindow; var printDocument = printWindow.document; // hide/show description jQuery("#styleHideDescription", printDocument).remove(); if (jQuery("#hide-description-checkbox")[0].checked) { var style = document.createElement('style'); style.id = 'styleHideDescription'; style.type = 'text/css'; style.innerHTML = ".issue-description { display: none; }" jQuery("head", printDocument).append(style); } // hide/show assignee jQuery("#styleHideAssignee", printDocument).remove(); if (jQuery("#hide-assignee-checkbox")[0].checked) { var style = document.createElement('style'); style.id = 'styleHideAssignee'; style.type = 'text/css'; style.innerHTML = ".issue-assignee { display: none; }" jQuery("head", printDocument).append(style); } // hide/show assignee jQuery("#styleHideDueDate", printDocument).remove(); if (jQuery("#hide-due-date-checkbox")[0].checked) { var style = document.createElement('style'); style.id = 'styleHideDueDate'; style.type = 'text/css'; style.innerHTML = ".issue-due-box { display: none; }" jQuery("head", printDocument).append(style); } // hide/show status jQuery("#styleHideStatus", printDocument).remove(); if (!jQuery("#hide-status-checkbox")[0].checked) { var style = document.createElement('style'); style.id = 'styleHideStatus'; style.type = 'text/css'; style.innerHTML = ".issue-status { display: none; }" jQuery("head", printDocument).append(style); } // enable/disable single card page jQuery("#styleSingleCardPage", printDocument).remove(); if (jQuery("#single-card-page-checkbox")[0].checked) { var style = document.createElement('style'); style.id = 'styleSingleCardPage'; style.type = 'text/css'; style.innerHTML = ".card { page-break-after: always; float: none; }" jQuery("head", printDocument).append(style); } } function scaleCards() { var printFrame = jQuery("#card-print-dialog-content-iframe"); var printWindow = printFrame[0].contentWindow; var printDocument = printWindow.document; var columnCount = jQuery("#columnCount").val(); var rowCount = jQuery("#rowCount").val(); var cardCount = jQuery(".card", printDocument).length; var pageCount = Math.ceil(cardCount / (columnCount * rowCount)) // scale // reset scale jQuery("html", printDocument).css("font-size", "1cm"); jQuery("#styleColumnCount", printDocument).remove(); jQuery("#styleRowCount", printDocument).remove(); // scale horizontal // substract one pixel due to rounding problems var cardMaxWidth = Math.floor(jQuery(".card", printDocument).outerWidth() / columnCount); var cardMinWidth = jQuery(".card", printDocument).css("min-width").replace("px", ""); var scaleWidth = cardMaxWidth / cardMinWidth - 0.01; // scale vertical // substract one pixel due to rounding problems // dont know why to multiply outer height with 2 var cardMaxHeight = Math.floor(jQuery(".card", printDocument).outerHeight() / rowCount); var cardMinHeight = jQuery(".card", printDocument).css("min-height").replace("px", ""); var scaleHeight = cardMaxHeight / cardMinHeight - 0.01; // scale down var scale = Math.min(scaleWidth, scaleHeight, 1); if (scale < 1) { jQuery("html", printDocument).css("font-size", scale + "cm"); } // size // size horizontal var style = document.createElement('style'); style.id = 'styleColumnCount'; style.type = 'text/css'; style.innerHTML = ".card { width: calc( 100% / " + columnCount + " - 0.001px ); }" jQuery("head", printDocument).append(style); // size horizontal var style = document.createElement('style'); style.id = 'styleRowCount'; style.type = 'text/css'; style.innerHTML = ".card { height: calc( 100% / " + rowCount + " - 0.001px ); }" jQuery("head", printDocument).append(style); } function cropCards() { var printFrame = jQuery("#card-print-dialog-content-iframe"); var printWindow = printFrame[0].contentWindow; var printDocument = printWindow.document; var cardElements = printDocument.querySelectorAll(".card"); forEach(cardElements, function(cardElement) { var cardContent = cardElement.querySelectorAll(".card-body")[0]; if (cardContent.scrollHeight > cardContent.offsetHeight) { cardContent.classList.add("zigzag"); } else { cardContent.classList.remove("zigzag"); } }); } function forEach(array, callback) { for (i = 0; i < array.length; i++) { callback(array[i]); } } function closePrintPreview() { jQuery("#card-print-overlay").remove(); jQuery("#card-print-overlay-style").remove(); } //############################################################################################################################ //############################################################################################################################ //############################################################################################################################ // http://www.cssdesk.com/T9hXg function printPreviewElement() { var result = jQuery('').html(global.printPreviewHtml).contents(); // info result.find("#report-issue").click(function(event) { window.open('https://github.com/qoomon/Jira-Issue-Card-Printer/issues'); return false; }); result.find("#about").click(function(event) { window.open('http://qoomon.blogspot.de/2014/01/jira-issue-card-printer-bookmarklet.html'); return false; }); // enable single card page result.find("#single-card-page-checkbox").click(function() { writeCookie("card_printer_single_card_page", this.checked); redrawCards(); return true; }); // hide description result.find("#hide-description-checkbox").click(function() { writeCookie("card_printer_hide_description", this.checked); redrawCards(); return true; }); // show assignee result.find("#hide-assignee-checkbox").click(function() { writeCookie("card_printer_hide_assignee", this.checked); redrawCards(); return true; }); // show due date result.find("#hide-due-date-checkbox").click(function() { writeCookie("card_printer_hide_due_date", this.checked); redrawCards(); return true; }); // show status result.find("#hide-status-checkbox").click(function() { writeCookie("card_printer_hide_status", this.checked); redrawCards(); return true; }); // scale font result.find("#font-scale-range").on("input", function() { writeCookie("card_printer_font_scale", jQuery(this).val()); var printFrame = result.find("#card-print-dialog-content-iframe"); var printWindow = printFrame[0].contentWindow; var printDocument = printWindow.document; jQuery("html", printDocument).css("font-size", jQuery(this).val() + "cm"); redrawCards(); }); // grid result.find("#rowCount").on("input", function() { writeCookie("card_printer_row_count", jQuery(this).val()); redrawCards(); }); result.find("#rowCount").click(function() { this.select(); }); result.find("#columnCount").on("input", function() { writeCookie("card_printer_column_count", jQuery(this).val()); redrawCards(); }); result.find("#columnCount").click(function() { this.select(); }); // print result.find("#card-print-dialog-print") .click(function(event) { print(); return false; }); // closePrintPreview result.find("#card-print-dialog-cancel") .click(function(event) { closePrintPreview(); return false; }); result.click(function(event) { if (event.target == this) { closePrintPreview(); } return true; }); jQuery(document).keyup(function(e) { if (e.keyCode == 27) { // ESC closePrintPreview(); } }); // prevent background scrolling result.scroll(function(event) { return false; }); return result; } function printOverlayStyleElement() { var result = jQuery(document.createElement('style')) .attr("id", "card-print-overlay-style") .attr("type", "text/css") .html(global.printPreviewCss); return result; } // card layout: http://jsfiddle.net/qoomon/ykbLb2pw/76 function cardElement(issueKey) { var result = jQuery('').html(global.cardHtml).contents() .attr("id", issueKey) return result; } function cardElementStyle() { var result = jQuery(document.createElement('style')) .attr("type", "text/css") .html(global.cardCss); return result; } //############################################################################################################################ //############################################################################################################################ //############################################################################################################################ function appendScript(url, callback) { var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.src = url; // Then bind the event to the callback function. // There are several events for cross browser compatibility. script.onreadystatechange = callback; script.onload = callback; head.appendChild(script); } function initGoogleAnalytics() { //