How to add headers in specific pages pdfkit generated pdfs - ruby-on-rails

I'm currently using pdfkit in a 3.0.5 rails application to generate reports of user activity.
The pdf document is simple, first page it has some details about the user, a summary then
it has a table containing all the user's activity of the selected period.
First page is ok, but when I show the table the next pages must start with that header column titles in every page with the activity table header. (it remind a bank statement)
Something like this:
|user |action | source | destination |date-time |
xxx 1 1 2 2011-04-01 hh:mm:ss
....
====================page break=================================
#after page break the column titles must be printed again
|user |action | source | destination |date-time |
xxx 5 4 5 2011-04-05 hh:mm:ss
Does anybody know how could I can do that?

You should be able to use some javascript to alter the contents of the header, but only on certain pages.
in your header html have a hidden div with your table headers, but your first page header by default. Then with a javascript onload function do something like this:
<html>
<head>
<script type='text/javascript'>
function swap_header() {
var pages = document.getElementsByClassName('header');
for (var i=0; i<pages.length; ++i) {
if ( i > 0 ) {
pages[i].innerHTML = '<table><thead><th>user</th><th>action</th></thead></table>';
}
}
}
</script>
</head>
<body onload='swap_header()'>
<div class='header'>Normal 1st page header</div>
<table>
<tr><td>foo</td><td>bar</td></tr>
</table>
</body>
</html>
You could also render out 2 different pdfs, and combine them programmatically with pdftk.

Related

How to add multiple pagination in one datatable

