Re-render Reactjs components for print - printing

I have a gallery component that uses the current window size to determine how large to make the gallery items. I've also hooked the window resize events so that the gallery items are resized correctly as the window is resized.
In Chrome, if a user then prints the gallery, the items are not being resized to fit the printed page. Instead they are just using the last size calculated for the window size. This is true even when switching from portrait to landscape in the print options.
Is there any way to force react to re-render components when the print dialog is being opened and when the page layout is switched from portrait to landscape? I thought the print dialog would re-render the page with the new dimensions but that doesn't seem to be the case.

When you print a page, the browser takes a snapshot of the current DOM and applies the print media styles. Your problem is the elements on your DOM are dependent on the dimensions of the screen.
Window resize events will help to rearrange your components when the user resizes their screen but they are not triggered when the user prints. There are however ways in which you can listen to an event when the user prints the page.
window.onbeforeprint will trigger when the user prints the page. On event you either resize the screen to make the window resize events trigger or re-render your components some other way. It is not supported in chrome although take a look at this stackoverflow post, it explains how you can use window.matchMedia('print') instead.
It's always best to depend on css media queries rather than on the screen dimensions and resize events, but sometimes that is not always possible.

Use media query to target portrait and landscape print
#media print and (orientation: landscape) {
/* landscape styles */
/* write specific styles for landscape e.g */
h1 {
color: #000;
background: none;
}
nav, aside {
display: none;
}
}
#media print and (orientation: portrait) {
/* portrait styles */
}

