How can I add header and footer in PDF page using phantom-html2pdf - express

I am unable to find way of adding header and footer in pdf page using phantom-html2pdf with Express and Coffeescript. My code is as follows can you please review it and tell me what I am missing:
pdf = require('phantom-html2pdf')
exports.test_pdf = (req, res) ->
paperSize = {
format: 'A4',
margin: "1cm",
orientation: 'portrait'
header: {
height: "200cm",
contents: '<h1>This is the Header</h1>'
},
}
htmls = '<html><body><h2>PDF CONTENT</h2></body></html>';
options = {
html: htmls,
css: "./public/stylesheets/foundation.css",
paperSize : page.paperSize
}
pdf.convert options, (err, result) ->
if !err
result.toBuffer()
# Using a readable stream
result.toStream()
# Using the temp file path */
result.getTmpPath()
# Using the file writer and callback */
result.toFile("./html/pdf_file.pdf")
else
res.render('index', { title: 'Social Media'})
I have already done some research that to add header and footer, I need to export a paperSize object from a runnings file. https://github.com/bauhausjs/phantom-html2pdf/issues/30
but adding that too could not help me or I am not adding it correctly.
A little help will be much appreciated. Thanks in advance.

module.exports will resolve your problem. After creating the page object for header & footer. you will export the object with module.export.
Here is the sample code
module.exports = {
header: {
height: '3cm', contents: function (page) {
return '<header class="pdf-header" style=" overflow:hidden; font-size: 10px; padding: 10px; margin: 0 -15px; color: #fff; background: none repeat scroll 0 0 #00396f;"><img style="float: left;" alt="" src="../images/logo.jpg"><p> XYZ </p></header>'
}
},
footer: {
height: '3cm', contents: function (page) {
return '<footer class="pdf-footer" style="font-size: 10px; font-weight: bold; color: #000;><p style="margin: 0">Powered by XYZ</p></footer>'
}
},
}
Note: You need to create runing file and copy & paste given code in it.

Related

Flickity Slider Animation and Gsap

The slider I am building have the active slider bigger than the others. I managed to make it work without the animation with flkty.reposition(). However, I am trying now to add the animation where the next slide grows in and the active decrease out. For The animation I am using GSAP.
The issue I am facing is to overwrite the left property with gsap so that it continuous animate. As of now, the left property (controlled by Flickity) does not take into account the final size (controlled by GSAP) of the selected slide.
https://codepen.io/stefanomonteiro/pen/VwzwjLw?editors=0010
As the left property of each slide is controlled by Flickity, we could use margin-left with a minus value as an alternative property to pull the selected slide to the left. I know margin is not a good property to animate but it works in this case without digging too deep into the Flickity core.
Here is the GSAP code:
gsap.to(slides, {
duration: 1,
width: "220px",
height: "336px"
});
gsap.to(selectedSlide, {
duration: 1,
marginLeft: "-248px", // the empty space calculated by newWidth - oldWidth
width: "468px",
height: "630px",
onComplete: () => {
// once all animations have been settled, we reset the margin
gsap.set(selectedSlide, { marginLeft: "" });
// and tell Flickity to update
flkty.resize();
flkty.reposition();
}
});
And the snippets
const animate = () => {
const flkty = Flickity.data(".carousel");
const selectedSlide = flkty.selectedElement;
const slides = flkty.getCellElements();
// remove the selected slides
slides.splice(flkty.selectedIndex, 1);
gsap.to(slides, {
duration: 1,
width: "220px",
height: "336px"
});
gsap.to(selectedSlide, {
duration: 1,
marginLeft: "-248px", // the empty space calculated by newWidth - oldWidth
width: "468px",
height: "630px",
onComplete: () => {
// once all animations have been settled, we reset the margin
gsap.set(selectedSlide, {
marginLeft: ""
});
// and tell Flickity to update
flkty.resize();
flkty.reposition();
}
});
};
new Flickity(".carousel", {
cellAlign: "right",
wrapAround: true,
percentPosition: false,
on: {
ready: () => animate()
}
});
const nextButton = document.querySelector(".flickity-button.next");
nextButton.addEventListener("click", () => animate());
/* external css: flickity.css */
* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
.carousel {
background: #EEE;
}
.carousel-cell {
width: 220px;
height: 336px;
margin-right: 20px;
background: #8C8;
border-radius: 5px;
counter-increment: carousel-cell;
}
.carousel-cell.is-selected {
width: 468px;
height: 630px;
z-index: 1;
}
/* cell number */
.carousel-cell:before {
display: block;
text-align: center;
content: counter(carousel-cell);
line-height: 200px;
font-size: 80px;
color: white;
}
<link href="https://npmcdn.com/flickity#2/dist/flickity.css" rel="stylesheet" />
<script src="https://unpkg.co/gsap#3/dist/gsap.min.js"></script>
<script src="https://npmcdn.com/flickity#2/dist/flickity.pkgd.js"></script>
<h1>Flickity - wrapAround</h1>
<!-- Flickity HTML init -->
<div class="carousel">
<div class="carousel-cell"></div>
<div class="carousel-cell"></div>
<div class="carousel-cell"></div>
<div class="carousel-cell"></div>
<div class="carousel-cell"></div>
</div>
And the Codepen
You can also notice that we have to wait until the animation is finished until we perform the next click, otherwise, it would mess up the whole process. This is predictable. Hence, I personally will try not to manipulate this Flickity slider for this kind of animation. Just want to give you a solution, anyway.

