html2pdf: overflow:hidden does not seem to work - html2pdf

I have text to output into cells, text might be too long, in this case I'd like the overflow to be simply hidden.
The version tested is html2pdf v. 5.2.2 .
I can't find doc about which CSS is recognised and which is not.
Instead I found in /src/Parsing/Css.php code that seems to imply that "overflow" is recognised at least for values "visible" and "hidden":
case 'overflow':
if (!in_array($val, array('visible', 'hidden'))) {
$val = 'visible';
}
$this->value['overflow'] = $val;
break;
So I tried following test case:
<?php
require __DIR__.'/vendor/autoload.php';
use Spipu\Html2Pdf\Html2Pdf;
$html = <<<EOT
<body>
<style>
.red {
color:red;
width:30px;max-width:30px;
overflow:hidden;
}
.blue {
color:blue;
}
</style>
<table>
<tr>
<td class="red" >totototototototototototototototo</td>
<td class="blue">titi</td>
</tr>
</table>
</body>
</html>
EOT;
$toPdf=false;
if($toPdf) {
$html2pdf = new Html2Pdf();
$html2pdf->writeHTML($html);
$html2pdf->output();
}
else { echo $html; }
I'd like the expected output, as rendered in an html browser.
But html2pdf's output simply ignores the css overflow directive (see captures).
Is there something I'm doing wrong?
Is there a way at all?
I'd like a CSS solution/turnaround if possible, no solution based on a substring truncation (because such solutions will have disastrous results with strings like "WWWMMWMWWM" vs "iiilliilli" for instance, 10 characters each, quite a different width).
I'd be grateful to any solution or any hint towards a solution.
Thanks in advance.
Here under the html output in a browser, and the PDF output made by html2pdf.

overflow:hidden finally seems to work with DIV elements.
But neither display:inline-blocknor float:left do, which would allow side by side DIVs...
A few more tests, and I found my turnaround: a DIV with overflow:hidden in each TD...

Related

How to Form Tables Correctly When HTML Template Components are Separated?

When building tables in Lit, sometimes I need to generate different parts of a table in different parts of the code. But when I put everything together, the table does not look the same as if it were declared all in one place.
See this playground for an example of the same table that's assembled two different ways. Is there any way I can make the "two halves" table look the same as the first, while still creating the elements in separate html`` blocks?
I tried creating a table in two different ways (see playground), I expected it to be the same resulting table in both instances. What actually happened is that they looked different, and I want to know why/how to correct this.
Lit does not do string concatenation and each html tag function results in a cached Template element which can be efficiently rendered. This means that each of your html tags get implicitly closed by the browser's HTML parser.
E.g.: html`<table>...` is parsed by the browser into: html`<table>...</table>`. From lit.dev documentation on "Well-formed HTML": https://lit.dev/docs/templates/expressions/#well-formed-html
Lit templates must be well-formed HTML. The templates are parsed by the browser's built-in HTML parser before any values are interpolated. Follow these rules for well-formed templates:
Templates should not contain unclosed elements—they will be closed by the HTML parser.
Therefore instead of the following structure:
// Does not work correctly - do not copy this. For demonstration purposes.
const start = html`<table>`;
const content = html`content`;
const end = html`</table>`;
const result = [start, content, end];
return html`${result}`;
// This would render as: <table></table>content<table></table>
Consider the following structure instead where each html tag function is well formed HTML:
const tableFrame = (content) => html`<table>${content}</table>`;
const content = html`content`;
// Pass the content template result into the table frame.
return tableFrame(content);
The following is your code from the playground example restructured in this way:
<script type="module">
import {LitElement, html, css} from "https://cdn.jsdelivr.net/gh/lit/dist#2/core/lit-core.min.js";
class TableExample extends LitElement {
static styles = css`table, th, td { border: 1px solid black; }`;
generateTables() {
const tables = [];
const tableRow1 = html`
<tr>
<td rowspan=2>0</td>
<td>1</td>
</tr>`;
const tableRow2 = html`
</tr>
<td>2</td>
</tr>`;
const table1 = html`
<table>
<tr>
<td rowspan=2>0</td>
<td>1</td>
</tr>
</tr>
<td>2</td>
</tr>
</table>
`;
const tableFrame = (content) => html`<table>${content}</table>`;
// Full table
tables.push(table1);
tables.push(html`<br />`);
// Use tableFrame with custom content.
tables.push(tableFrame(html`<tr><td>Custom Content</td></tr>`));
tables.push(html`<br />`);
// Use tableFrame with the two rows defined earlier.
tables.push(tableFrame([tableRow1, tableRow2]));
return tables;
}
render() {
return this.generateTables();
}
}
customElements.define('table-example', TableExample)
</script>
<table-example></table-example>
As an additional reference the documentation on Templates: https://lit.dev/docs/templates/expressions/#templates

Modal for fullsize image with gatsby-image - limit height and width

