Update
This commit is contained in:
parent
292f516e33
commit
082be76c51
@ -32,8 +32,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body d-flex justify-content-center align-items-center">
|
<div class="modal-body d-flex justify-content-center align-items-center">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row" >
|
<div class="row" ref="qrInfo" id="qrInfo">
|
||||||
<div class="col-6 text-center">
|
<div class="col-5 text-center">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div id="QrContainer"></div>
|
<div id="QrContainer"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,19 +43,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 text-center">
|
<div class="col-7 d-flex align-items-center justify-content-center">
|
||||||
<div class="col-12 text-center">
|
<div class="text-center fs-4 text">
|
||||||
Department: {{thisQRInfo.departmentName}}
|
<div class="col-12 my-3">
|
||||||
|
{{thisQRInfo.departmentName}}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 text-center">
|
<div class="col-12 my-3">
|
||||||
Item: {{thisQRInfo.productName}}
|
{{thisQRInfo.productName}}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 text-center">
|
<div class="col-12 my-3">
|
||||||
Warranty: {{thisQRInfo.endWDate}}
|
{{thisQRInfo.endWDate}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<button v-on:click="printQRInfo">Print QR Info</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -622,11 +627,27 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#itemDatatable tbody').on('click', '.print-btn', function () {
|
$('#itemDatatable tbody').on('click', '.print-btn', function () {
|
||||||
const itemId = $(this).data('id');
|
const $button = $(this); // The clicked button
|
||||||
var $row = $(this).closest('tr'); // get the row containing the button
|
const $row = $button.closest('tr'); // The parent row of the button
|
||||||
var imageSrc = $row.find('img').attr('src'); // find the img element in the row and get its src
|
const itemId = $button.data('id'); // Get the item ID from the button's data attribute
|
||||||
// console.log(imageSrc);
|
|
||||||
self.printItem(itemId, imageSrc);
|
let imageSrc;
|
||||||
|
|
||||||
|
// Check if the table is collapsed
|
||||||
|
if ($row.hasClass('child')) {
|
||||||
|
// For collapsed view: Look for the closest `.dtr-data` that contains the img
|
||||||
|
imageSrc = $row.prev('tr').find('td:first-child img').attr('src');
|
||||||
|
} else {
|
||||||
|
// For expanded view: Find the img in the first column of the current row
|
||||||
|
imageSrc = $row.find('td:first-child img').attr('src');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageSrc) {
|
||||||
|
console.log(imageSrc);
|
||||||
|
self.printItem(itemId, imageSrc); // Call the print function with the itemId and imageSrc
|
||||||
|
} else {
|
||||||
|
console.error("Image source not found.");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@ -898,6 +919,120 @@
|
|||||||
}
|
}
|
||||||
return this.items.find(item => item.uniqueID === uniqueID);
|
return this.items.find(item => item.uniqueID === uniqueID);
|
||||||
},
|
},
|
||||||
|
// printQRInfo() {
|
||||||
|
// const qrElement = this.$refs.qrInfo;
|
||||||
|
|
||||||
|
// if (qrElement) {
|
||||||
|
// const qrElement = this.$refs.qrInfo;
|
||||||
|
// if (qrElement) {
|
||||||
|
// domtoimage.toPng(qrElement,{
|
||||||
|
// quality: 1,
|
||||||
|
// })
|
||||||
|
// .then(function (dataUrl) {
|
||||||
|
// // Print the image using printJS
|
||||||
|
// printJS({
|
||||||
|
// printable: dataUrl, // Image data URL
|
||||||
|
// type: 'image',
|
||||||
|
// css: '/../lib/bootstrap/dist/css/bootstrap.css',
|
||||||
|
// style: `
|
||||||
|
// @@media print {
|
||||||
|
// @@page { margin-top: 15px; margin-bottom: 15px; }
|
||||||
|
// body { margin: 0; }
|
||||||
|
// img {
|
||||||
|
// display: block;
|
||||||
|
// margin: auto;
|
||||||
|
// width: auto;
|
||||||
|
// max-width: 100%;
|
||||||
|
// height: auto;
|
||||||
|
// max-height: 100vh;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// `
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// .catch(function (error) {
|
||||||
|
// console.error("Error generating image:", error);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// console.error("QR Info element not found.");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
printQRInfo() {
|
||||||
|
// Create a virtual DOM element
|
||||||
|
const virtualElement = document.createElement('div');
|
||||||
|
virtualElement.style.width = '500px'; // Set dimensions
|
||||||
|
virtualElement.style.height = 'auto';
|
||||||
|
virtualElement.style.position = 'absolute';
|
||||||
|
virtualElement.style.left = '-9999px'; // Position offscreen
|
||||||
|
|
||||||
|
// Populate the virtual DOM with content
|
||||||
|
virtualElement.innerHTML = `
|
||||||
|
<div class="row" id="qrInfo">
|
||||||
|
<div class="col-5 text-center">
|
||||||
|
<div id="QrContainer">
|
||||||
|
<!-- QR Code can be dynamically inserted here -->
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>${this.thisQRInfo.uniqueID}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-7 d-flex align-items-center justify-content-center">
|
||||||
|
<div class="text-center fs-4 text">
|
||||||
|
<div>${this.thisQRInfo.departmentName}</div>
|
||||||
|
<div>${this.thisQRInfo.productName}</div>
|
||||||
|
<div>${this.thisQRInfo.endWDate}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Append the virtual DOM to the body (temporarily)
|
||||||
|
document.body.appendChild(virtualElement);
|
||||||
|
|
||||||
|
// Use html2canvas to convert the virtual DOM to an image
|
||||||
|
html2canvas(virtualElement, {
|
||||||
|
scale: 10, // Increase scale for sharper image
|
||||||
|
useCORS: true,
|
||||||
|
allowTaint: true,
|
||||||
|
}).then((canvas) => {
|
||||||
|
// Convert the canvas to an image
|
||||||
|
const imgData = canvas.toDataURL('image/png');
|
||||||
|
|
||||||
|
// Use printJS to print the image
|
||||||
|
printJS({
|
||||||
|
printable: imgData,
|
||||||
|
type: 'image',
|
||||||
|
css: '/../lib/bootstrap/dist/css/bootstrap.css',
|
||||||
|
style: `
|
||||||
|
@@media print {
|
||||||
|
@@page {
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
body { margin: 0; }
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
width: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
max-height: 100vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove the virtual DOM from the body after use
|
||||||
|
document.body.removeChild(virtualElement);
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("Error generating image:", error);
|
||||||
|
// Remove the virtual DOM if an error occurs
|
||||||
|
document.body.removeChild(virtualElement);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Mono.TextTemplating;
|
using Mono.TextTemplating;
|
||||||
@ -19,11 +20,13 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
{
|
{
|
||||||
private readonly ILogger<InvMainAPI> _logger;
|
private readonly ILogger<InvMainAPI> _logger;
|
||||||
private readonly CentralSystemContext _centralDbContext;
|
private readonly CentralSystemContext _centralDbContext;
|
||||||
|
private readonly UserManager<UserModel> _userManager;
|
||||||
|
|
||||||
public InvMainAPI(ILogger<InvMainAPI> logger, CentralSystemContext centralDbContext)
|
public InvMainAPI(ILogger<InvMainAPI> logger, CentralSystemContext centralDbContext, UserManager<UserModel> userManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_centralDbContext = centralDbContext;
|
_centralDbContext = centralDbContext;
|
||||||
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DepartmentCompany
|
public class DepartmentCompany
|
||||||
@ -209,8 +212,30 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
[HttpPost("ItemList")]
|
[HttpPost("ItemList")]
|
||||||
public async Task<IActionResult> ItemList()
|
public async Task<IActionResult> ItemList()
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return BadRequest("User not found");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user.departmentId = user.departmentId != null ? user.departmentId : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userRole = await _userManager.GetRolesAsync(user);
|
||||||
|
var isAdmin = userRole.Contains("SystemAdmin") || userRole.Contains("SuperAdmin");
|
||||||
|
List<ItemModel> itemList = new List<ItemModel>();
|
||||||
// Get the item list
|
// Get the item list
|
||||||
var itemList = await _centralDbContext.Items.Include("CreatedBy").Include("Department").Include("Product").ToListAsync();
|
if (isAdmin)
|
||||||
|
{
|
||||||
|
itemList = await _centralDbContext.Items.Include("CreatedBy").Include("Department").Include("Product").ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
itemList = await _centralDbContext.Items.Include("CreatedBy").Include("Department").Include("Product").Where(i => i.DepartmentId == user.departmentId).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
// Get the departments list (DepartmentId references Departments)
|
// Get the departments list (DepartmentId references Departments)
|
||||||
var departments = await _centralDbContext.Departments.ToListAsync();
|
var departments = await _centralDbContext.Departments.ToListAsync();
|
||||||
@ -226,7 +251,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
item.SerialNumber,
|
item.SerialNumber,
|
||||||
item.Quantity,
|
item.Quantity,
|
||||||
item.Supplier,
|
item.Supplier,
|
||||||
item.PurchaseDate,
|
PurchaseDate = item.PurchaseDate.ToString("dd/MM/yyyy"),
|
||||||
item.PONo,
|
item.PONo,
|
||||||
item.Currency,
|
item.Currency,
|
||||||
item.DefaultPrice,
|
item.DefaultPrice,
|
||||||
@ -234,7 +259,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
item.ConvertPrice,
|
item.ConvertPrice,
|
||||||
item.DODate,
|
item.DODate,
|
||||||
item.Warranty,
|
item.Warranty,
|
||||||
item.EndWDate,
|
EndWDate = item.EndWDate.ToString("dd/MM/yyyy"),
|
||||||
item.InvoiceDate,
|
item.InvoiceDate,
|
||||||
item.Department?.DepartmentName,
|
item.Department?.DepartmentName,
|
||||||
item.CreatedBy!.UserName,
|
item.CreatedBy!.UserName,
|
||||||
@ -244,8 +269,11 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
|
|
||||||
return Json(itemListWithDetails);
|
return Json(itemListWithDetails);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("GenerateItemQr/{id}")]
|
[HttpPost("GenerateItemQr/{id}")]
|
||||||
public IActionResult GenerateItemQr(string id)
|
public IActionResult GenerateItemQr(string id)
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
<link rel="stylesheet" href="~/assets/libs/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css" />
|
<link rel="stylesheet" href="~/assets/libs/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css" />
|
||||||
<link rel="stylesheet" href="~/assets/libs/quill/dist/quill.snow.css" />
|
<link rel="stylesheet" href="~/assets/libs/quill/dist/quill.snow.css" />
|
||||||
<link href="~/dist/css/style.min.css" rel="stylesheet" />
|
<link href="~/dist/css/style.min.css" rel="stylesheet" />
|
||||||
|
<link href="~/lib/printjs/print.min.css" rel="stylesheet" />
|
||||||
<!-- DataTables CSS-->
|
<!-- DataTables CSS-->
|
||||||
<link href="~/lib/datatables/datatables.css" rel="stylesheet" />
|
<link href="~/lib/datatables/datatables.css" rel="stylesheet" />
|
||||||
<!-- Vue Js -->
|
<!-- Vue Js -->
|
||||||
@ -740,6 +740,9 @@
|
|||||||
<script src="~/assets/libs/jquery-minicolors/jquery.minicolors.min.js"></script>
|
<script src="~/assets/libs/jquery-minicolors/jquery.minicolors.min.js"></script>
|
||||||
<script src="~/assets/libs/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
|
<script src="~/assets/libs/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
|
||||||
<script src="~/assets/libs/quill/dist/quill.min.js"></script>
|
<script src="~/assets/libs/quill/dist/quill.min.js"></script>
|
||||||
|
<script src="~/lib/printjs/print.min.js"></script>
|
||||||
|
<script src="~/lib/html2canvas/html2canvas.min.js"></script>
|
||||||
|
<script src="~/lib/html2canvas/dom-to-image.min.js"></script>
|
||||||
<!-- Datatables JS-->
|
<!-- Datatables JS-->
|
||||||
<script src="~/lib/datatables/datatables.js"></script>
|
<script src="~/lib/datatables/datatables.js"></script>
|
||||||
@await RenderSectionAsync("Scripts", required: false)
|
@await RenderSectionAsync("Scripts", required: false)
|
||||||
|
|||||||
29
wwwroot/lib/PrintJs/browser.js
Normal file
29
wwwroot/lib/PrintJs/browser.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const Browser = {
|
||||||
|
// Firefox 1.0+
|
||||||
|
isFirefox: () => {
|
||||||
|
return typeof InstallTrigger !== 'undefined'
|
||||||
|
},
|
||||||
|
// Internet Explorer 6-11
|
||||||
|
isIE: () => {
|
||||||
|
return navigator.userAgent.indexOf('MSIE') !== -1 || !!document.documentMode
|
||||||
|
},
|
||||||
|
// Edge 20+
|
||||||
|
isEdge: () => {
|
||||||
|
return !Browser.isIE() && !!window.StyleMedia
|
||||||
|
},
|
||||||
|
// Chrome 1+
|
||||||
|
isChrome: (context = window) => {
|
||||||
|
return !!context.chrome
|
||||||
|
},
|
||||||
|
// At least Safari 3+: "[object HTMLElementConstructor]"
|
||||||
|
isSafari: () => {
|
||||||
|
return Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0 ||
|
||||||
|
navigator.userAgent.toLowerCase().indexOf('safari') !== -1
|
||||||
|
},
|
||||||
|
// IOS Chrome
|
||||||
|
isIOSChrome: () => {
|
||||||
|
return navigator.userAgent.toLowerCase().indexOf('crios') !== -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Browser
|
||||||
103
wwwroot/lib/PrintJs/functions.js
Normal file
103
wwwroot/lib/PrintJs/functions.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import Modal from './modal'
|
||||||
|
import Browser from './browser'
|
||||||
|
|
||||||
|
export function addWrapper (htmlData, params) {
|
||||||
|
const bodyStyle = 'font-family:' + params.font + ' !important; font-size: ' + params.font_size + ' !important; width:100%;'
|
||||||
|
return '<div style="' + bodyStyle + '">' + htmlData + '</div>'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function capitalizePrint (obj) {
|
||||||
|
return obj.charAt(0).toUpperCase() + obj.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function collectStyles (element, params) {
|
||||||
|
const win = document.defaultView || window
|
||||||
|
|
||||||
|
// String variable to hold styling for each element
|
||||||
|
let elementStyle = ''
|
||||||
|
|
||||||
|
// Loop over computed styles
|
||||||
|
const styles = win.getComputedStyle(element, '')
|
||||||
|
|
||||||
|
for (let key = 0; key < styles.length; key++) {
|
||||||
|
// Check if style should be processed
|
||||||
|
if (params.targetStyles.indexOf('*') !== -1 || params.targetStyle.indexOf(styles[key]) !== -1 || targetStylesMatch(params.targetStyles, styles[key])) {
|
||||||
|
if (styles.getPropertyValue(styles[key])) elementStyle += styles[key] + ':' + styles.getPropertyValue(styles[key]) + ';'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print friendly defaults (deprecated)
|
||||||
|
elementStyle += 'max-width: ' + params.maxWidth + 'px !important; font-size: ' + params.font_size + ' !important;'
|
||||||
|
|
||||||
|
return elementStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
function targetStylesMatch (styles, value) {
|
||||||
|
for (let i = 0; i < styles.length; i++) {
|
||||||
|
if (typeof value === 'object' && value.indexOf(styles[i]) !== -1) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addHeader (printElement, params) {
|
||||||
|
// Create the header container div
|
||||||
|
const headerContainer = document.createElement('div')
|
||||||
|
|
||||||
|
// Check if the header is text or raw html
|
||||||
|
if (isRawHTML(params.header)) {
|
||||||
|
headerContainer.innerHTML = params.header
|
||||||
|
} else {
|
||||||
|
// Create header element
|
||||||
|
const headerElement = document.createElement('h1')
|
||||||
|
|
||||||
|
// Create header text node
|
||||||
|
const headerNode = document.createTextNode(params.header)
|
||||||
|
|
||||||
|
// Build and style
|
||||||
|
headerElement.appendChild(headerNode)
|
||||||
|
headerElement.setAttribute('style', params.headerStyle)
|
||||||
|
headerContainer.appendChild(headerElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
printElement.insertBefore(headerContainer, printElement.childNodes[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanUp (params) {
|
||||||
|
// If we are showing a feedback message to user, remove it
|
||||||
|
if (params.showModal) Modal.close()
|
||||||
|
|
||||||
|
// Check for a finished loading hook function
|
||||||
|
if (params.onLoadingEnd) params.onLoadingEnd()
|
||||||
|
|
||||||
|
// If preloading pdf files, clean blob url
|
||||||
|
if (params.showModal || params.onLoadingStart) window.URL.revokeObjectURL(params.printable)
|
||||||
|
|
||||||
|
// Run onPrintDialogClose callback
|
||||||
|
let event = 'mouseover'
|
||||||
|
|
||||||
|
if (Browser.isChrome() || Browser.isFirefox()) {
|
||||||
|
// Ps.: Firefox will require an extra click in the document to fire the focus event.
|
||||||
|
event = 'focus'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handler = () => {
|
||||||
|
// Make sure the event only happens once.
|
||||||
|
window.removeEventListener(event, handler)
|
||||||
|
|
||||||
|
params.onPrintDialogClose()
|
||||||
|
|
||||||
|
// Remove iframe from the DOM
|
||||||
|
const iframe = document.getElementById(params.frameId)
|
||||||
|
|
||||||
|
if (iframe) {
|
||||||
|
iframe.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener(event, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRawHTML (raw) {
|
||||||
|
const regexHtml = new RegExp('<([A-Za-z][A-Za-z0-9]*)\\b[^>]*>(.*?)</\\1>')
|
||||||
|
return regexHtml.test(raw)
|
||||||
|
}
|
||||||
65
wwwroot/lib/PrintJs/html.js
Normal file
65
wwwroot/lib/PrintJs/html.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { collectStyles, addHeader } from './functions'
|
||||||
|
import Print from './print'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
print: (params, printFrame) => {
|
||||||
|
// Get the DOM printable element
|
||||||
|
const printElement = document.getElementById(params.printable)
|
||||||
|
|
||||||
|
// Check if the element exists
|
||||||
|
if (!printElement) {
|
||||||
|
window.console.error('Invalid HTML element id: ' + params.printable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone the target element including its children (if available)
|
||||||
|
params.printableElement = cloneElement(printElement, params)
|
||||||
|
|
||||||
|
// Add header
|
||||||
|
if (params.header) {
|
||||||
|
addHeader(params.printableElement, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print html element contents
|
||||||
|
Print.send(params, printFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cloneElement (element, params) {
|
||||||
|
// Clone the main node (if not already inside the recursion process)
|
||||||
|
const clone = element.cloneNode()
|
||||||
|
|
||||||
|
// Loop over and process the children elements / nodes (including text nodes)
|
||||||
|
const childNodesArray = Array.prototype.slice.call(element.childNodes)
|
||||||
|
for (let i = 0; i < childNodesArray.length; i++) {
|
||||||
|
// Check if we are skiping the current element
|
||||||
|
if (params.ignoreElements.indexOf(childNodesArray[i].id) !== -1) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone the child element
|
||||||
|
const clonedChild = cloneElement(childNodesArray[i], params)
|
||||||
|
|
||||||
|
// Attach the cloned child to the cloned parent node
|
||||||
|
clone.appendChild(clonedChild)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all styling for print element (for nodes of type element only)
|
||||||
|
if (params.scanStyles && element.nodeType === 1) {
|
||||||
|
clone.setAttribute('style', collectStyles(element, params))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the element needs any state processing (copy user input data)
|
||||||
|
switch (element.tagName) {
|
||||||
|
case 'SELECT':
|
||||||
|
// Copy the current selection value to its clone
|
||||||
|
clone.value = element.value
|
||||||
|
break
|
||||||
|
case 'CANVAS':
|
||||||
|
// Copy the canvas content to its clone
|
||||||
|
clone.getContext('2d').drawImage(element, 0, 0)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return clone
|
||||||
|
}
|
||||||
48
wwwroot/lib/PrintJs/image.js
Normal file
48
wwwroot/lib/PrintJs/image.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { addHeader } from './functions'
|
||||||
|
import Print from './print'
|
||||||
|
import Browser from './browser'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
print: (params, printFrame) => {
|
||||||
|
// Check if we are printing one image or multiple images
|
||||||
|
if (params.printable.constructor !== Array) {
|
||||||
|
// Create array with one image
|
||||||
|
params.printable = [params.printable]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create printable element (container)
|
||||||
|
params.printableElement = document.createElement('div')
|
||||||
|
|
||||||
|
// Create all image elements and append them to the printable container
|
||||||
|
params.printable.forEach(src => {
|
||||||
|
// Create the image element
|
||||||
|
const img = document.createElement('img')
|
||||||
|
img.setAttribute('style', params.imageStyle)
|
||||||
|
|
||||||
|
// Set image src with the file url
|
||||||
|
img.src = src
|
||||||
|
|
||||||
|
// The following block is for Firefox, which for some reason requires the image's src to be fully qualified in
|
||||||
|
// order to print it
|
||||||
|
if (Browser.isFirefox()) {
|
||||||
|
const fullyQualifiedSrc = img.src
|
||||||
|
img.src = fullyQualifiedSrc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the image wrapper
|
||||||
|
const imageWrapper = document.createElement('div')
|
||||||
|
|
||||||
|
// Append image to the wrapper element
|
||||||
|
imageWrapper.appendChild(img)
|
||||||
|
|
||||||
|
// Append wrapper to the printable element
|
||||||
|
params.printableElement.appendChild(imageWrapper)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check if we are adding a print header
|
||||||
|
if (params.header) addHeader(params.printableElement, params)
|
||||||
|
|
||||||
|
// Print image
|
||||||
|
Print.send(params, printFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
168
wwwroot/lib/PrintJs/init.js
Normal file
168
wwwroot/lib/PrintJs/init.js
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
import Browser from './browser'
|
||||||
|
import Modal from './modal'
|
||||||
|
import Pdf from './pdf'
|
||||||
|
import Html from './html'
|
||||||
|
import RawHtml from './raw-html'
|
||||||
|
import Image from './image'
|
||||||
|
import Json from './json'
|
||||||
|
|
||||||
|
const printTypes = ['pdf', 'html', 'image', 'json', 'raw-html']
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init () {
|
||||||
|
const params = {
|
||||||
|
printable: null,
|
||||||
|
fallbackPrintable: null,
|
||||||
|
type: 'pdf',
|
||||||
|
header: null,
|
||||||
|
headerStyle: 'font-weight: 300;',
|
||||||
|
maxWidth: 800,
|
||||||
|
properties: null,
|
||||||
|
gridHeaderStyle: 'font-weight: bold; padding: 5px; border: 1px solid #dddddd;',
|
||||||
|
gridStyle: 'border: 1px solid lightgray; margin-bottom: -1px;',
|
||||||
|
showModal: false,
|
||||||
|
onError: (error) => { throw error },
|
||||||
|
onLoadingStart: null,
|
||||||
|
onLoadingEnd: null,
|
||||||
|
onPrintDialogClose: () => {},
|
||||||
|
onIncompatibleBrowser: () => {},
|
||||||
|
modalMessage: 'Retrieving Document...',
|
||||||
|
frameId: 'printJS',
|
||||||
|
printableElement: null,
|
||||||
|
documentTitle: 'Document',
|
||||||
|
targetStyle: ['clear', 'display', 'width', 'min-width', 'height', 'min-height', 'max-height'],
|
||||||
|
targetStyles: ['border', 'box', 'break', 'text-decoration'],
|
||||||
|
ignoreElements: [],
|
||||||
|
repeatTableHeader: true,
|
||||||
|
css: null,
|
||||||
|
style: null,
|
||||||
|
scanStyles: true,
|
||||||
|
base64: false,
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
|
onPdfOpen: null,
|
||||||
|
font: 'TimesNewRoman',
|
||||||
|
font_size: '12pt',
|
||||||
|
honorMarginPadding: true,
|
||||||
|
honorColor: false,
|
||||||
|
imageStyle: 'max-width: 100%;'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a printable document or object was supplied
|
||||||
|
const args = arguments[0]
|
||||||
|
if (args === undefined) {
|
||||||
|
throw new Error('printJS expects at least 1 attribute.')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process parameters
|
||||||
|
switch (typeof args) {
|
||||||
|
case 'string':
|
||||||
|
params.printable = encodeURI(args)
|
||||||
|
params.fallbackPrintable = params.printable
|
||||||
|
params.type = arguments[1] || params.type
|
||||||
|
break
|
||||||
|
case 'object':
|
||||||
|
params.printable = args.printable
|
||||||
|
params.fallbackPrintable = typeof args.fallbackPrintable !== 'undefined' ? args.fallbackPrintable : params.printable
|
||||||
|
params.fallbackPrintable = params.base64 ? `data:application/pdf;base64,${params.fallbackPrintable}` : params.fallbackPrintable
|
||||||
|
for (var k in params) {
|
||||||
|
if (k === 'printable' || k === 'fallbackPrintable') continue
|
||||||
|
|
||||||
|
params[k] = typeof args[k] !== 'undefined' ? args[k] : params[k]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error('Unexpected argument type! Expected "string" or "object", got ' + typeof args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate printable
|
||||||
|
if (!params.printable) throw new Error('Missing printable information.')
|
||||||
|
|
||||||
|
// Validate type
|
||||||
|
if (!params.type || typeof params.type !== 'string' || printTypes.indexOf(params.type.toLowerCase()) === -1) {
|
||||||
|
throw new Error('Invalid print type. Available types are: pdf, html, image and json.')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we are showing a feedback message to the user (useful for large files)
|
||||||
|
if (params.showModal) Modal.show(params)
|
||||||
|
|
||||||
|
// Check for a print start hook function
|
||||||
|
if (params.onLoadingStart) params.onLoadingStart()
|
||||||
|
|
||||||
|
// To prevent duplication and issues, remove any used printFrame from the DOM
|
||||||
|
const usedFrame = document.getElementById(params.frameId)
|
||||||
|
|
||||||
|
if (usedFrame) usedFrame.parentNode.removeChild(usedFrame)
|
||||||
|
|
||||||
|
// Create a new iframe for the print job
|
||||||
|
const printFrame = document.createElement('iframe')
|
||||||
|
|
||||||
|
if (Browser.isFirefox()) {
|
||||||
|
// Set the iframe to be is visible on the page (guaranteed by fixed position) but hidden using opacity 0, because
|
||||||
|
// this works in Firefox. The height needs to be sufficient for some part of the document other than the PDF
|
||||||
|
// viewer's toolbar to be visible in the page
|
||||||
|
printFrame.setAttribute('style', 'width: 1px; height: 100px; position: fixed; left: 0; top: 0; opacity: 0; border-width: 0; margin: 0; padding: 0')
|
||||||
|
} else {
|
||||||
|
// Hide the iframe in other browsers
|
||||||
|
printFrame.setAttribute('style', 'visibility: hidden; height: 0; width: 0; position: absolute; border: 0')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set iframe element id
|
||||||
|
printFrame.setAttribute('id', params.frameId)
|
||||||
|
|
||||||
|
// For non pdf printing, pass an html document string to srcdoc (force onload callback)
|
||||||
|
if (params.type !== 'pdf') {
|
||||||
|
printFrame.srcdoc = '<html><head><title>' + params.documentTitle + '</title>'
|
||||||
|
|
||||||
|
// Attach css files
|
||||||
|
if (params.css) {
|
||||||
|
// Add support for single file
|
||||||
|
if (!Array.isArray(params.css)) params.css = [params.css]
|
||||||
|
|
||||||
|
// Create link tags for each css file
|
||||||
|
params.css.forEach(file => {
|
||||||
|
printFrame.srcdoc += '<link rel="stylesheet" href="' + file + '">'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
printFrame.srcdoc += '</head><body></body></html>'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check printable type
|
||||||
|
switch (params.type) {
|
||||||
|
case 'pdf':
|
||||||
|
// Check browser support for pdf and if not supported we will just open the pdf file instead
|
||||||
|
if (Browser.isIE()) {
|
||||||
|
try {
|
||||||
|
console.info('Print.js doesn\'t support PDF printing in Internet Explorer.')
|
||||||
|
const win = window.open(params.fallbackPrintable, '_blank')
|
||||||
|
win.focus()
|
||||||
|
params.onIncompatibleBrowser()
|
||||||
|
} catch (error) {
|
||||||
|
params.onError(error)
|
||||||
|
} finally {
|
||||||
|
// Make sure there is no loading modal opened
|
||||||
|
if (params.showModal) Modal.close()
|
||||||
|
if (params.onLoadingEnd) params.onLoadingEnd()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Pdf.print(params, printFrame)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'image':
|
||||||
|
Image.print(params, printFrame)
|
||||||
|
break
|
||||||
|
case 'html':
|
||||||
|
Html.print(params, printFrame)
|
||||||
|
break
|
||||||
|
case 'raw-html':
|
||||||
|
RawHtml.print(params, printFrame)
|
||||||
|
break
|
||||||
|
case 'json':
|
||||||
|
Json.print(params, printFrame)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
109
wwwroot/lib/PrintJs/json.js
Normal file
109
wwwroot/lib/PrintJs/json.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { capitalizePrint, addHeader } from './functions'
|
||||||
|
import Print from './print'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
print: (params, printFrame) => {
|
||||||
|
// Check if we received proper data
|
||||||
|
if (typeof params.printable !== 'object') {
|
||||||
|
throw new Error('Invalid javascript data object (JSON).')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate repeatTableHeader
|
||||||
|
if (typeof params.repeatTableHeader !== 'boolean') {
|
||||||
|
throw new Error('Invalid value for repeatTableHeader attribute (JSON).')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate properties
|
||||||
|
if (!params.properties || !Array.isArray(params.properties)) {
|
||||||
|
throw new Error('Invalid properties array for your JSON data.')
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will format the property objects to keep the JSON api compatible with older releases
|
||||||
|
params.properties = params.properties.map(property => {
|
||||||
|
return {
|
||||||
|
field: typeof property === 'object' ? property.field : property,
|
||||||
|
displayName: typeof property === 'object' ? property.displayName : property,
|
||||||
|
columnSize: typeof property === 'object' && property.columnSize ? property.columnSize + ';' : 100 / params.properties.length + '%;'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a print container element
|
||||||
|
params.printableElement = document.createElement('div')
|
||||||
|
|
||||||
|
// Check if we are adding a print header
|
||||||
|
if (params.header) {
|
||||||
|
addHeader(params.printableElement, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the printable html data
|
||||||
|
params.printableElement.innerHTML += jsonToHTML(params)
|
||||||
|
|
||||||
|
// Print the json data
|
||||||
|
Print.send(params, printFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function jsonToHTML (params) {
|
||||||
|
// Get the row and column data
|
||||||
|
const data = params.printable
|
||||||
|
const properties = params.properties
|
||||||
|
|
||||||
|
// Create a html table
|
||||||
|
let htmlData = '<table style="border-collapse: collapse; width: 100%;">'
|
||||||
|
|
||||||
|
// Check if the header should be repeated
|
||||||
|
if (params.repeatTableHeader) {
|
||||||
|
htmlData += '<thead>'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the table header row
|
||||||
|
htmlData += '<tr>'
|
||||||
|
|
||||||
|
// Add the table header columns
|
||||||
|
for (let a = 0; a < properties.length; a++) {
|
||||||
|
htmlData += '<th style="width:' + properties[a].columnSize + ';' + params.gridHeaderStyle + '">' + capitalizePrint(properties[a].displayName) + '</th>'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the closing tag for the table header row
|
||||||
|
htmlData += '</tr>'
|
||||||
|
|
||||||
|
// If the table header is marked as repeated, add the closing tag
|
||||||
|
if (params.repeatTableHeader) {
|
||||||
|
htmlData += '</thead>'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the table body
|
||||||
|
htmlData += '<tbody>'
|
||||||
|
|
||||||
|
// Add the table data rows
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
// Add the row starting tag
|
||||||
|
htmlData += '<tr>'
|
||||||
|
|
||||||
|
// Print selected properties only
|
||||||
|
for (let n = 0; n < properties.length; n++) {
|
||||||
|
let stringData = data[i]
|
||||||
|
|
||||||
|
// Support nested objects
|
||||||
|
const property = properties[n].field.split('.')
|
||||||
|
if (property.length > 1) {
|
||||||
|
for (let p = 0; p < property.length; p++) {
|
||||||
|
stringData = stringData[property[p]]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stringData = stringData[properties[n].field]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the row contents and styles
|
||||||
|
htmlData += '<td style="width:' + properties[n].columnSize + params.gridStyle + '">' + stringData + '</td>'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the row closing tag
|
||||||
|
htmlData += '</tr>'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the table and body closing tags
|
||||||
|
htmlData += '</tbody></table>'
|
||||||
|
|
||||||
|
return htmlData
|
||||||
|
}
|
||||||
62
wwwroot/lib/PrintJs/modal.js
Normal file
62
wwwroot/lib/PrintJs/modal.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
const Modal = {
|
||||||
|
show (params) {
|
||||||
|
// Build modal
|
||||||
|
const modalStyle = 'font-family:sans-serif; ' +
|
||||||
|
'display:table; ' +
|
||||||
|
'text-align:center; ' +
|
||||||
|
'font-weight:300; ' +
|
||||||
|
'font-size:30px; ' +
|
||||||
|
'left:0; top:0;' +
|
||||||
|
'position:fixed; ' +
|
||||||
|
'z-index: 9990;' +
|
||||||
|
'color: #0460B5; ' +
|
||||||
|
'width: 100%; ' +
|
||||||
|
'height: 100%; ' +
|
||||||
|
'background-color:rgba(255,255,255,.9);' +
|
||||||
|
'transition: opacity .3s ease;'
|
||||||
|
|
||||||
|
// Create wrapper
|
||||||
|
const printModal = document.createElement('div')
|
||||||
|
printModal.setAttribute('style', modalStyle)
|
||||||
|
printModal.setAttribute('id', 'printJS-Modal')
|
||||||
|
|
||||||
|
// Create content div
|
||||||
|
const contentDiv = document.createElement('div')
|
||||||
|
contentDiv.setAttribute('style', 'display:table-cell; vertical-align:middle; padding-bottom:100px;')
|
||||||
|
|
||||||
|
// Add close button (requires print.css)
|
||||||
|
const closeButton = document.createElement('div')
|
||||||
|
closeButton.setAttribute('class', 'printClose')
|
||||||
|
closeButton.setAttribute('id', 'printClose')
|
||||||
|
contentDiv.appendChild(closeButton)
|
||||||
|
|
||||||
|
// Add spinner (requires print.css)
|
||||||
|
const spinner = document.createElement('span')
|
||||||
|
spinner.setAttribute('class', 'printSpinner')
|
||||||
|
contentDiv.appendChild(spinner)
|
||||||
|
|
||||||
|
// Add message
|
||||||
|
const messageNode = document.createTextNode(params.modalMessage)
|
||||||
|
contentDiv.appendChild(messageNode)
|
||||||
|
|
||||||
|
// Add contentDiv to printModal
|
||||||
|
printModal.appendChild(contentDiv)
|
||||||
|
|
||||||
|
// Append print modal element to document body
|
||||||
|
document.getElementsByTagName('body')[0].appendChild(printModal)
|
||||||
|
|
||||||
|
// Add event listener to close button
|
||||||
|
document.getElementById('printClose').addEventListener('click', function () {
|
||||||
|
Modal.close()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
close () {
|
||||||
|
const printModal = document.getElementById('printJS-Modal')
|
||||||
|
|
||||||
|
if (printModal) {
|
||||||
|
printModal.parentNode.removeChild(printModal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Modal
|
||||||
57
wwwroot/lib/PrintJs/pdf.js
Normal file
57
wwwroot/lib/PrintJs/pdf.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import Print from './print'
|
||||||
|
import { cleanUp } from './functions'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
print: (params, printFrame) => {
|
||||||
|
// Check if we have base64 data
|
||||||
|
if (params.base64) {
|
||||||
|
const bytesArray = Uint8Array.from(atob(params.printable), c => c.charCodeAt(0))
|
||||||
|
createBlobAndPrint(params, printFrame, bytesArray)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format pdf url
|
||||||
|
params.printable = /^(blob|http|\/\/)/i.test(params.printable)
|
||||||
|
? params.printable
|
||||||
|
: window.location.origin + (params.printable.charAt(0) !== '/' ? '/' + params.printable : params.printable)
|
||||||
|
|
||||||
|
// Get the file through a http request (Preload)
|
||||||
|
const req = new window.XMLHttpRequest()
|
||||||
|
req.responseType = 'arraybuffer'
|
||||||
|
|
||||||
|
req.addEventListener('error', () => {
|
||||||
|
cleanUp(params)
|
||||||
|
params.onError(req.statusText)
|
||||||
|
|
||||||
|
// Since we don't have a pdf document available, we will stop the print job
|
||||||
|
})
|
||||||
|
|
||||||
|
req.addEventListener('load', () => {
|
||||||
|
// Check for errors
|
||||||
|
if ([200, 201].indexOf(req.status) === -1) {
|
||||||
|
cleanUp(params)
|
||||||
|
params.onError(req.statusText)
|
||||||
|
|
||||||
|
// Since we don't have a pdf document available, we will stop the print job
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print requested document
|
||||||
|
createBlobAndPrint(params, printFrame, req.response)
|
||||||
|
})
|
||||||
|
|
||||||
|
req.open('GET', params.printable, true)
|
||||||
|
req.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createBlobAndPrint (params, printFrame, data) {
|
||||||
|
// Pass response or base64 data to a blob and create a local object url
|
||||||
|
let localPdf = new window.Blob([data], { type: 'application/pdf' })
|
||||||
|
localPdf = window.URL.createObjectURL(localPdf)
|
||||||
|
|
||||||
|
// Set iframe src with pdf document url
|
||||||
|
printFrame.setAttribute('src', localPdf)
|
||||||
|
|
||||||
|
Print.send(params, printFrame)
|
||||||
|
}
|
||||||
102
wwwroot/lib/PrintJs/print.js
Normal file
102
wwwroot/lib/PrintJs/print.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import Browser from './browser'
|
||||||
|
import { cleanUp } from './functions'
|
||||||
|
|
||||||
|
const Print = {
|
||||||
|
send: (params, printFrame) => {
|
||||||
|
// Append iframe element to document body
|
||||||
|
document.getElementsByTagName('body')[0].appendChild(printFrame)
|
||||||
|
|
||||||
|
// Get iframe element
|
||||||
|
const iframeElement = document.getElementById(params.frameId)
|
||||||
|
|
||||||
|
// Wait for iframe to load all content
|
||||||
|
iframeElement.onload = () => {
|
||||||
|
if (params.type === 'pdf') {
|
||||||
|
// Add a delay for Firefox. In my tests, 1000ms was sufficient but 100ms was not
|
||||||
|
if (Browser.isFirefox()) {
|
||||||
|
setTimeout(() => performPrint(iframeElement, params), 1000)
|
||||||
|
} else {
|
||||||
|
performPrint(iframeElement, params)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get iframe element document
|
||||||
|
let printDocument = (iframeElement.contentWindow || iframeElement.contentDocument)
|
||||||
|
if (printDocument.document) printDocument = printDocument.document
|
||||||
|
|
||||||
|
// Append printable element to the iframe body
|
||||||
|
printDocument.body.appendChild(params.printableElement)
|
||||||
|
|
||||||
|
// Add custom style
|
||||||
|
if (params.type !== 'pdf' && params.style) {
|
||||||
|
// Create style element
|
||||||
|
const style = document.createElement('style')
|
||||||
|
style.innerHTML = params.style
|
||||||
|
|
||||||
|
// Append style element to iframe's head
|
||||||
|
printDocument.head.appendChild(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If printing images, wait for them to load inside the iframe
|
||||||
|
const images = printDocument.getElementsByTagName('img')
|
||||||
|
|
||||||
|
if (images.length > 0) {
|
||||||
|
loadIframeImages(Array.from(images)).then(() => performPrint(iframeElement, params))
|
||||||
|
} else {
|
||||||
|
performPrint(iframeElement, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function performPrint (iframeElement, params) {
|
||||||
|
try {
|
||||||
|
iframeElement.focus()
|
||||||
|
|
||||||
|
// If Edge or IE, try catch with execCommand
|
||||||
|
if (Browser.isEdge() || Browser.isIE()) {
|
||||||
|
try {
|
||||||
|
iframeElement.contentWindow.document.execCommand('print', false, null)
|
||||||
|
} catch (e) {
|
||||||
|
iframeElement.contentWindow.print()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Other browsers
|
||||||
|
iframeElement.contentWindow.print()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
params.onError(error)
|
||||||
|
} finally {
|
||||||
|
if (Browser.isFirefox()) {
|
||||||
|
// Move the iframe element off-screen and make it invisible
|
||||||
|
iframeElement.style.visibility = 'hidden'
|
||||||
|
iframeElement.style.left = '-1px'
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanUp(params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadIframeImages (images) {
|
||||||
|
const promises = images.map(image => {
|
||||||
|
if (image.src && image.src !== window.location.href) {
|
||||||
|
return loadIframeImage(image)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return Promise.all(promises)
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadIframeImage (image) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const pollImage = () => {
|
||||||
|
!image || typeof image.naturalWidth === 'undefined' || image.naturalWidth === 0 || !image.complete
|
||||||
|
? setTimeout(pollImage, 500)
|
||||||
|
: resolve()
|
||||||
|
}
|
||||||
|
pollImage()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Print
|
||||||
1
wwwroot/lib/PrintJs/print.min.css
vendored
Normal file
1
wwwroot/lib/PrintJs/print.min.css
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.printModal{font-family:sans-serif;display:flex;text-align:center;font-weight:300;font-size:30px;left:0;top:0;position:absolute;color:#045fb4;width:100%;height:100%;background-color:hsla(0,0%,100%,.9)}.printClose{position:absolute;right:10px;top:10px}.printClose:before{content:"\00D7";font-family:Helvetica Neue,sans-serif;font-weight:100;line-height:1px;padding-top:.5em;display:block;font-size:2em;text-indent:1px;overflow:hidden;height:1.25em;width:1.25em;text-align:center;cursor:pointer}.printSpinner{margin-top:3px;margin-left:-40px;position:absolute;display:inline-block;width:25px;height:25px;border:2px solid #045fb4;border-radius:50%;animation:spin .75s linear infinite}.printSpinner:after,.printSpinner:before{left:-2px;top:-2px;display:none;position:absolute;content:"";width:inherit;height:inherit;border:inherit;border-radius:inherit}.printSpinner,.printSpinner:after,.printSpinner:before{display:inline-block;border-color:#045fb4 transparent transparent;animation-duration:1.2s}.printSpinner:before{transform:rotate(120deg)}.printSpinner:after{transform:rotate(240deg)}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}
|
||||||
1
wwwroot/lib/PrintJs/print.min.js
vendored
Normal file
1
wwwroot/lib/PrintJs/print.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
wwwroot/lib/PrintJs/raw-html.js
Normal file
15
wwwroot/lib/PrintJs/raw-html.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Print from './print'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
print: (params, printFrame) => {
|
||||||
|
// Create printable element (container)
|
||||||
|
params.printableElement = document.createElement('div')
|
||||||
|
params.printableElement.setAttribute('style', 'width:100%')
|
||||||
|
|
||||||
|
// Set our raw html as the printable element inner html content
|
||||||
|
params.printableElement.innerHTML = params.printable
|
||||||
|
|
||||||
|
// Print html contents
|
||||||
|
Print.send(params, printFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
2
wwwroot/lib/html2canvas/dom-to-image.min.js
vendored
Normal file
2
wwwroot/lib/html2canvas/dom-to-image.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7830
wwwroot/lib/html2canvas/html2canvas.js
Normal file
7830
wwwroot/lib/html2canvas/html2canvas.js
Normal file
File diff suppressed because one or more lines are too long
20
wwwroot/lib/html2canvas/html2canvas.min.js
vendored
Normal file
20
wwwroot/lib/html2canvas/html2canvas.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user