Vue-multiselect - How to insert html code in placeholder?

Im trying insert span in placeholder, for color change. But placeholder returns only string, ow to fix that?
computed: {
customPlaceholder () {
let numLength = this.options.length;
return this.placeholder + "<span>"+numLength+"</span>"
}
}
I think you're trying to add a custom placeholder inside an input field.
to do this you need some mix of css and html.
new Vue({
el: '#editor',
data: {
input: '',
input2: 'some text'
},
computed: {
placeholderText: function () {
return `${this.input2} <span>*</span>`
}
},
methods: {
update: _.debounce(function (e) {
this.input = e.target.value
}, 300)
}
})
#editor div {
display: inline-block;
}
.input-placeholder {
position: relative;
}
.input-placeholder input {
padding: 10px;
font-size: 25px;
}
.input-placeholder input:valid + .placeholder {
display: none;
}
.placeholder {
position: absolute;
pointer-events: none;
top: 0;
bottom: 0;
height: 25px;
font-size: 25px;
left: 10px;
margin: auto;
color: #ccc;
}
.placeholder span {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/lodash#4.16.0"></script>
<div id="editor">
<div class="input-placeholder">
<input type="text" #input="update">
<div class="placeholder" v-if="!input" v-html="placeholderText">
Email <span>*</span>
</div>
</div>
</div>
I have created this jsfiddle for my solution.
you can use css placeholder selector
input::-webkit-input-placeholder { /* Edge */
color: green!important;
}
input:-ms-input-placeholder { /* Internet Explorer 10-11 */
color: green!important;
}
input::placeholder {
color: green!important;
}
Try it, then try to remove the !important.
But information is missing. You want to change the color dynamically or not? or you want to have different colours into the same placeholder?

Nuxt.js: add custom loading component

I have been trying to add loading spinner to my NuxtJS project using the loading configuration: https://nuxtjs.org/api/configuration-loading.
However, the documentation is hard to understand, I have no idea how to apply it to my project. Did any have any ideas of how to add loading spinner using that?
Thanks in advance,
So you can create a custom loading:
We can create our custom component in components/loading.vue:
<template lang="html">
<div class="loading-page" v-if="loading">
<p>Loading...</p>
</div>
</template>
<script>
export default {
data: () => ({
loading: false
}),
methods: {
start () {
this.loading = true
},
finish () {
this.loading = false
}
}
}
</script>
<style scoped>
.loading-page {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.8);
text-align: center;
padding-top: 200px;
font-size: 30px;
font-family: sans-serif;
}
</style>
Then, we update our nuxt.config.js to tell Nuxt.js to use our component:
export default {
loading: '~/components/loading.vue'
}
And then in your compenent you can show and hide with the:
this.$nuxt.$loading.start() to start the loading bar and this.$nuxt.$loading.finish() to finish it.
You can put this in the callbacks of a request.
probably it's about z-index value

