HTML5 / JS - preProcess of uploaded html page and simulate pagebreaks - javascript

I'm making a html-5 based report generator. I created a button to upload a [HTML] page containing multiple paragraphs and tables, which is continuous.
Now my task is to display the whole contents into separated a4-sized pages, just like in Microsoft Word.]
This is the sketch: >>>LINK<<<
Here are part of my codes.
function xx (){
var fi = document.getElementById('fi').files[0];
reader.onload = function (e){
var reader = new FileReader();
var inner ="";
inner += this.result;
inn.innerHTML ="<center><div class='bg' id='0'><div id='testmain'>"+inner+"</div></div></center>";
}
reader.onerror = function (e){
dd.innerHTML = "error<br>";
}
reader.readAsText(fi);
}
After displaying the result of pages, users can click a specific part of the paper, just like a paragraph, then a pagebreak is created and the pages changes, the remaining content are pushed starting from top of next page.
Could you please give me some ideas about how to realize it?

Instead of using comments as chat to present my suggestion, here's my answer:
I once tried to do such a thing, back in html4. Here's the logic I was using. Create a div that has the exact size of your page CONTENT (after margins and all) put all your content in it and cycle through its direct children. If the current child's bottom is lower than his parent, take it and all the following children and put them in a new div CONTENT. Rinse and repeat.
For this, you will need to calculate the height of the container and cross-check it against the offset+height of the elements. My vanillaJS is a bit rusty as for browser specifics and all... So I will display the logic using jQuery but most of it can easily be made in pure JS. The code will assume that we have a div.page that has the right CSS to make it exactly the size of a content page, and that will not resize to content (overflow:hidden) and the document will contain one of those div with all the content of what should be in the pages...
$(document).ready(function(){
var $page = $('div.page');
var newPage = true;//To track if we loop
while(newPage){
newPage = false;
$page.children().each(function(){
if($(this).offset().top+$(this).outerHeight() > $page.offset().top+$page.height()){
$page = $('<div>').addClass('page').appendTo('body');
$(this).nextAll().appendTo($page);
$(this).prependTo($page);//Don't forget the element too.
newPage = true;
}
});
}
});

Related

Reloading a DIV's image and class by Javascript on click of separate DIV.

The code I’m working with is too long to post, so I’ve made a fiddle here: http://jsfiddle.net/Emily92/5b72k225/
This code takes a random image and cuts it up into a number of pieces depending on the class that is applied in the div which contains the image.
When the page loads, a random image is selected from the array and the class is applied to it, what I’m trying to do is create a separate div, which when clicked on will reload the div containing the image. The result I’m looking for is for the image to be replaced by a new random image with the class applied to it.
Right now, the only way I can make a new image appear in the div is to reload the entire page, ideally this would be achieved by just having the div reload instead of all the other page elements reloading too.
I haven’t been able to do this so far but have received some help on here on how to reload an image and class on click of a div, lines 980-1018 of the Javascript code in the jsfiddle is the current attempt at achieving this, but solving this problem seems much more complicated as the image is being manipulated by the Javascript code, so perhaps this needs to also be reloaded at the same time as the new randomised image is selected?
This is the current attempt at solving this problem:
$(function() {
var imageArray = [
'http://www.webdesignhot.com/wp-content/uploads/2009/10/CatsVectorImage.jpg',
'http://www.costume-works.com/images/halloween_cat_in_witch_hat.jpg',
'http://onthewight.com/wp-content/2013/04/sooty-ryde.jpg'];
reloadImages(imageArray);
$('#reload').on('click',function(){
$( "#masterdiv img[id^='div']" ).each(function(index){
$(this).removeClass("jqPuzzle jqp-r"+(index+3)+"-c"+(index+3)+"-SCN");
$(this).fadeOut( "slow", function() {
if(index==0) {
reloadImages(imageArray);
}
$(this).addClass("jqPuzzle jqp-r"+(index+3)+"-c"+(index+3)+"-SCN");
$(this).fadeIn();
});
});
});
});
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function reloadImages(array){
shuffleArray(array);
for(var i=0;i<3;i++){
// places the first image into all divs
document.getElementById('div'+(i+1)+'id').src=array[0];
}
}
I’ve written more details on the issue in the html section of the jsfiddle. I'd really appreciate any advice in solving this and thank you for any help in advance!
The plugin reads the images' src before page load, takes them and then generates the puzzle. As such, you can not just update the images as they're not there anymore. So you'd have to clear the divs under each difficulty classes (easyDiv,mediumDiv,hardDiv), append a new <img> under each div then calls / reload the plugin. Updated code in : http://jsfiddle.net/5b72k225/6/
Changes I've made:
Separate old reloadImages into initImages and reloadImages. initImages is called in the beginning, while reloadImages is called when reloading.
Created new function makePuzzle by taking out the intialization of the plugin from $(document).ready() block, so makePuzzle can be called after reloading new image.
The new $(document).ready() block now initializes the images and attaches click event handler to the button. When clicked, divs are emptied, new <img>s inserted and plugin is called.

