We have a complex AngularJS-based application with different loaded stylesheets. I need to print the separate page with nice styling, exactly how it looks in the browser, plus several elements need to be opened via ng-show for the print.
Looking for potential existing solutions, I've found the following AngularJS directive: https://dzone.com/articles/building-simple-angularjs. I had to slightly update it to load css stylesheets. Eventually, when I click the Print button, I can generate the huge HTML file with css references in <head/>. Being posted directly into browser, it looks more or less nice, but:
Ng-show /ng-hide are fully ignored, and that is expectable. How to deal with it?
Mostly important - when I try to Ctrl-P this HTML, it doesn't looks nice in preview at all. What I'm doing wrong?
Related
I've searched for latest info but can't find a full answer relevant to my situation and since I'm new to js and php I need a little more direction.
I created a site using Bootstrap and the popover section proved a problem on mobile (specifically Safari - it doesn't dismiss). I decided to use BS panels for mobile and used Bootstrap's .hidden-lg and .visible-sm classes to show that popovers are visible on desktops and panels are visible on mobile sizes. However the script clashed, as soon as both are in my html file, it won't load won't of them, eg. popovers won't work but panels does. I tried to place it differently, thinking maybe the order in my code matters. In the end I found that little sentence in BS docs that says "don't use data attributes from multiple plugins on the same element". I figured that means I can't use two types of plugins in my one page even though the two sections are not supposed to be displayed on the same page - it should load only one depending on the device size.
I searched for a method to use jquery to detect screen size to insert a php file. I created two php files (one for large screens, one for small, placed the popover and panel sections in each) I created my original index as a new index.php.
I can't tell where I went wrong because it's not working and I've made so many changes to the code to try and fix it that it's probably a mess right now anyway.
I tried another method: I found some old info to create m.domain.com which means you have to include link rel="alternate"... in desktop file and rel="canonical" in mobile to link to mobile_file.php
It loaded the correct files (though mobile is duplicating my footer for no apparent reason) but the js script is still not activating properly. Now mobile is loading panels but not dismissing it (and it worked for sure when I tested the single file before) and desktop popover is not opening up (meaning the js is not working) at all!
How can I use a simple method to say: if the screen size is this, use this file and if not, use that file. I'm sure this is possible with js but I just can't find a clear, easy to understand and follow method online. Clearly my js knowledge is lacking but a simple site is proving complicated in the final steps. All help would be appreciated because it's really hard to find updated info on this exact issue.
for more info: I used the Bootstrap html boilerplate which links this by default as script: src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"
The panels would only work if I use src="js/jquery.min.js"
I know these two are the culprits because when I deleted the first then the panels would work and when I deleted the second the popovers would work but they will not work for both with either one of these. I don't know what to change to make it work.
So on my websites I need to make sure that everything still works even when JavaScript is being blocked, which means that things that I want to hide until someone clicks on something have to be shown with CSS and then hidden with JS, which makes it look glitchy when the page is loading because the JS files are always loaded after the CSS stylesheets.
Is there a way for JS style changes to happen before CSS is loaded? Like, stop the CSS from loading with JS, make the necessary changes, and then continue loading the other files, maybe?
If you really want to load your css-file after some code of your javascript:
1. Don't specify a href attribute of you css:
<link rel="stylesheet" href="" type="text/css" media="screen" id="my-style">
Add this in your code (may be the last line of your javascript):
$('#my-style').attr('href','style.css');
And your css-file will be loaded only after that line of javascript
Try adding a .js-enabled class to HTML the tag with an inline script at the top of the head tag. You can then have CSS hide the scripted stuff for you while the rest of the scripts load.
Updated answer (see comment below):
If JS is blocked, you need to either choose to detect this and serve content based on that, meaning backend code, or make use of another strategy such as <noscript>.
Original answer:
which means that things that I want to hide until someone clicks on something have to be shown with CSS and then hidden with JS,
I would always start with display:none or visibility:hidden (see elsewhere for difference between the two) in the css, and use the JS to reveal the element.
There are several ways to solve your problem. What you need to know is the difference between blocking and non-blocking content. Every script and css (media=screen) is immediately invoked. So if you put some css in there in your head, and append something with JavaScript later on, you indeed might seen it shortly in a 'non javascript' way.
To combat this you could have the objects initial state represent the html/css as if the JavaScript has been loaded. (Most ideally you would have serverside rendering, but for simpler sites thing isn't always needed). The downside of this method is that if you have an JavaScript error which prevents further execution, you have a broken state. And if you also neglect the few people that have JS disabled, you're save and rendering looks fine again. Furthermore! You can improve on your sites performance by loading the scripts asynchronously.
If you want a different approach, you can add a className to your html eg <html class="noscript">. Then when all your JavaScript has been loaded, you remove the className. This way you only have one redraw, and it looks progressive. There is a downside to this approach though, since bad performance becomes increasingly visible (since the first time your browser rendered and the time the JavaScript is done could take a while). So ussually this method is not preferred (though looks better than the first for non-js/js disabled browsers).
I am working on a simple Cordova app with about 4 page types and I am trying to think through which is the better way to handle the inner HTML templates.
Hidden HTML hard coded into the HTML files that is hidden and populated/revealed by my JS.
Using a JS template system and appending and removing from the DOM.
I feel that appending all that to the DOM for a page is inefficient when I could just update the sections that change. But perhaps an append is lightweight enough where I shouldn't worry about it.
There are a number of ways you can do it. In terms of load on the browser. That is hard to say. From your question it is hard to know what is in these pages, what are you displaying, is it live data, static html etc.
When you first plot out an app, if you are from the old class of building multiple page websites, it can be a little concerning as to how well your app/page will run with all those pages crammed in to one, and all that data plus code.
The answer is, amazingly well. If done properly in modern browsers, and for example Ipads the app will run to near native performance.
The options you have are
Map all the pages into one HTML document. Hide each page content using css display:none, flip them into view using css animation, fading or just display:block.
Use a javascript routing library to map urls to blocks of code that deal with each page, this makes mapping out your app much easier, and means that buttons can just link to your pages, like a real website. see http://projects.jga.me/routie/
Building all the page templates into one page can make it hard to code, as the page becomes enormous, consider breaking the inner content of each page into separate files, you can then give each page holder a url and use a small xhr request to load the page on-the fly, once loaded you can cache it into memory or even local-storage, depending on whether you remove it when it is closed or keep it hidden.
In my experience you can put an enormous number or nodes into one page and have very little speed drop, bear in mind if you use something like jquery and do a lot of $(".page > .page1 > .items li") your going to have a slow app.
Tips
Use element ID's everywhere document.getElementById(..) is 100's of times faster in a loop that $(...)
cache elements when you find them, if you need them later store them in a memory cache.
keep for loop inner code to a minimum.
use a decent click touch libary like http://hammerjs.github.io/ and delegate all the events of the body tag or at least on each page.
If you need to touch the server, load data, think dom first, device second server later. A good app is a responsive app, that responds to the user instantly.
I know this has been posted a while ago, but for the sake of the users I am going to add my answer.
I completely agree with MartinWebb but my answer will shed some light on the results of his options. I am currently working on a similar project. Please note that this answer pertains to cordova (previously called phonegap) specifically. My app has about 5 pages with +-20 different components (input's, div's, h1's, p's, etc.). This is what i tried and the result of each:
jQuery was my first option, mainly because it is easy to use and reduces the amount of code required to accomplish a said goal. Result: First time I tried this approach I though I would spice it up with animations and transformations. The result of this was a very unresponsive app. I removed the animation and transformation, however due to the nature of my application I required multiple dynamically added components and jQuery just wasn't up for the task.
Css display:none and visible:hidden was my next option. I used javascript's dom to display certain div's. Result: This works if your not planning on switching many div shortly after one another eg. a simple menu. It quickly became apparent that this wasn't going to work. Also this does not eliminate my need for the dom. Remember document.getElementById('menu').style.display = "none"; is still part of the dom. This as a solution, for me, is poor. There is a reason that var menu= document.createElement('div'); is part of the language. Which brings me to my last option.
Building a page 90% on javascript's dom was my last option. Logically I could not see how 600 lines of code cold trump one .innerHTML or .style.display = "block"; but it did. Result: It was by far the most responsive of all the solutions.
I'm not saying that all webpages should be coded with dom appending, but as I stated previously, for a cordova app of a few pages (<6), with a few components a javascript dom appending approach would be best. It takes longer to code, but you will be rewarded with control and efficiency. I would suggest coding the backbone of your app in html and populating and controlling with javascript's dom.
Best of luck.
The first option, <div>s with display:none; would be more efficient by a small margin, but you can get the best of both worlds by compiling your JavaScript and templates together into a single file using something like browserify or require.js.
I have a long web page (vertically)
which can be thought of having 40 pages.
each page is divided by a hr element like this:
and has the same height: 860px.
I would like to transform each 'page' in that html in a jpg.
In an automated way of course.
Can somebody suggest how ?
This isn't an easy problem to solve because for one, different browsers may render the page slightly differently. So how important is it that the table looks exactly like it does on the webpage?
It's more common to convert HTML pages to PDF, for printing purposes or email attachments. There are many libraries to do this (but they're all a bit meh), I've used TCPDF with some success.
You may either
create an image of the whole page, then use some image library to split the hrs
or inject some javascript into your page and use it to hide everything but one single page, then take a screenshot individually.
Try wkhtmltoimage, which uses a headless webkit browser to generate images of HTML pages. Manual
Alternatively, there's browsershot's screenshot factory, which I haven't tried out but will probably do the job. However, it may require a bit of tweaking.
Then there's crazy things like HTML parsers written in JS, but I don't think they're any use in this case. Just to mention that.
So, I've written a little javascript widget. All a user has to do is paste a script tag into the page, and right below it I insert a div with all of the content the user has requested.
Many sites do similar things, such as Twitter, Delicious and even StackOverflow.
What I'm curious about is how to test this widget to make sure that it will work properly on everyone's webpage. I'm not using an iframe, so I really want to make sure that this code will work when inserted most places. I know it looks the same in all browsers.
Suggestions? Or should I just build one hundred web pages and insert my script tag and see if it works? I would hope there is an easier way than that.
Once you have confirmed that your javascript works cross-browser in a controlled environment, here are some things that might cause problems when used on an actual website:
CSS
You're using a CSS class that is already being used (for a different purpose) by the target website
You're using positioning that might interfere with the site's CSS
The elements you are using are being styled by the website's CSS (you might want to use some sort of "reset" CSS that applies only to your widget)
HTML
You're creating elements with the same id attribute as an element that already exists on the website
You're specifying a name attribute that is already being used (while name can be used for multiple elements, you may not be expecting that)
Javascript
What is the expected behaviour without Javascript enabled? If your script creates everything, is it acceptable for nothing to be present without JS?
At very basic you should make sure your widget works for following test-cases. I am sure then it will work on all web-pages -
http/https: There should not be any warning for HTTPS pages for unencrypted content.
<script> / <no-script>: What if JavaScript is disabled? Is your widget still visible?
What happens when third-party cookies are disabled? Does your widget still work?
Layout-box restrictions: When parent div element's size is less than your widget. Does your widget overflow the given size and destroys owners page?
By keeping all your Javascripts under a namespace (global object) with a very unique name, you should be pretty much OK. Also, you can simply use an anonymous function if you just want to print out something.
Similar question: How to avoid name clashes in JavaScript widgets