In addition the WitVault's solution, I've created a simple React Component that makes handling complex print.css much easier. Instead of adding classes, IDs, etc. all over your markup and creating a complex print.css file, you can use my react-print library as follows:
https://github.com/captray/react-print
Add this ID to the root (or somewhere high up in your DOM tree) of your current content (but inside in the body tag)
<div id="react-no-print">
Add a div with the id of 'print-mount', or whatever mount ID you'd like to use.
<div id="print-mount"></div>
Create the structure you want for your printable version (which can include child components with their own styles to make things easier.
var PrintTemplate = require('react-print');
var ReactDOM = require('react-dom');
var React = require('react');
var MyTemplate = React.createClass({
render() {
return (
<PrintTemplate>
Your custom HTML or React Components go here, and will replace the existing HTML inside of the "react-no-print" ID, and instead it will render what's inside of your custom template.
</PrintTemplate>
);
}
});
ReactDOM.render(<MyTemplate/>, document.getElementById('print-mount'));
Basically, this renders your printable version, but it's hidden until it's needed for printing. If you need this for a sliding gallery, you probably want to hook into the change event for your slider and re-render (unmount the old one, mount the new one) the print template.
Hope this helps!

You will need to use matchMedia API in your component. But doing it yourself, you will be re-inventing a whole lot of the wheel. It'd be easier to use an existing library which takes care of this. Please check out https://www.npmjs.com/package/react-responsive. It has React based wrapper components over matchMedia, so you should be able to quickly prototype it in your project. There are polyfills available too. One other advantage I can think of is that you can have a print-preview option in your interface where you can let the user preview how the gallery will look in print mode. For this you can use the server rendering feature of this library to simulate print mode.
PS: I am not affiliated with this project in any way.

Related

Vaadin Dialog resize programmatically

Vaadin 14.2.0.alpha7 added new functionality to Dialog component (https://vaadin.com/api/platform/14.2.0.alpha7/com/vaadin/flow/component/dialog/Dialog.html), especially the resizing availability. Unfortunately I was unable to find a way to have dialog being created with width I need neither to set the width programmatically after the dialog is opened.
Here are few lines of code I use for described purposes (unsuccessfully):
dialog.isResizable = true
dialog.width = "900px"
dialog.addOpenedChangeListener { event ->
println("!!!opened-changed event fired")
dialog.width = "900px"
println("!!!dialog width = ${dialog.width}")
}
dialog.addResizeListener { event ->
println("!!! on resize event width = ${dialog.width}")
}
When I open the dialog it appears with its limited width (around 500px), the OpenedChanged event being fired and prints that dialog has 900px width (while its not!), when I resize it manually the Resize event being fired and prints that dialog has around 600px width (after I increased it a bit manually using mouse).
I know that early versions of Dialog had limited width (around 500px) in templates and there is workaround with importing styles to adjust dialog width. I was hoping with new version to increase dialog width without touching templates and client-side.
Is there any way to set dialog width and adjust on being opened programmatically without touching client-side templates?
P.S. The 14.2.0 version announced to be published on April so I believe the question is suitable even for now its prerelease version.
This happens due to the max-width setting of ~560px to comply with the materials design. There is a ticket about it here: Dialog Size - Material Theme. (In the default Lumo theme this works out of the box. You can verify it by commenting out #Theme(value = Material::class, variant = Material.LIGHT) in MainLayout.kt)
Unfortunately, as style targets the overlay part, the only one way to overcome this is using style files. On the other hand, it should be pretty straightforward in the current version :)
I created a pull request to your repo with the changes needed. Feel free to use it, if you want Make width acccept values more than 500px :)

WebView qml doesn't work correctly on iOS 11

I've a problem, i need to open url inside app, and I used a WebView, but doesn't work correctly.
imported this:
import QtWebView 1.0
my code:
Rectangle{
width: Screen.width
height: Screen.height
color: "Orange"
anchors.fill: parent
z:9999999
WebView {
id: webviewer
anchors.fill: parent
url: "http://www.google.com"
onLoadProgressChanged: {
console.log(webviewer.loadProgress)
}
}
}
and in the .pro file i've put:
QT += webview
And my main.cpp
QtWebView::initialize();
my console.log is printing correctly the load status, but on the screen I don't see nothing.
Why?
Works on iOS, the solution is:
Open project in Xcode from build folder, and set App Transport Security Settings, you must add Allow Arbitrary Loads and sets it on YES.
Now the WebView works.
initialize() creates opengl surface, in this case You must first open parent window(surface to display) , other solution is to comment initialize() - page will show. If you'll decide to show it on GL surface, try to se ALWAYSSTACKONTOP attribute to see, if other windows dont cover webview, opengl is rendered first,so any other background can make it not visible. You may also open webview class parented to other, visible window, but if you will show it fullscreen, it will be flicker a while

Hide automatic visability of HTML5 video controls at beginning of video play but maintain all other default control behaviour

I have a high(er) resolution (500 x 403) "video intro" that a client wants me to add to the beginning of a "main" video they delivered to me. The main video is low res (200 x 150).
I can EITHER makes the intro low res and add it (which the client doesn't like) OR I can double the resolution of the main video and add it (which balloons the bandwidth required to download and play the movie.) Also not optimal as this is destined for mobile.
I have a third solution I am going to use. I am playing the high res "intro video" and when that ends I am automatically loading the main video and playing it right behind the intro by creating a playlist containing the intro and the main video.
The problem I have is the default controller behavior for HTML 5 video is to be visible for the first 2 or 3 seconds of a video and then fade out. This is fine for the first video in the playlist however I would like the control to not show at the beginning of subsequent videos. The intro is only 6 seconds and the appearing and disappearing controls look messy and I would like both videos to appear as one.
I have tried using "videoPlayer.removeAttribute("controls");" however this kills the controls entirely so if a user taps the video later to intentionally bring the controls back up later nothing happens. Ideally I would like to keep all the default behavior with the exception of showing the controls at the beginning of the video.
I have seen some long winded attempts at trying to modify video.js to achieve something of this nature but ideally I can do something to the native features to enable this.
Any ideas?
Original code:
<script type="text/javascript">
$(document).ready(function(){
var xx=1;
var nextVideo = new Array();
nextVideo[0] = "Content/videos/Logo_Animate_537.mp4";
nextVideo[1] = "Content/videos/Main.mp4";
nextVideo[2] = "Content/videos/Logo_Animate_537.mp4";
$("#videoPlayer").bind('ended', function(){
if(xx>nextVideo.length-1){
videoPlayer.setAttribute("controls","controls");
videoPlayer.pause();
xx=1;
} else {
videoPlayer.removeAttribute("controls");
videoPlayer.src = nextVideo[xx];
videoPlayer.play();
xx++;
}
});
//+++++++++++++++++++ This section was added as the solution ++++++++++++++
$("#videoPlayer").on('click touchstart', function () {
videoPlayer.setAttribute("controls","controls");
});
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
});
</script>
<video id="videoPlayer" width="537" height="403" controls poster="images/main.jpg">
<source src="Content/videos/Logo_Animate_537.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
It seems like you have two options here. The first one is to simply remove and replace the controls attribute as you need. This would be the simplest solution, as
element.setAttribute('controls', '')
will simply put the controls back when you need them. The other option is to not use the browser controls at all, define your own custom controls, and hide or show them as you wish.

jquery resizable handles - are they supposed to work?

Ok, So I'm a bit lost on this. jQuery UI documentation states that on resizable i can have visible handles which as i understand are visible icons/pictures (do I understand this correctly?)
If specified as a string, should be a comma-split list of any of the following: 'n, e, s, w, >ne, se, sw, nw, all'. The necessary handles will be auto-generated by the plugin.
So I should have handles all over my object if I specify 'all' ? If so, it does not seem to work--I only have something visible on 'se' corner.
Now looking at jQuery UI resizable source code, it seems that this is the only way it is supossed to work :
if ('se' == handle) {
axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
};
Am I missing something? Can I create them on my own?
That code is telling the widget to only bother setting up a nice icon for the SE handle, if they're automatically generated. It's still actually creating the handles as a small, invisible box in each corner which can be dragged, just without any icon (the jQuery UI iconset actually doesn't have any other similar handles).
Refer to the API doc for how to attach them to your own DOM objects, which you can easily customise the appearance of. Quick example:
$('#targetToMakeResizable').resizable({handles : { ne : ".jquerySelectorForNEHandle", sw: ".jquerySelectorForSWHandle" }, aspectRatio : true});
Alternatively, you can just override the base css for .ui-resizable-handle.ui-resizable-{direction} with your own settings.
Here's a jsfiddle to demonstrate both methods. Note that rotating the icon in the way I've done it is probably not going to work in every browser.

Grails UI Menu flakey behavior in IE

I'm using a GRAILS UI (1.2-SNAPSHOT) an it's implementation of the YUI menubar (YUI 2.7.0.1). I am seeing flakey mouseover behavior in IE (Firefox is ok). When I mouse over the menu item with a submenu, it will show. As I try to mouse over the sub-menu, the submenu disappears before I can click. This happends in a pattern I haven't fully figured out. Usually the first time I select a menu it's fine but if I move around the menu back to a menu item, the submenu begins to display this behavior. By clicking and holding the mouse button I can usually get the sub-menu to stick around.
I've palyed with various configurations like keepopen and automenudisplay but they don't seem to change the behavior. I have not seen much posted about this. But I also don't see menu's documented in the UI plugin either. I could really use some feedback if UI menu is not ready for primetime yet or I'm missing something else. I've not worked with much AJAX before.
Below is the code with the added options I played with that did not have a positive impact.
<gui:menubar id='menubar' renderTo='mainmenu' autosubmenudisplay="false" shadow="true" keepopen="true">
<gui:menuitem url="/esmzone">Home</gui:menuitem>
<gui:submenu label='Profile'>
<gui:menuitem url="${createLink(controller:'memberProfile', action:'view')}">View</gui:menuitem>
<gui:menuitem url="${createLink(controller:'memberProfile', action:'profile')}">Edit</gui:menuitem>
<gui:menuitem url="${createLink(controller:'user', action:'account')}">Settings</gui:menuitem>
<gui:menuitem url="#">Subscription</gui:menuitem>
</gui:submenu>
Here is the code generated by the plugin:
<script>
YAHOO.util.Event.onDOMReady(function() {
GRAILSUI.menubar = new YAHOO.widget.MenuBar("menubar_div", {'autosubmenudisplay': false,
'shadow': true,
'keepopen': true});
GRAILSUI.menubar.render('mainmenu');
});
</script>
I made some progress on this by researching the YUI library. There is a documented bug with IE7. Apparently the grails-ui plugin does not address the fix. I'm testing with IE8 but I assume it's still there.
http://developer.yahoo.com/yui/menu/#knownissues
It appears that you should set the zoom property to 1 (zoom:1) for the bd class.
I added the following code to my style sheet
div.yuimenubar .bd {
zoom: 1;
}
and it seems to help. I see no side effect in Firefox but I didn't dynamically check for the version of browser as I would need to hack the code that generates the YUI javascript and put in
if (YAHOO.env.ua.ie === 7) {
YAHOO.util.Dom.addClass(document.body, "ie7");
}
after the render() call. Then instead of the style I added you could do an IE7 (probably >=7) style.
This is what the Yahoo site had to say about it:
The following application of
"zoom:1" sets the "hasLayout"
property to "true" and prevents
first tier submenus of a MenuBar
from hiding when the mouse is moving
from an item in a MenuBar to a
submenu in IE 7.
For more on the "hasLayout" property:
http://msdn.microsoft.com/en-us/library/ms533776(VS.85).aspx

Resources