flying saucer page number + page count - flying-saucer

I'm trying to configure a nice footer on a pdf document I'm generating using Flying Saucer.
But I'm having problems getting the page number and page count in a nice position.
Consider this bit of css:
div#page-footer {
position : running(footer);
// .. more styling .. //
}
div.page-number:before {
content: counter(page);
}
Using this bit of html will not give me a page number:
<div id="page-footer">
<div class="page-number"></div>
</div>
The only way I manage to get a page number if I move the class a level up.
<div id="page-footer" class="page-number">
</div>
But this does not allow me to add additional content in the footer or makes it really difficult to apply styling. I could add a separate footer just for the page number, but it would be quite hard to get the position just right.
Is there a way to get page number + page count in a footer that also contains other elements and styling?
Extra notes:
I simplified the footer a bit, in the original there is more in there, but even this simple example it is giving problems.
using span or div for the element does not make a difference.

You should use the id instead of the class to identify the div containing the page number.
This will work:
div#page-number:before {
content: counter(page);
}
<div id="page-footer">
<div id="page-number"></div>
</div>

Related

First page blank in vuehtml2pdf

vuehtml2pdf generating pdf but first page is blank only when my content is too much, it does break to second page but first page is left blank.
<client-only>
<vue-html2pdf
ref="html2pdf"
pdf-format="a4"
:show-layout="false"
:preview-modal="false"
:enable-download="false"
:manual-pagination="false"
#progress="onProgress($event)"
:pdf-quality="2"
:paginate-elements-by-height="10"
:filename="user.fullName + 'resume'"
#beforeDownload="beforeDownload($event)"
:html-to-pdf-options="{
filename: user.fullName + ' Resume',
jsPDF: {
format: 'a4',
unit: 'mm'
},
html2canvas: {
useCORS: true,
dpi: 192,
letterRendering: true,
scale: 4, // resolution
},
}">
<section slot="pdf-content">
<section>
<component :is="resumeComponent"></component>
</section>
</section>
</vue-html2pdf>
this is my code and my component is dynamic and it might have many pages of data or maybe one page. but when the data is too much an empty page is generated at first.
You have a very low value of paginate-elements-by-height
That number is in pixels.
Try 1000, instead of 10.
When that value is very low, it creates the behaviour you see:
It seems to eject one blank page, and then put one item on each subsequent page, with no limit on the size of that item (i.e. it doesn't break items).
Most likely its algorithm is:
For each item:
Does that item fit onto the current page without exceeding the paginate-elements-by-height?
If so, add it.
If not, eject page, and add it to the next page, irrespective of whether it is within the limit of paginate-elements-by-height.
(I suppose this is necessary, because if it applied that limit on the next page, then an outsize item would cause an infinite number of pages to be ejected.)
I think your code design puts all your elements inside a single super-element
That explains why it always ejects a page at the beginning. vue-html2pdf is not receiving a series of elements, but a single giant element:
<section slot="pdf-content">
<section>
<component :is="resumeComponent"></component>
</section>
</section>
Instead of putting all your individual elements inside , I suggest breaking it up into individual entries inside the <vue-html2pdf> tag.
That would allow the pagination function to work correctly.
<vue-html2pdf ....>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
</vue-html2pdf>
Make sure each of the items that are direct children of <vue-html2pdf> has only a reasonable vertical height: no larger than the screen size.
If this works for you, remember to mark the answer as correct!

how do _mobile_* divs gets populated with html data when viewing a prestashop page in mobile

I want to understand how prestashop works regarding mobile displays.
I noticed in the used template, the header.tpl file contains the following html divs for mobile:
<div class="float-xs-right" id="_mobile_language_selector"></div>
<div class="float-xs-right" id="_mobile_user_info"></div>
<div class="float-xs-right" id="_mobile_cart"></div>
<div class="float-xs-right" id="_mobile_currency_selector"></div>
I also noticed that once I remove any of the components (for example the shopping card) from theme.yml:
global_settings:
configuration:
PS_IMAGE_QUALITY: png
modules:
to_enable:
- ps_linklist
hooks:
modules_to_hook:
displayNav1:
- ps_contactinfo
- tuxinmodaccessibility
displayNav2:
- ps_languageselector
- ps_currencyselector
- ps_customersignin
REMOVE THIS LINE ->>> - ps_shoppingcart
displayTop:
then the cart component is not displayed in the navbar. so the mobile and deskop version required this configuration to be set.
I noticed also that for each component besides having main div with _mobile_ prefix, there are also divs with _desktop_ prefix.
I'm trying to find out how to properly add my accessibility component to the navbar and that it will also be displayed on mobile.
so far it displays only on desktop and not on mobile so I was guessing that I need to add something like
<div class="float-xs-right" id="_mobile_tuxinmodaccessibility"></div>
no idea how to implement it properly.
I don't quite understand how for example, how this process works for mobile_cart div while the module name is ps_shoppingcart.
any information regarding the issue would be greatly.
You need to checkout themes/classic/_dev/js/responsive.js file.
The answer is in the theme.js file.
Script moves contents between desktop and mobile HTML elements in DOM. Every HTML element with ID that starts with id="_mobile_" gets content from corresponding desktop variation that starts with id="_desktop_" (if you inspect DOM in mobile view you'll notice that desktop elements got empty).
function o() {
u.default.responsive.mobile ? (0, s.default)("*[id^='_desktop_']").each(function(t, e) {
var n = (0, s.default)("#" + e.id.replace("_desktop_", "_mobile_"));
n.length && r((0, s.default)(e), n)
}) : (0, s.default)("*[id^='_mobile_']").each(function(t, e) {
var n = (0, s.default)("#" + e.id.replace("_mobile_", "_desktop_"));
n.length && r((0, s.default)(e), n)
}), u.default.emit("responsive update", {
mobile: u.default.responsive.mobile
})
}

Apply vue-katex to content loaded from static folder

I'm trying to make a blog using Vue as laid out in the excellent demo here. I'd like to include some mathematical formulas and equations in my blog, so I thought I'd try to use vue-katex. vue-katex formats my mathematical notation perfectly when I put all my KaTeX HTML directly into my Vue templates, but to create a useable blog I need to keep my content separate from my templates (as shown in the demo).
I can't get vue-katex to format HTML content in the static folder. That's what I'd like help with.
Setup
I cloned the github repo for the demo.
I added vue-katex to package.json:
"vue-katex": "^0.1.2",
I added the KaTeX CSS to index.html:
<!-- KaTeX styles -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-alpha2/katex.min.css"
integrity="sha384-exe4Ak6B0EoJI0ogGxjJ8rn+RN3ftPnEQrGwX59KTCl5ybGzvHGKjhPKk/KC3abb"
crossorigin="anonymous"
>
I added the import statement to src/App.vue:
import Vue from 'vue'
import VueKatex from 'vue-katex'
Vue.use(VueKatex)
and I added a simple line of HTML with KaTeX to the BlogPost template:
<p>Here's an equation in the actual Vue template: <div class="equation" v-katex="'X \\sim N(\\mu, \\sigma^2)'"></div></p>
As I said, this works - I see formatted mathematical notation in my blog post (URL http://localhost:8080/read/neque-libero-convallis-eget):
However, I need different equations for every blog post, of course.
So I tried adding KaTeX HTML to the "content" field in the JSON for the first blog post: static/api/post/neque-libero-convallis-eget.json. I changed the "content" line to:
"content": "Here's an equation in the static folder: <div class=\"equation\" v-katex=\"'X \\sim N(\\mu, \\sigma^2)'\"></div>",
This content appears on the page, but the equation doesn't render. I see this: (the text appears but no equation is shown)
When I use Developer Tools to inspect the HTML on the page, I see this:
You can see that vue-katex has been applied to the equation I put in the template directly: it has parsed the HTML I typed into lots of spans with all the mathematical symbols, which are showing perfectly.
However the KaTeX HTML I've added to the "content" in the static folder has simply been placed on the page exactly as I typed it, and is therefore not showing up as an equation on the page. I really need to keep my blog post content in this static folder - I don't want to have to create a different .vue file for each blog post, that defeats the point!
My question is: is there a way to manually "apply" vue-katex to the HTML I place in the static folder, when it loads? Perhaps there is something I can add to the plugins/resource/index.js file, since this contains the function that loads the data from the static folder?
Many thanks in advance for any help.
*Disclaimer: I'm definitely no expert / authority on what I'm about to explain!
One thing to remember is that Vue reads the templates you write, and then replaces them as reactive components. This means that although you often write Vue attributes like v-for, v-html or in this case v-katex these attributes are only useful up until the app or component is mounted.
With this in mind, if you have a Vue app that ajax loads some html, its not going to be able to rerender itself with those Vue bindings in place.
I have somewhat ignored your current set up and set about solving the issue in another way.
Step 1: Reformat your data from the server side
I've put the posts into an array, and each post contains the template (just a string of html) and the equations separately as an array. I've used [e1] in the post as a placeholder for where the katex will go.
var postsFromServer = [{
content : `<div>
<h2>Crazy equation</h2>
<p>Look here!</p>
[e1]
</div>`,
equations : [
{
key : 'e1',
value : "c = \\pm\\sqrt{a^2 + b^2}"
}
]
}];
Step 2: When the post is rendered, do some work on it
Rather than just use v-html="post.content", I've wrapped the html output in a method
<div id="app">
<div v-for="post in posts" v-html="parsePostContent(post)">
</div>
</div>
Step 3: Create a method that renders all the katex, and then replaces the placeholders in the post
methods : {
parsePostContent(post){
// Loop through every equation that we have in our post from the server
for(var e = 0; e < post.equations.length; e++){
// Get the raw katex text
var equation = post.equations[e].value;
// Get the placeholder i.e. e1
var position = post.equations[e].key;
// Replace [e1] in the post content with the rendered katex
post.content = post.content.replace("[" + position + "]", katex.renderToString(equation));
}
// Return
return post.content;
}
}
Here is the whole set up, which renders Katex:
https://codepen.io/EightArmsHQ/pen/qxzEQP?editors=1010

result hits in multiple columns using Algolia and Bootstrap 3

I'm using Algolia instantsearch.js for search, and to display my result page, I'm using Bootstrap 3, and I'd like hits to be displayed in 3 columns:
qry | hit1 | hit2
| hit3 | hit4
| hit5 | hit6
(where qry = the search query input widget)
etc..
If it's mobile, it should display as:
qry
hit1
hit2
hit3
etc.
Can someone help me with the html/css I can use to implement this?
Thanks!
Basically, you want to use bootstrap rows and grid layout col-{xs,sm,md,lg}-X (More info about the grid layout here).
One interesting property with bootstrap is that if you declare a block as being col-YY-X, if the screen width is under the dimensions YY is associated with, it automatically expands to the full width.
instantsearch.js's widgets expose a cssClasses parameter that allows you to customize the classes of the underlying markup.
To easily do two columns, all you need to do is declare the root element of the cssClasses as being a .row, and each result as a .col-sm-6 (or .col-md-6 or .col-lg-6 depending on which screen size you want it to apply).
By combining them, you can have some really interesting layouts.
See this JSFiddle
Here, I've extended a bit the idea. Try to resize the view, and you'll see that it automatically picks a number of results to display per line depending on the width by combining multiple col-YY-X classes on the hit widget.
search.addWidget(
instantsearch.widgets.hits({
container: '#hits',
templates: {
empty: 'No results',
item: '<div class="hit">{{title}}</div>'
},
hitsPerPage: 6,
cssClasses: {
root: 'row',
item: 'col-lg-3 col-md-4 col-sm-6'
}
})
);
As you can see, I've also added an inner class to the item template to be able to use the item as a wrapper with padding inside to avoid having the hits glued to each other. I apply the border to the inner element, because adding margins to bootstrap grid elements is not the right solution.
The layout itself is really simple, you can just nest rows together:
<div class="container-fluid">
<div id="search" class="row">
<div class="col-sm-4">
<div id="input"></div>
</div>
<div class="col-sm-8">
<div id="hits" class="row">
</div>
</div>
</div>
</div>

safari - contenteditable, after making it empty, creates an element with text-align:center

In safari,
i had a simple edtable div with a input button, on deletion of the element (backspace or delete), caret moves to center of edtiable div with some inline styled p tag with text-align:center and inline style "color"
<div class="editable" contenteditable="true">
<input type="button" value="inputBtn" />
</div>
http://jsfiddle.net/VqCvt/
its a strange behavior observed only in safari.
Over a year after this post, this issue is still a problem. This issue is directly tied to the input tag. Once an input tag has been in a contenteditable element, Safari will attempt to make the style of the text similar to the input (I confirmed this by observing that the resulting style was different for type="text" vs type="button"). It's a very strange bug. I have found a workaround that works, but it's pretty absurd. My fix is basically to test when my main input no longer has content, and then removing the element, and re-adding it
<div id="content-wrapper">
<div contenteditable="true" id="content" role="textbox"></div>
</div>
and in my "keyup" listener, I put the following code
// Grab main editable content div
var element = document.getElementById("content");
// Check empty state conditions. These work for me, but you may have your own conditions.
if (element.getElementsByTagName("input").length == 0 &&
element.innerText.trim().length == 0) {
// Grab parent container
var elementContainer = document.getElementById("content-wrapper");
// Add a copy of your element to the same specifications. If you have custom style attributes that you set through javascript, don't forget to copy them over
elementContainer.innerHTML = '<div contenteditable="true" id="content" role="textbox"></div>';
// Re-focus the element so the user doesn't have to click again to keep typing
element = document.getElementById("content");
element.focus();
}
What this code does works for my case because input is the only elements which are allowed in my code other than text nodes and <br>, so I first check to make sure there are no input elements, and then make sure the innerText is empty (this indicates no content in my case, you may have to customize your conditions for the "empty" state). Once the empty state is confirmed, I replace the old div with a new one to the same specification, and the user never notices. A very strange issue with a hacky workaround, but I think contenteditables.
You could probably also strip out the HTML that Safari is generating, but for my case this solution is much simpler. I hope this helps someone in the future.