What I want to achive
I am using gatsby and want to design an image gallery. Clicking on one of the images shall open a modal, which: (1) is showing the image in maximum possible size, so that it still fits into the screen and (2) is centered in the screen.
My Code
/* imagemodal.js */
import React from 'react'
import * as ImagemodalStyles from './imagemodal.module.css'
import { Modal } from 'react-bootstrap'
import Img from 'gatsby-image'
import { useStaticQuery, graphql } from 'gatsby'
export default function Imagemodal() {
const data = useStaticQuery(graphql`
query {
file(relativePath: { eq: "images/mytestimage.jpg" }) {
childImageSharp {
fluid(maxWidth: 1200) {
...GatsbyImageSharpFluid
}
}
}
}
`)
return (
<div>
<Modal
show={true}
centered
className={ImagemodalStyles.imageModal}
dialogClassName={ImagemodalStyles.imageModalDialog}
onHide={(e) => console.log(e)}
>
<Modal.Header closeButton />
<Modal.Body className={ImagemodalStyles.imageModalBody}>
<h1>TestInhalt</h1>
<Img fluid={data.file.childImageSharp.fluid} />
</Modal.Body>
</Modal>
</div>
)
}
/* imagemodal.module.scss */
.imageModalDialog {
display: inline-block;
width: auto;
}
.imageModal {
text-align: center;
}
.imageModalBody img {
max-height: calc(100vh - 225px);
}
The Problem
The image does not scale to the screen size. The image is either too big - so it flows over the vieport - or it is too small. Secondly, the modal size does not respond to the image size correctly and / or is not centered.
What I tried
I used this suggestion for the CSS: How to limit the height of the modal?
I tried as well dozens of other CSS parameter combinations. But I could not find a working solution.
I tried to format the gatsby-image directly with a style-tag.
I tried as well react-modal but had similar problems.
Does anyone have a good solution to show a gatsby-image in full screen size in a responsive modal? For me it is okay to use either the bootstrap-modal or react-modal - or any other suitable solution.
Edit
In the end I ended up with a workaround. I used react-image-lightbox and took the Image-Source from gatsby-image as the input for lightbox. My component gets the data from the graphQL query in the props via props.imageData.
This works quite well for me:
import Lightbox from 'react-image-lightbox';
...
export default function Imagegallery(props) {
...
const allImages = props.imageData.edges
const [indexImageToShow, setIndexImageToShow] = useState()
...
return(
<Lightbox
mainSrc={allImages[indexImageToShow].node.childrenImageSharp[0].fluid.src}
...
/>
Special thanks to #FerranBuireu to point me to the right direction
Assuming that the functionality works as expected, as it seems, it's a matter of CSS rules, not React/Gatsby issue. The following rule:
.imageModalBody img {
max-height: calc(100vh - 225px);
}
It Will never be applied properly, since gatsby-image creates an output of HTML structure of nested <div>, <picture> and <img> so your rule will be affected by the inherited and relativity of the HTML structure. In other words, you are not pointing to the image itself with that rule because of the result HTML structure.
You should point to the <Img>, which indeed, it's a wrapper, not an <img>.
return (
<div>
<Modal show={true} onHide={handleClose} centered className={ImagemodalStyles.imageModal} dialogClassName={ImagemodalStyles.imageModalDialog}>
<Modal.Header closeButton />
<Modal.Body>
<Img className={ImagemodalStyles.imageModalBody} fluid={props.data.file.childImageSharp.fluid} />
</Modal.Body>
</Modal>
</div>
)
The snippet above will add the (spot the difference, without img):
.imageModalBody {
max-height: calc(100vh - 225px);
}
To the wrapper, which may or may not fix the issue, but at least will apply the rule correctly. It's difficult to know what's wrong without a CodeSandbox but you will apply the styles correctly with this workaround.
Keep always in mind that when using gatsby-image, the <img> it's profound in the resultant HTML structure so your styles should apply to the outer wrapper of it.

Newline inside variable in div

Is it possible to use a variable in <div> with newline inside?
class Hello extends React.Component {
render() {
const texts = {
subHeaderText: 'first line \n second line'
};
return <div>{texts.subHeaderText}</div>;
}
}
I wish to result
first line
second line
What is the simplest way?
https://jsfiddle.net/69z2wepo/263117/
You can use p (paragraph) tags.
check out this site:
https://forum.freecodecamp.org/t/newline-in-react-string-solved/68484/7
div{
white-space: pre-line;
}
Add this to the css file of your html. This will automatically create line breaks whenever /n or <br> are encountered. This is the simplest way.
As a recommendation, since it looks like a hardcode you might as well use two separate <p> or <div> for both like so:
<div>
<p>
first line
</p>
<p>
second line
</p>
</div>
It's just much more elegant that way unless you really want to display line breaks from input. Given that you may also approach it in a js way like so:
texts.subHeaderText.split('\n').map((item, i) => {
return <p key={i}>{item}</p>;
});

Dynamically set fancybox 3 iframe size

When dealing with dynamically sizing the iframe in fancybox, I accidentally found that setting data-width and data-height on the [data-fancybox] is helpful after reading this answer.
Exmaple HTML element:
<a data-fancybox data-width="<?= $banner_width; ?>" data-height="<?= $banner_height; ?>" data-src="example.com" href="javascript:;">example.com</a>
and js:
$("[data-fancybox]").fancybox({
afterLoad: function ( instance, slide ) {
$('body').find('.fancybox-content').css({"width": slide.opts.width + "px", "height": slide.opts.height + "px"});
}
});
What I couldn't figure out is that there is no explanation of data-width and data-height usage on HTML element from fancybox documentation (please correct me if I'm wrong).
NOTE: these two code snippets above do work for me, but they have to work together, it wouldn't work if one of them is taken off.
Can anyone explain that a little bit for me please?
Based on fancybox 3 documentation, they do offer a way to set our own custom options by creating data-options attribute. Here is the example from the documentation:
<a data-fancybox
data-options='{"caption" : "My caption", "src : "iframe.html"}' href="javascript:;">
Open external page using iframe
</a>
You can see the value of these options by console.info( slide.opts ) from the callback function like onComplete (slide is one argument in the callback function ).
Not surprisingly, these two snippets are the same:
<a data-fancybox data-width="<?= $banner_width; ?>" data-height="<?= $banner_height; ?>" data-src="example.com" href="javascript:;">example.com</a>
<a data-fancybox data-options='{"width" : "<?= $banner_width; ?>", "height" : data-height="<?= $banner_height; ?>", "src" : "example.com" }' href="javascript:;">example.com</a>
So, in my javascript, I use slide.opts.width to get the value from data-width and slide.opts.heightto get the height from data-height, that is how my width and height value get passed from backend to frontend.
Since these two values are processed in afterLoad callback, so every iframe will be initiated with different width and height.
Properties - data-width and data-height - are used to tell the script real dimension of the image. The script then can calculate position and start zooming thumbnail while real image is still loading.
See documentation - http://fancyapps.com/fancybox/3/docs/#images
These properties are not used anywhere else.
You can use { iframe : { css : { width: '', height : '' } } } to set iframe element width/height, but there is no option to change iframe content.

How to: Fixed Table Header with ONE table (no jQuery)

I know, there are at least 3 dozen questions like this on stackoverflow and still, I could not make this happen:
A simple table where thead is sticked/fixed at the top, and the tbody is scrolled.
I tried so much in the past days and now I ended up here crying for help.
A solution should work in IE8+ and newest FF, Chrome & Safari.
The difference to other "possible duplicates like this one is that I don't want to use two nested tables or jQuery (plain javascript is fine though).
Demo of what I want:
http://www.imaputz.com/cssStuff/bigFourVersion.html.
Problem is it doesn't work in IE, and I would be fine to use some JS.
Ok i got it:
You need to wrap the table in two DIVs:
<div class="outerDIV">
<div class="innerDIV">
<table></table>
</div>
</div>
The CSS for the DIVs is this:
.outerDIV {
position: relative;
padding-top: 20px; //height of your thead
}
.innerDIV {
overflow-y: auto;
height: 200px; //the actual scrolling container
}
The reason is, that you basically make the inner DIV scrollable, and pull the THEAD out of it by sticking it to the outer DIV.
Now stick the thead to the outerDIV by giving it
table thead {
display: block;
position: absolute;
top: 0;
left: 0;
}
The tbody needs to have display: block as well.
Now you'll notice that the scrolling works, but the widths are completely messep up. That's were Javascript comes in.
You can choose on your own how you want to assign it. I for myself gave the TH's in the table fixed widths and built a simple script which takes the width and assigns them to the first TD-row in the tbody.
Something like this should work:
function scrollingTableSetThWidth(tableId)
{
var table = document.getElementById(tableId);
ths = table.getElementsByTagName('th');
tds = table.getElementsByTagName('td');
if(ths.length > 0) {
for(i=0; i < ths.length; i++) {
tds[i].style.width = getCurrentComputedStyle(ths[i], 'width');
}
}
}
function getCurrentComputedStyle(element, attribute)
{
var attributeValue;
if (window.getComputedStyle)
{ // class A browsers
var styledeclaration = document.defaultView.getComputedStyle(element, null);
attributeValue = styledeclaration.getPropertyValue(attribute);
} else if (element.currentStyle) { // IE
attributeValue = element.currentStyle[vclToCamelCases(attribute)];
}
return attributeValue;
}
With jQuery of course this would be a lot easier but for now i was not allowed to use a third party library for this project.
Maybe we should change a method to archieve this goal.Such as:
<div><ul><li>1</li><li>2</li></ul></div> //make it fixed
<table>
<thead>
<tr><th>1</th><th>2</th></tr>
</thead>
<tfoot></tfoot>
<tbody></tbody>
</table>
Of course, this is not good to sematic.But it is the simplest way without js or jq.
Don't you think so?