Iframe nomenucontext - Modify img tag after creation

Hi I am adding a iframe dynamically, It displays an image from a server. I need to disable the context menu for this item. In chrome I can inspect element and if I add oncontextmenu="return false" I do get the wanted affect. However I am unable to do this while the page is generated. Here is an example of the working html.
However I can not reproduce this when i frame is being created. Here is my code.
$(window).scrollTop(0);
$('#secVerify').show();
$("#popWaitLoad").modal("hide");
imgLoading.hide();
dvIframe.empty();
//else load deposit data into interface
$("#spanType").text(deposit.DepositType);
$("#spanReference").text(deposit.Reference);
$("#spanAmount").text("R " + deposit.Amount.toFixed(2));
$("#spanDate").text(deposit.DateCreatedOffsetS);
imageID = deposit.Deposit_Doc_imageID;
var url = imageUrl + '/' + deposit.Deposit_Doc_imageID + '/false';
var imgFrame = document.createElement("iframe");
imgFrame.src = url;
imgFrame.frameBorder = '0';
imgFrame.scrolling = 'no';
imgFrame.width = '100%';
imgFrame.height = '100%';
imgFrame.align = 'middle';
imgFrame.id = "iframeImg";
dvIframe.append(imgFrame);
I have tried examples like.
$("#iframeImage").contents().find("img").attr("oncontextmenu", 'return false');
$('#iframeImage img').on('contextmenu', function (e) {
e.stopPropagation();
// Your code.
return false;
});
But because the img element seems to be only created is done after page load it seems to not work. I know disabling the the menu will not help much and I have explained all the other methods of obtaining the image that is still available but the client really wants this.
I have added nocontextmenu to the body tag and it works everywhere except for the iframe.
So let me clarify, My iframe is working like it should however I would like to disable the right click aka context menu on the specific iframe.
I have used setAttribute to set the attributes and targeted a container to appendChild.
function example(){
var target = document.getElementById('container');
var element = document.createElement('img');
element.setAttribute('src', 'http://gopalshenoy.files.wordpress.com/2011/04/product_demos.jpg');
//element.setAttribute('width','100%');
//element.setAttribute('height','100%');
element.setAttribute('id','iframeImage');
element.setAttribute("oncontextmenu","return false;");
target.appendChild(element);
}
// Demo-Snippet use.
window.onload=example;
<!-- Demo Snippet use -->
<div id="container"></div>
If you build more than one element using this function you might find further issues due to duplicated ID's.
ID's are used to target a specific element 'one of' so if you want to build multiple elements I would recommend giving them unique ID's.
I hope this helps. Happy coding!

How to properly scroll IFrame to bottom in javascript