I am using asp.net core with bootstrap datatable. It has one pagination for 1 datatable. I want one one more pagination , how can i add it.
DataTables has some built-in controls:
l - length/page size dropdown
f - filter / search input
t - the table itself
i - table information, show xxx of total entries
p - pagination control
So you can always change the DataTables markup to add/remove any control you want in the dom option: https://datatables.net/reference/option/dom
For example, you can add an extra pagination on top of the current filter box in Bootstrap 4 like the following:
$(function() {
$('#example').DataTable( {
"dom": "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>"
+ "<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>"
+ "<'row'<'col-sm-12'tr>>"
+ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
...
} );
});
A line <'col-sm-12 col-md-7'p> basically reads as following:
<!-- < means a div -->
<!-- ` means the class assigned to the div -->
<div class="col-sm-12 col-md-7">
<!-- the pagination control -->
</div>

Pass variable from content to layout in Nanoc using Slim

I basically want to know the easiest way to pass a ruby variable from a content page to its layout using Nanoc and Slim. I am thinking of something like this:
content/content.slim:
---
title: Writeups
layout: /layout.slim
---
- age = get_age
layout/layout.slim:
doctype html
html
head
== yield
p I am #{#item[:title]} and am #{#item[:age]} years old
I know how to access values via frontmatter, but frontmatter values are fixed and what I want is a ruby function to find that value for me.
Nanoc provides a capturing helper, which makes it possible to “capture” content in one place and use it somewhere else.
content/content.slim:
---
title: Mister Tree
---
p Hello there!
- content_for :age
| hundreds of years
layout/layout.slim:
doctype html
html
body
== yield
p I am #{#item[:title]} and am #{content_for(#item, :age)} years old
lib/default.rb (or any file in lib/ of your choosing):
use_helper Nanoc::Helpers::Capturing
This generates the following output:
<!DOCTYPE html>
<html>
<body>
<p>Hello there!</p>
<p>I am Mister Tree and am hundreds of years years old</p>
</body>
</html>

Grails what is the correct way of reloading a gsp

LAST UPDATE: It seems like the problem was related to geomap and not wanting to update, have now rewritten it using jvectormap as that fits my requirement better.
So
Got an application which have two boxes, one contains a bunch of controllers (resolution, region and stuff). It makes a remote call to a second box which then takes that data and extracts a bunch of things, sets up the data then sends to google visualisation.
However, if I use render in the class it works perfectly, can see that it picks up the right variables, and that they look like they do from the start.
Problem is, if I let it run without render, then the gsp page does not reload, and it is displaying the same code as was originally loaded (and actually, the picture that is generated disappears)
Is there a way I should tell the gsp page to reload or similar?
Below is the remotesubmit that works like a charm (if the controller renders output)
<g:formRemote name="mapRepmote" on404="alert('not found!')" update="page-body"
url="[controller: 'mapren', action:'show']">
<g:if test="${listreg == 'true'}">
Regulation: <g:select name="regsel" from="${reglist}" value="${regreq}" />
</g:if>
<g:else>
Regulation: ${regreq}
</g:else>
Resolution: <g:select name="ressel" from="${reslist}" value="${resreq}" />
Region: <g:select name="mapsel" from="${maplist}" value="${mapreq}" />
<div id="bupdate"><Button type="submit">Update</Button></div>
</g:formRemote>
Edit: What on earth
So been playing around and get the same results over and over again.
So the show action from the mapren controller does seem to be called. I can see the calls to the db layer and all. And if I add three render statements I can see that the requests are coming in.
def show(String regsel, String mapsel, String ressel) {
String mapcode
switch (mapsel) {
case "World":
mapcode="world"
break
case "Europe":
mapcode=150
break
case "Asia":
mapcode=140
break
case "Africa":
mapcode=002
break
case "Central Ameirca":
mapcode=017
break
case "Pacific":
mapcode=035
break
default:
mapcode="world"
}
def restem = ressel.split('x')
String mwidth = restem[0]
String mheight = restem[1]
render "I was asked to show reg: ${params.regsel} <BR>map: ${params.mapsel}<BR>Resolution ${params.ressel}<BR>"
render "will generate map for ${regsel} on code ${mapcode} resolutio"
render "I will ${mwidth} and ${mheight}"
def query = Regstat.where {
(reg==regsel)
}
def regcolumns = [['string', 'Country'],['number', regsel + 'Status']]
def results = query.list(sort:"lupdate")
def regdata = []
results.each {
regdata << [it.country.countryname,it.status]
}
def RegColors = ['0xF0F0F0','0x66CCFF','0x0000FF','0xCC66FF','0x9900CC','0x7D7D7D']
[reg_columns: regcolumns, reg_data: regdata,reg_colors: RegColors, regioncode: mapcode, wwidth: mwidth, wheight: mheight]
}
}
But if I remove the render calls, I would have expected that the show.gsp would get loaded?
But no such luck.
Have attached the show.gsp file. Note, it does is generated when index does a against it to generate the first geomap.
<%# page import="org.grails.plugins.google.visualization.util.DateUtil" %>
<html>
<head>
<script src="http://maps.google.com/maps?file=api&v=2&key=ABCDEFG" type="text/javascript"></script>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
</head>
<body>
<script type="text/javascript">
function selectHandler(e) {
alert('A table row was selected');
}
</script>
<gvisualization:geoMap elementId="page-body" showLegend="${false}" region="${regioncode}" width="${wwidth}" height="${wheight}" colors="${reg_colors}" columns="${reg_columns}" data="${reg_data}" />
</body>
</html>
OK, partial answer, but one step forward a couple back:)
So moved it around and ended up creating a straight forward static version of mapren which have a controller (staticmapren) and a template (_mapdisp). These do seem to work correctly, every time a request comes in, the page now updates correctly with text.
Problem is that the geomap is only displayed first time around.
Was fighting with this quite a lot, then realised that maybe (just maybe) the javascript console might have something to say about this...
Yes it does as it turns out...
Uncaught RangeError: Maximum call stack size exceeded
Red herring: Well, maybe, seems like that one comes up with or without reloading. It happens after about 40 seconds, so still dont have a clue why the map only turns up the first time
My problem is, what on earth can I do about this, could I potentially destroy the object and get a new one each time.
The simplified version of the controller is:
class StaticmaprenController {
def index() {
render "I am an index"
}
def show(String regsel, String mapsel, String ressel) {
String mapcode
mapcode="world"
def restem = ressel.split('x')
String mwidth = restem[0]
String mheight = restem[1]
//render "I was asked to show reg: ${params.regsel} <BR>map: ${params.mapsel}<BR>Resolution ${params.ressel}<BR>"
//render "will generate map for ${regsel} on code ${mapcode} resolutio"
//render "I will ${mwidth} and ${mheight}"
def regcolumns = [['string', 'Country'],['number', regsel + ' Status']]
def RegColors = ['0xF0F0F0','0x66CCFF','0x0000FF','0xCC66FF','0x9900CC','0x7D7D7D']
def regdata = [['UK','3'],['United States','2'],['Russia','4']]
String content = g.render (template:"mapdisp", model:[reg_columns: regcolumns, reg_data: regdata,reg_colors: RegColors, regioncode: mapcode, wwidth: mwidth, wheight: mheight])
render content
[reg_columns: regcolumns, reg_data: regdata,reg_colors: RegColors, regioncode: mapcode, wwidth: mwidth, wheight: mheight]
}
}
And the _mapdisp template
Going to elementId="page-body" <BR>
Testing some stuff showLegend="${false}" <BR>
Will do region="${regioncode}" <BR>
Lets go width="${wwidth}" and height="${wheight}"<BR>
And these are the Beutiful colours colors="${reg_colors}" <BR>
Now columns columns="${reg_columns}"<BR>
And the data="${reg_data}"<BR>
<script type="text/javascript">
function selectHandler(e) {
alert('A table row was selected');
}
</script>
<gvisualization:geoMap elementId="geomap2" showLegend="${false}" region="${regioncode}" width="${wwidth}" height="${wheight}" colors="${reg_colors}" columns="${reg_columns}" data="${reg_data}" />
</body>
<div id="geomap2"></div>
</html>
And to get geomap and google visualisation you will need to install the api, and do some fix with raw (Google Visualization API. Graphs are not displaying in gsp pages)
I have also loaded the api in the main body of the page.
(Adding the following lines)
<%# page import="org.grails.plugins.google.visualization.util.DateUtil" %>
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="genmap-desk"/>
<script src="http://maps.google.com/maps?file=api&v=2&key=ABCDEFG" type="text/javascript"></script>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
Any suggestions what I can do about Maximum call stack?

Remove hash id from url

I have a menu header and when you click one of the menu links it directs to another page half way down (which i want) as it finds the relevant div id name. I was wondering if there is a way to clean the url back up again so it doesn't include the #id in my url? Tried window.location hash and this breaks it from scrolling and leaves the # in the url. Here is what i have:
In my menu: <li><a href="about#scroll-to" ....
And on the about page, it scrolls down to a div called #scroll-to..<div id="scroll-to"></div>
Any suggestions would be great. Thanks!
Using jquery, you can make a POST call to the target page when menu is clicked.
The POST data will contain the id of the div where you want to slide to.
On your target page, use your server language (php, asp) to output that id in a js variable and on document ready slide using jquery to that id.
Then you will have a clean url, and the page scrolling to your div.
---- edit: here comes the code!
Lets use jquery to make a POST to the target page, when a menu item is clicked. We will add a class, lets say, "mymenuitem". We will add this class to our link in the menu. So we will have
<li>Information about us</li>
(the onClick stops link from redirecting manually)
and an empty form (put it after the < body >)
<form id="slidinganchorform" method="post" action="YOURTARGETPAGE.HTML"></form>
then we will create the neccessary jquery so when the < a > tag with class "mymenuitem" is clicked, we will make a POST to the target page.
<script type="text/javascript">
jQuery(document).ready(function(){
$(".mymenuitem").click(function() {
// we will split the clicked href's value by # so we will get [0]="about" [1]="scroll-to"
var the_anchor_id_to_scroll_to = $(this).attr("href").split('#')[1];
// lets do the POST (we WILL TRIGGER a normal FORM POST while appending the correct id)
$("#slidinganchorform").append('<input type="hidden" name="anchorid" value="'+ the_anchor_id_to_scroll_to + '">');
$("#slidinganchorform").submit();
});
});
</script>
then in our YOURTARGETPAGE.HTML we will have something like (let's assume we use php)
<head>
<!-- make sure your jquery is loaded ;) -->
<?php
if($_POST['anchorid']!='')
{
?>
<script type="text/javascript">
jQuery(document).ready(function(){
// lets get the position of the anchor (must be like <a name="scroll-to" id="scroll-to">Information</a>)
var thePositiontoScrollTo = jQuery('#<?php echo $_POST['anchorid']; ?>').offset().top;
// Lets scroll
jQuery('html, body').animate({scrollTop:thePositiontoScrollTo}, 'slow');
});
</script>
<?php
}
?>
</head>
be sure the correct id must exist ;)
<a name="scroll-to" id="scroll-to">Information about us or whatever...</a>
(remove your old code because i changed some variable names and it will be difficult to debug if there are parts from the previous version. write everything from the start )
You can do this when the new page loads
history.pushState("", document.title, window.location.pathname);
However it will also remove the query string. Although, you could play with it a little bit to keep it

Append html to div not working on cordova iOS

I am using cordova 2.2.0 with Xcode 4.5.2. On one of my pages I have a select component and once a particular option is selected I want to display a table within a div. My html looks like this: <div class="hero-unit" id="#facprog"></div>
The javascript/jquery looks like this:
<pre><code>
$(function() {
$('#selFaculty').change(function() {
var facultyName = $('#selFaculty').val();
var progDetails = app.fillFacultyProgramme(facultyName);
alert(progDetails);
$('#facprog').append(progDetails);
});
});
</code></pre>
Note that #selFaculty is the id of the select object. However, when the select option changes, everything in javascript executes except for the append. Nothing shows up in the div. Is there a different way to add html element to a div in jquery under cordova 2.2.0 in iOS?
Thanks in advance,
José
With jquery you can refresh a div.
This is a good example:
<script>
var auto_refresh = setInterval(
function()
{
$('#loaddiv').fadeOut('slow').load('reload.php').fadeIn("slow");
}, 20000);
</script>
and now you need to put the div in the body section of your page
<div id="loaddiv">
</div>
from http://designgala.com/how-to-refresh-div-using-jquery/
and there is another example here:
refresh div with jquery
The first example is useful when you need to load a script and refresh and the second one is useful when you need to make a change, e.g. append html and then refresh as in your case.

Resources