print vueJS component or convert to pdf

I have a vueJS component that I want to print. However, when I use the standard print dialog I lose all the CSS and basically only have plain text.
I have also tried Printd.
My code is along the lines of:
mounted () {
this.cssText = `
.a4-paper {
height: 29cm;
width: 14cm;
}
h4, h3, h2, h1 {
text-align: center;
width: 100%;
}
label.underline {
border-bottom: solid black 1px;
height: 0.3cm;
width: 100%;
}`;
this.d = new Printd()
},
methods: {
show(event: Event) {
this.event = event;
this.visible = true;
},
print() {
this.d.print(this.$el, this.cssText)
}
}
However, the result looks nothing like how the component is rendered. I haven't been able to find a solution for this. Can somebody help me?
The problem exists because printd creates a new Document for printing, therefore styles aren't carried down into the child component, which you are referencing with this.$el
The workaround which I use is to take all of the style elements from the head of the current document and append them to the document that printd creates. Change your print method to the following;
print() {
const d = new Printd()
d.print(this.$el, this.cssText, (win, doc, node, launchPrint) => {
// Get style elements
const styles = [].slice.call(document.getElementsByTagName('style'))
// append them to the the new document head element
styles.forEach(styleElement => doc.head.appendChild(styleElement.cloneNode(true)))
launchPrint(win)
})
},

How to make blueimp gallery textFactory work with an iframe

I have followed the documentation here:
https://github.com/blueimp/Gallery
First loaded assets separatedly.
Then created blueimp-gallery-textFactory.js and loaded after core file, before video file, with the following contents:
blueimp.Gallery.prototype.textFactory = function (obj, callback) {
var $element = $('<div>')
.addClass('text-content')
.attr('title', obj.title);
var iframe=$('<iframe>', {
src: obj.href,
frameborder: 0,
height: '100%',
width: '100%',
scrolling: 'no'
});
$element.html(iframe);
callback({
type: 'load',
target: $element[0]
});
return $element[0];
};
So what changes from original example is that I'm not making an ajax request and then running callback, but instead creating an iframe and then running callback.
And also added the aditional css style to the stylesheet:
.blueimp-gallery > .slides > .slide > .text-content {
overflow: auto;
margin: 60px auto;
padding: 0 60px;
max-width: 920px;
text-align: left;
}
The issue I ran into is that the onLoad/complete event would never fire and the slideLoading class will be always on top of the iframe.
I started to look into the videoFactory plugin and youtube one to see what could be wrong.
So I've stole some CSS from the video plugin:
.blueimp-gallery > .slides > .slide > .text-content > iframe {
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: 100%;
border: none;
}
.blueimp-gallery > .slides > .slide > .text-content > iframe {
top: 0;
}
This (helps) but did not solve the problem.
What did solve the problem was taken from blueimp-gallery-video.js and that is running the callback with this setTimeout function.
blueimp.Gallery.prototype.textFactory = function (obj, callback) {
var $element = $('<div>')
.addClass('text-content')
.attr('title', obj.title);
var iframe=$('<iframe>', {
src: obj.href,
frameborder: 0,
height: '100%',
width: '100%',
scrolling: 'no'
});
$element.html(iframe);
// callback({
// type: 'load',
// target: $element[0]
// });
this.setTimeout(callback, [
{
type: 'load',
target: $element[0]
}
]);
return $element[0];
};
This time the problem got solved. I guess with the $.get ajax call from original example there was no need to call setTimeout but with the iframe it was required.