For a mockup-webpage used for research on interaction on websites, I created a mockup message-stream using JavaScript. This message stream is loaded in an IFrame and should show images at pre-set intervals and scroll to the bottom of the page after placing a new image at the bottom of the page. Getting the images to appear is working quite well with the provided script. However, both Chrome and IE seem to have trouble scrolling the page to the bottom. I would like to scroll to the bottom of the page as soon as the image is attached, but have for now added a 5 ms delay because that seemed to work sometimes. My questions are:
Is it okay to use document.body.scrollHeight for this purpose?
Can I make the scroll occur directly, or do I need a small interval before scrolling?
How to make the code scroll to the bottom of the IFrame directly after adding an image?
The following functions are used and trypost() is started onLoad:
function scrollToBottom(){
window.scrollBy(0,document.body.scrollHeight);
}
function trypost(){
point = point + 1;
if(point < interval.length){
//create and append a new image
var newImg = document.createElement("IMG");
newImg.src = "images/"+images[point]+".png";
document.getElementById('holder').appendChild(newImg);
//create and append a return
var br = document.createElement("br");
document.getElementById('holder').appendChild(br);
//time scroll to bottom (after an arbitrary 5 seconds)
var stb = window.setTimeout(scrollToBottom, 5);
//time next post
var nextupdate = interval[point]*400;
var tp = window.setTimeout(trypost, nextupdate);
}
}
My script section contains at least the following variables:
var point = -1;
var interval = [10, 10, 15];
var images = ["r1", "a1", "r2"];
This questions is a continuation of the project described in How to proper use setTimeout with IE?
To answer one of your questions, document.body.scrollHeight is appropriate for this purpose, but not if you're actually calling for document. That'll give you the scroll height of the document the iFrame is in, not the iFrame's document. The iFrame's document can be called upon by [insert variable for iFrame here].contentDocument.
Here's how I did it (and by that, I mean I tested it out with my own stuff to make sure it worked):
let i = document.querySelector('iframe')
i.contentWindow.scrollTo(0, i.contentDocument.body.scrollHeight);
That being said, the other answer by Thomas Urban will also work most of the time. The difference is only if your page has a really long scroll height. Most pages won't be longer than 999999 (for all I know that's impossible and that's why they chose that number), but if you have a page longer than that, the method I showed here would scroll to the bottom and the 999999 would scroll to somewhere not yet at the bottom.
Also note, if you have more than one iFrame, you're gonna want to query it in a different way than I did, like by ID.
Scrolling to bottom is always like scrolling to some ridiculously large top offset, e.g. 999999.
iframe.contentWindow.scrollTo( 0, 999999 );
In addition see this post: Scrolling an iframe with javascript?
If scrolling occurs too early it's probably due to images not being loaded yet. Thus, you will have to scroll as soon as added image has been loaded rather than on having placed it. Add
newImg.onload = function() { triggerScrolling(); };
after creating newImg, but before assigning property src.
If several events are required to trigger scrolling you might need to use some "event collector".
function getEventCollector( start, trigger ) {
return function() {
if ( --start == 0 ) { trigger(); )
};
}
You can then use it like this:
var collector = getEventCollector( 2, function() { triggerScrolling(); } );
newImg.onload = collector;
window.setTimeout( collector, 100 );
This way triggerScrolling() is invoked after 100ms at least and after image has been loaded for collector has to be invoked twice for triggerScrolling() being invoked eventually.

Resize a dynamically generated iframe

