I'm working on a WYSIWYG editor and experiencing a problem with the image handling using execCommand, the following is a simplified example of my page structue:
<div id="buttons_panel"><input id="img_submit" type="button"/></div>
<div id="img_handle" style="display:none;">
<div id="ajax_upload"></div> /* AJAX IMG UPLOAD FROM */
<div id="images"></div> /* DIV FOR ALL UPLOADED IMAGES DISPLAY */
</div>
<iframe id="text_content"></iframe>
the simplified JavaScript I'm using, basically showing the hidden div uploading an image with ajax and displaying all uploaded images:
<script>
$("#img_submit").click(function(){
$("#img_handle").show();
/* HANDLE IMG UPLOAD WITH AJAX AND RELOAD ALL IMAGES INTO #images DIV */
});
</script>
Now, all of this works just fine - as soon as the new image is uploaded with ajax I append it to the images div:
function loadImgs(){
var loadImages="PATH/TO/URL";
$.post(loadImages, {request:"loadImages"}, function(response){
$("#images").append(response);
insert_img();
});
}
Then, on click on either of the results i run the following function:
function insert_img(){$(".img_insert").click(function(){
var frame = document.getElementById('text_content'); frame.document.execCommand('InsertImage',false,"../PATH/TO/IMG");
});}
Now, here is where the execCommand refuses to work in firebug i get: "getElementById("text_content").document UNDEFIEND"
Every other execCommand functions I run on that page (ex: italic Bold, font-color etc..) works, but here it doesn't, can some one please help me figure out a solution?
The standard way to get hold of the document object within an <iframe> element is via its contentDocument property rather than document. This isn't supported in some older browsers but in those you can use contentWindow.document instead.
So, the following will work in all browsers except those which do not support contentDocument or contentWindow, which in practice are not around today:
function getIframeDocument(iframeEl) {
return iframeEl.contentDocument || iframeEl.contentWindow.document;
}
function insert_img(){
$(".img_insert").click(function() {
var frame = document.getElementById('text_content');
getIframeDocument(frame).execCommand('InsertImage',false,"../PATH/TO/IMG");
});
}
Related
We have many animations generated by Google webdesigner which popups when user click on some td element.
I've found that the only way to add these animations is have a iframe, so we have a fixed iframe where we update src with these animations
Edit.cshtml:
<iframe id="popUpFrame"></iframe>
<script src="~/js/popUp/popUp.js"></script>
On end of this file we have several "apps" created by Google webdesigner (generated to html file)
Element with id 01 is td element which listen on click
// PopUps
let frame_elem = document.getElementById("popUpFrame")
//speedtest popup-01
let speedtest_elem = document.getElementById("01")
hoPopUp(frame_elem, speedtest_elem, "505px", "505px", "/images/PopUps/01.html")
popup.js file:
function hoPopUp(frame_elem, td_elem, width, height, file_path){
frame_elem.style.width = width
frame_elem.style.height = height
frame_elem.style.top = "50%"
frame_elem.style.left = "50%"
td_elem.addEventListener("click", function () { showIframe(frame_elem, file_path) })
td_elem.addEventListener("mouseout", function () { hideIframe(frame_elem) })
}
function showIframe(frame_elem, file_path) {
frame_elem.setAttribute("src", file_path)
frame_elem.classList.add("active")
}
function hideIframe(frame_elem){
frame_elem.classList.remove('active')
frame_elem.removeAttribute('src')
}
The google webdesigner html file is full of javascript code, but I dont know how to allow it. We've found out that Add blocker is blocking it so we create detection of add blocker by sending some fetch request to some add, but my colleague is using uBlocker where the detection mechanism is not working.
Question is, how to allow running the javascript inside the iframe. Why are the browser tools blocking javascript "downloaded" from my own website?
Thank you for help
uBlocker is doing some "cosmetic filtering", so add detection by sending some javascript fetch Request doesnt work...
Instead of trying detect browser's tool, we put a note to every webdesigner generated html code:
<body>
<div style="width: 100%; position:absolute; top:50%;">
<p style="display:flex; justify-content:center;">
Please disable add blocker and content filters on this site
</p>
</div>
If the javascript is allowed to run inside the iframe with the webdesigner html code, the animation will be over this note
I have this function to print a DIV.
Whenever the page is loaded and I click in a "Print" link I have, the DIV is shown to be printed without CSS.
If I close Chrome's print visualization page and click in the "Print" link again, the DIV has CSS applied.
Any ideas why?
Javascript
function printDiv(divId) {
var printDivCSSpre =
'<link href="/static/assets/vendor/sb-admin-2-1.0.7/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">' +
'<link href="/static/assets/vendor/sb-admin-2-1.0.7/dist/css/sb-admin-2.css" rel="stylesheet">' +
'<div style="width:1000px; padding-right:20px;">';
var printDivCSSpost = '</div>';
$('body').append('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
$("link").clone().appendTo($("#print_frame").contents().find("head"));
window.frames["print_frame"].document.body.innerHTML =
printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
var windowInstance = window.frames["print_frame"].window;
windowInstance.print();
}
HTML
<a id="print" href="#">
<i class="fa fa-print"></i> Print
</a>
<script>
$('#print').click(function () {
printDiv('report')
})
</script>
<div id="report" class="report">
<p># Generated Table#</p>
</div>
First click:
http://imgur.com/a/Go81Y
Closing the print preview page and clicking again in print
http://imgur.com/a/SCxJF
This happens because when you call your printDiv() function, css is also written using inner HTML and in this scenario CSS is not applied during first click because you wrote CSS to the elements even when they do not exist inside DIV.
The function to work as desired has to write DIV contents first and then CSS should be applied. I would say write css after contents of DIV or load on top of your HTML page and just write DIV contents.
Hope that helps.
Every thing is right just change the sequence. In browser debugger on first click it didn't show 'print_frame' in sources section while in second click it does (I am using chrome devtool).
So load in memory frame with css attributes during onload:
var windowInstance;
$(function(){
$('body').append('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
$("link").clone().appendTo($("#print_frame").contents().find("head"));
windowInstance = window.frames["print_frame"].window;
});
and onClick just append html
$('#print').click(function () {
var divId = 'report';
var printDivCSSpre ='<div id="printReportDiv" style="width:1000px; padding-right:20px;">';
var printDivCSSpost = '</div>';
window.frames["print_frame"].document.body.innerHTML = printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
windowInstance.print();
});
updated jsfiddle
Try this one. The problem mainly arises because the css has not been applied to the page when the print command is initiated. setTimeout is one way to solve it as others have mentioned but it is really not possible to predict how much delay you will need. Slow internet connections will require high delays before you fire the print statement. The following code, however, only fires the print event after the css has been properly applied to the iframe.
$('#print').click(function () {
if($("#print_frame").length == 0) {
$('#report').after('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
}
var $head = $("#print_frame").contents().find("head");
// for now for ease I will just empty head
// ideally you would want to check if this is not empty
// append css only if empty
$head.empty();
$.ajax({
url : "https://dl.dropboxusercontent.com/u/7760475/reports.css",
dataType: "text",
success : function (reports) {
// grab css and apply its content to the iframe document
$head.append('<style>'+reports+'</style>');
$.ajax({
url : "https://dl.dropboxusercontent.com/u/7760475/bootstrap.css",
dataType: "text",
success : function (bootstrap) {
// grab another css and apply its content to the iframe document
// there may be better ways to load both css files at once but this works fine too
$head.append('<style>'+bootstrap+'</style>');
// css has been applied
// clone your div and print
var $body = $("#print_frame").contents().find('body');
// empty for ease
// but later append content only if empty
$body.empty();
$("#report").clone().appendTo($body);
$('#print_frame').get(0).contentWindow.print();
}
});
}
});
});
Use inline CSS instead.
Reason: When we PRINT or save as PDF if fails to fetch external css Files, So we have to use Inline css.
edited your file please see: jsfiddle.net/ytzcwykz/18/
As other people mentioned it is hard to see your problem without seeing the working example of a problem, but just guessing from the code:
Browser is not able to load the CSS before your print() call.
Browser is not able to render the CSS before your print() call.
Keeping that in mind changing your JS function that way might do the trick
function printDiv(divId) {
$("link").clone().appendTo($("#print_frame").contents().find("head"));
window.frames["print_frame"].document.body.innerHTML =
printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
var windowInstance = window.frames["print_frame"].window;
setTimeout(function() {
windowInstance.print();
}, 0);
}
The idea behind this function is to let browser execute it's code after we added changed the HTML/CSS code in the window - see Why is setTimeout(fn, 0) sometimes useful?
WARNING: this approach is not tested for your particular problem, and it might also not work because we escape/leave the mouse-click call-stack, calling print() method might be not possible out of user-interaction stack.
UPDATE: after looking in the posted jsfiddle - my assumption was correct, the browser needs some time to load and render the CSS, that is why calling the print() right after changing iframe contents doesn't give the desired result. There are 3.5 ways to solve that:
Use events to identify when iframe's document and window has finished loading and rendering. I tried two approaches, and failed so far, need to read docs more carefully about when document and window are behiving during the loading sequence:
we can do that from outside of iframe, i.e. listen to events of iframe element and it's children
we can do that from inside of iframe, i.e. add little javascript snippet inside which will send a message to the parent window when loading is done.
Consider forming the print result different, how about print style-sheets? I.e. add one more style sheet with print-media query to the parent doc and just call print on it?
Consider forming an iframe which is already loaded and ready to be printed, but replace just the table contents inside it.
As others mentioned, The problem here is that the CSS files used are external resources and browser takes time to download and cache it locally. Once it is cached, it would serve faster and that's why it works fine from the second click.
As Anton mentioned, setTimeout is the key here! You may probably increase the timeout seconds to make that work. I tried setting it to 500ms and that worked,
setTimeout(function(){windowInstance.print();},500);
I show links to 240 images on a page. The real images are uploaded by users. I tried to avoid showing an empty image if users did not upload it yet. jQuery did not work for me because of conflicts, so I have to do it in pure JavaScript.
image(s) links:
<img class="photo240" src="http://www.example.com/i/%%GLOBAL__AuthorID%%/p/b01.jpg" onerror="imgError()">
My JavaScript:
function imgError()
{
alert('The image could not be loaded.');
var _aryElm=document.getElementsByTagName('img'); //return an array with every <img> of the page
for( x in _aryElm) {
_elm=_aryElm[x];
_elm.className="photo240off";
}
}
The style photo240off equals to display:none.
Right now, whenever an image misses, all the images are turned to style photo240off and I want only the missing image to be hidden. So there is something wrong with my script.
(the overall script works well, because I get the alert).
Use this to get the image with the error.
Change to:
onerror="imgError(this)"
Then the function can be:
function imgError(el) {
alert('The image could not be loaded.');
el.className = "photo240off";
}
You need to reference the image from your onerror call and change the class only for that one.
Something like this:
HTML
<img class="photo240" src="example.jpg" onerror="imgError(this)">
JS
function imgError(el) {
el.className="photo240off";
}
I am looking for a way to cancel image loading using javascript. I've looked at other questions and hiding them is not enough. Also, the rest of the page must load (window.stop() is out of the question).
The page that is being loaded is not under my control, only one thing is guaranteed - the first <script> on the page is my javascript (lightweight - no jquery).
I have tried setting all img sources to nothing, that did not help since the dom is created after the page is parsed, and all browsers have the same behavior - the img is loaded once it is parsed.
Not possible with modern browsers. Even if you alter the src attribute of image tag with JavaScript browsers still insist on loading the images. I know this from developing the Lazy Load plugin.
The only way I can see to stop images loading is to not have an src attribute present in the image itself, and using a custom data-* attribute to hold the location of the image:
<img data-src="http://path.to/image.png" />
Obviously this doesn't gracefully degrade for those (admittedly rare) JavaScript disabled browsers, and therefore requires a noscript fall-back:
<img data-src="http://path.to/image.png" />
<noscript><img src="http://path.to/image.png" /></noscript>
And couple this with a simple function to load the images when you, or your users, are ready for them:
/* simple demo */
function imagePopulate(within, attr) {
within = within && within.nodeType == 1 ? within : document;
attr = attr || 'data-src';
var images = within.getElementsByTagName('img');
for (var i = 0, len = images.length; i < len; i++) {
if (images[i].parentNode.tagName.toLowerCase() !== 'noscript') {
images[i].src = images[i].getAttribute(attr);
}
}
}
document.getElementById('addImages').onclick = function(){
imagePopulate();
};
JS Fiddle demo.
I can't be sure for all browsers, but this seems to work in Chrome (in that there's no attempt, from looking at the network tab of the developer tools, to load the noscript-contained img).
It can be done with webworkers. See the following example:
https://github.com/NathanWalker/ng2-image-lazy-load.
Stopping a web worker cancels the image loading in browser
Recalling the onload event:
window.onload=function(){
imgs = document.getElementsByTagName('img');
for(i = 0; i < imgs.length(); i++){
imgs[i].src = '#';
}
};
If you want to only cancel the loading of the image , you can use sємsєм's solution
but i do not think it will work by using an window onload event .
You will probably need to provide a button to cancel the image load. Also i suggest, instead of setting the src attribute to "#" , you can remove the src attribute itself using
removeAttribute()
[Make sure you disable the cache while testing]
You need a proxy.
Your script can redirect to another server using something like
location.replace('http://yourserver.com/rewrite/php?url='+escape(this.href));
perhaps you tell us why you want to cancel image loading and whose site you are loading on so we can come up with a better solution
If there is nothing on the page other than images, you could try
document.write('<base href="http://yourserver.com/" />');
which will mess with all non-absolute src and hrefs on the page.
UPDATE Horrible hack but perhaps this almost pseudo code (I am off to bed) will do someting
document.write('<script src="jquery.js"></script><div id="myDiv"></div><!-'+'-');
$(function() {
$.get(location.href,function(data) {
$("#myDiv").html(data.replace(/src=/g,'xsrc='));
});
})
The closest you can get to what you maybe want is to have a quickly loaded placeholder image (ie. low resolution version of your image) and a hidden image (eg. {display:none}) in which the large image gets loaded but not displayed. Then in the onload event for the large image swap the images over (eg. display:block for the large image display:none for the smaller). I also use an array (with their url), to reuse any images that have already been opened.
BTW if you open an image in a new webpage when it gets closed then the image loading will be cancelled. So maybe you can do something similar in a webpage using an iframe to display the image.
To close the iframe and therefore unload the image, remove the frame from the DOM
(another advantage is that browsers spawn another process to deal with iframes, so the page won't lock up while the image loads)
I'm running a Javascript replace function to replace standard images with class="replace-2x"on my jQuery Mobile site with Retina-quality images if the user is on a mobile device with Retina display. For example, on a Retina device, logo.png will be replaced with logo#2x.png. The JS function is here:
function highdpi_init() {
$(".replace-2x").each(function () {
var src = $(this).attr("src");
$(this).attr("src", src.replace(".png", "#2x.png").replace(".jpg", "#2x.jpg"));
});
}
$(".page").live('pageinit',function(event){
highdpi_init();
});
I'm now running into an issue where the replace function is running more than once. So for example, it replaces logo.png with logo#2x.png as the page is loading, but then as the page continues to load, it KEEPS replacing .png with #2x.png in the img src over and over so that the image tag ends up looking like this:
<img src="mobile/images/logo#2x#2x#2x#2x#2x#2x#2x#2x#2x#2x#2x.png" class="replace-2x" alt="logo" width="200">
How can I prevent this from replacing on a single img element more than once? Keep in mind, I will have multiple images on the same page, so the function will need to apply to all images, but only one time each.
The problem is surely that your 'pageinit' event is being called more than once. You can either follow MДΓΓ БДLL's idea (which won't work if images are dynamically added) or you can make your handler smarter so that it doesn't replace the src if it already was replaced
function highdpi_init() {
$(".replace-2x").each(function () {
var $this = $(this);
var src = $this.attr("src");
$this.attr("src", src.replace(".png", "#2x.png").replace(".jpg", "#2x.jpg"));
// Remove the class so it doesn't replace it again
$this.removeClass('replace-2x')
});
}
You don't need JS for this, you could do it in CSS only.
<link rel="stylesheet" media="only screen and (-webkit-min-device-pixel-ratio: 2)" href="/css/highdpi.css"/>
You could make your images look like
<img src="transparent.gif" class="logo-a" alt="logo" width="200" />
And in highdpi.css you could do
img.logo-a {
background-image: url('file#2x.png')
}
And in lowdpi.css
img.logo-a {
background-image: url('file.png')
}
Using .one() should work since it is just a binding and if you are using Jquery Mobile the way that is suggested it will be just fine. That is unless you are passing back the html from the server. In which case it would be a good idea to add an extra condition to make sure that the src doesn't already have #2x.png before replacing.
There is disappointingly little documentation on pageinit on the offical jQuery Mobile docs. So I'm going to speculate here. It looks like pageinit is used to fire events for when a specific DOM element has finished loading, since it may not have been loaded on the initial page load (deferred until needed). That being said, it may be that adding/altering images to the DOM element in question fires the pageinit again. Could you tag each updated image with something that says, 'hey, I've already been updated to 2x'? Something such as
$.data(targetimg, 'retinafied', true);
And then check for that value before replacing the src?