I have a report generated by Oracle Apex (A UI tool operating against the Oracle database). I have customized it to have a hyperlink on each record, which when clicked opens a detail report in an iframe right under the current record. This, I am doing by using the Javascript insertRow method on the html table element (Condensed Javascript code below. Oracle APEX allows use of JS/Jquery)
var pTable= html_CascadeUpTill(t,'TABLE');
var myNewRow = pTable.insertRow(pTR.rowIndex+1);
var myNewCell = myNewRow.insertCell(0);
myNewCell.innerHTML = '<iframe src="detail report url" height="0"></iframe>';
In order to resize the height of the iFrame that is different for different detail records, I have the following code in the document).ready(function() of the page
$('iframe').load(function()
{
setTimeout(iResize, 1000);
}
function iResize()
{
// Iterate through all iframes in the page.
for (var i = 0, j = iFrames.length; i < j; i++)
{
var y=(iFrames[i].contentWindow || iFrames[i].contentDocument);
if (y.document)y=y.document;
var docHt = getDocHeight(y);
if (docHt) iFrames[i].height = docHt + "px";
}
}
);
Without the setTimeout call to iResize function, the iframe resize is not happening. But this setTimeout is adding a delay in the resized iframe to appear which I want to avoid. Is there a way to do this? All the related posts/articles I have seen online deal with iframes that are built into the page but not generated on-the-fly as in my case.
Let me know if you need more information. Please help. Thank you.
You should consider putting the details in a <div> block, then showing or hiding the <div> with JQuery. You can set dimensions for your block with CSS, or just let the content flow normally inside of the block. Sounds like a much simpler way to achieve the same effect.
The issue is that if you perform the resize too soon it will get the dimensions of the child document before it has been fully rendered, hence the use of a timer.
If your detail reports are other APEX pages that you control, then you could call the iResize function from the "Execute when page loads" section of the detail page:
parent.iResize();
That seems to work for me.
It sounds to me like the iframes don't even exist when the page first loads.
Instead of calling the iResize function on page load and then every second you could place the call to iResize in the code that creates the iframe.

How can we keep OpenX from blocking page load?

We're using OpenX to serve ads on a number of sites. If the OpenX server has problems, however, it blocks page loads on these sites. I'd rather have the sites fail gracefully, i.e. load the pages without the ads and fill them in when they become available.
We're using OpenX's single page call, and we're giving divs explicit size in CSS so they can be laid out without their contents, but still loading the script blocks page load. Are there other best practices for speeding up pages with OpenX?
We load our ads in iframes to avoid the problem you're having. We size div and the iframe the same, with the iframe pointing to a page which just contains the ad snippet (you can pass the zone and other required options as parameters to that page).
cheers
Lee
We lazy-load OpenX's code. Instead of putting the single-page call at the top of the page, we put it at the bottom. After the page has loaded, the call will get the banner data and a custom code will add the correct banners in the correct zones.
The code below requires a proper DOM. If you have jQuery, DOMAssistant, FlowJS, etc, the DOM should be fixed for you.
This code will work with normal banners with images, flash, or HTML content. It may not work in some cases like when using banners from external providers (adform, etc). For that you may need to hack the code a bit.
How to use it?
add your SinglePageCall code towards the end of your HTML code
add this code under the SPC code.
after half a second or so, your OpenX code should be ready, and the code below will put the banners within the specified DIVs.
Oh, yeah, you need to add to your HTML code some DIVs as place holders for your banners. By default I have these banners set with CSS class "hidden" which totally hides the DIVs (with visibility, display, and height). Then, after the banner in a given DIV is successfully loaded, we remove the hidden class and the DIV (and the banner within) become visible.
Use at your own risk! :) Hope it helps
(function(){
if (!document || !document.getElementById || !document.addEventListener || !document.removeClass) {
return; // No proper DOM; give up.
}
var openx_timeout = 1, // limit the time we wait for openx
oZones = new Object(), // list of [div_id] => zoneID
displayBannerAds; // function.
// oZones.<divID> = <zoneID>
// eg: oZones.banner_below_job2 = 100;
// (generated on the server side with PHP)
oZones.banner_top = 23;
oZones.banner_bottom = 34;
displayBannerAds = function(){
if( typeof(OA_output)!='undefined' && OA_output.constructor == Array ){
// OpenX SinglePageCall ready!
if (OA_output.length>0) {
for (var zone_div_id in oZones){
zoneid = oZones[zone_div_id];
if(typeof(OA_output[zoneid])!='undefined' && OA_output[zoneid]!='') {
var flashCode,
oDIV = document.getElementById( zone_div_id );
if (oDIV) {
// if it's a flash banner..
if(OA_output[zoneid].indexOf("ox_swf.write")!=-1)
{
// extract javascript code
var pre_code_wrap = "<script type='text/javascript'><!--// <![CDATA[",
post_code_wrap = "// ]]> -->";
flashCode = OA_output[zoneid].substr(OA_output[zoneid].indexOf(pre_code_wrap)+pre_code_wrap.length);
flashCode = flashCode.substr(0, flashCode.indexOf(post_code_wrap));
// replace destination for the SWFObject
flashCode = flashCode.replace(/ox\_swf\.write\(\'(.*)'\)/, "ox_swf.write('"+ oDIV.id +"')");
// insert SWFObject
if( flashCode.indexOf("ox_swf.write")!=-1 ){
eval(flashCode);
oDIV.removeClass('hidden');
}// else: the code was not as expected; don't show it
}else{
// normal image banner; just set the contents of the DIV
oDIV.innerHTML = OA_output[zoneid];
oDIV.removeClass('hidden');
}
}
}
} // end of loop
}//else: no banners on this page
}else{
// not ready, let's wait a bit
if (openx_timeout>80) {
return; // we waited too long; abort
};
setTimeout( displayBannerAds, 10*openx_timeout );
openx_timeout+=4;
}
};
displayBannerAds();
})();
OpenX has some documentation on how to make their tags load asynchronously:
http://docs.openx.com/ad_server/adtagguide_synchjs_implementing_async.html
I've tested it, and it works well in current Chrome/Firefox.
It takes some manual tweaking of their ad code. Their example of how the ad tags should end up:
<html>
<head></head>
<body>
Some content here.
Ad goes here.
<!-- Preserve space while the rest of the page loads. -->
<div id="placeholderId" style="width:728px;height:90px">
<!-- Fallback mechanism to use if unable to load the script tag. -->
<noscript>
<iframe id="4cb4e94bd5bb6" name="4cb4e94bd5bb6"
src="http://d.example.com/w/1.0/afr?auid=8&target=
_blank&cb=INSERT_RANDOM_NUMBER_HERE"
frameborder="0" scrolling="no" width="728"
height="90">
<a href="http://d.example.com/w/1.0/rc?cs=
4cb4e94bd5bb6&cb=INSERT_RANDOM_NUMBER_HERE"
target="_blank">
<img src="http://d.example.com/w/1.0/ai?auid=8&cs=
4cb4e94bd5bb6&cb=INSERT_RANDOM_NUMBER_HERE"
border="0" alt=""></a></iframe>
</noscript>
</div>
<!--Async ad request with multiple parameters.-->
<script type="text/javascript">
var OX_ads = OX_ads || [];
OX_ads.push({
"slot_id":"placeholderId",
"auid":"8",
"tid":"4",
"tg":"_blank",
"r":"http://redirect.clicks.to.here/landing.html",
"rd":"120",
"rm":"2",
"imp_beacon":"HTML for client-side impression beacon",
"fallback":"HTML for client-side fallback"
});
</script>
<!-- Fetch the Tag Library -->
<script type="text/javascript" src="http://d.example.com/w/1.0/jstag"></script>
Some other content here.
</body>
</html>
Following #Rafa excellent answer, i'm using this code to invoke OpenX banners after the page loads. I'm using jquery as well and had to add a new replace call for the "document.write" that flash banners use, and replacing it with "$('#"+ oDIV.id +"').append" instead. I'm using a custom "my_openx()" call, to replace "OA_show()". My banners area called by the zone_id and are wrapped inside a div, like this:
<div id="openx-4"><script>wm_openx(4);</script></div>
It's working :)
<script type="text/javascript">
$is_mobile = false;
$document_ready = 0;
$(document).ready(function() {
$document_ready = 1;
if( $('#MobileCheck').css('display') == 'inline' ) {
$is_mobile = true;
//alert('is_mobile: '+$is_mobile);
}
});
function wm_openx($id) {
if($is_mobile) return false;
if(!$document_ready) {
setTimeout(function(){ wm_openx($id); },1000);
return false;
}
if(typeof(OA_output[$id])!='undefined' && OA_output[$id]!='') {
var flashCode,
oDIV = document.getElementById('openx-'+$id);
if (oDIV) {
// if it's a flash banner..
if(OA_output[$id].indexOf("ox_swf.write")!=-1) {
// extract javascript code
var pre_code_wrap = "<script type='text/javascript'><!--// <![CDATA[",
post_code_wrap = "// ]]> -->";
flashCode = OA_output[$id].substr(OA_output[$id].indexOf(pre_code_wrap)+pre_code_wrap.length);
flashCode = flashCode.substr(0, flashCode.indexOf(post_code_wrap));
// replace destination for the SWFObject
flashCode = flashCode.replace(/ox\_swf\.write\(\'(.*)'\)/, "ox_swf.write('"+ oDIV.id +"')");
flashCode = flashCode.replace(/document.write/, "$('#"+ oDIV.id +"').append");
// insert SWFObject
if( flashCode.indexOf("ox_swf.write")!=-1 ) {
//alert(flashCode);
eval(flashCode);
//oDIV.removeClass('hidden');
}// else: the code was not as expected; don't show it
}else{
// normal image banner; just set the contents of the DIV
oDIV.innerHTML = OA_output[$id];
//oDIV.removeClass('hidden');
}
}
}
//OA_show($id);
}
</script>
I was looking for this to load advertising from my openX server only when the advertising should be visible. I'm using the iFrame version of openX which is loaded in a div. The answer here put me on my way to solving this problem, but the posted solution is a bit too simple. First of all, when the page is not loaded from the top (in case the user enters the page by clicking 'back') none of the divs are loaded. So you'll need something like this:
$(document).ready(function(){
$(window).scroll(lazyload);
lazyload();
});
also, you'll need to know what defines a visible div. That can be a div that's fully visible or partially visible. If the bottom of the object is greater or equal to the top of the window AND the top of the object is smaller or equal to the bottom of the window it should be visible (or in this case: loaded). Your function lazyload may look like this:
function lazyload(){
var wt = $(window).scrollTop(); //* top of the window
var wb = wt + $(window).height(); //* bottom of the window
$(".ads").each(function(){
var ot = $(this).offset().top; //* top of object (i.e. advertising div)
var ob = ot + $(this).height(); //* bottom of object
if(!$(this).attr("loaded") && wt<=ob && wb >= ot){
$(this).html("here goes the iframe definition");
$(this).attr("loaded",true);
}
});
}
Tested on all major browsers and even on my iPhone, works like a charm!!

Categories

Resources