I'm using Python and plotly.io to create plotly charts and using the plotly write_html function to create an html page with the chart. I've been using the 'post_script' argument in the write_html function which allows me to add Javascript code to the html file, I am using this parameter to insert a hyperlink next to my plotly chart like so:
pio.write_html(fig, '/home/docs/plotly_test.html', post_script =
"el = document.querySelector('div.plotly-graph- div.js-plotly-plot'); " +
"a = document.createElement('a');"+
"a.href = 'https://google.com';"+
"a.target = '_blank';"+
"a.innerHTML = 'Link';"+
"el.appendChild(a);")
I am able to see my chart and hyperlink but upon clicking the hyperlink, I get an error: "Blocked opening 'https://google.com/' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set."
I have tried to dynamically force the iFrame attributes to allow popups
pio.write_html(fig, '/home/docs/plotly_test.html', post_script =
"el = document.querySelector('div.plotly-graph-div.js-plotly-plot'); " +
"var frames = document.getElementsByTagName('iframe');"+
"for (var frame of frames) {"+
"frame.setAttribute('sandbox', 'allow-modals allow-orientation-lock
allow-pointer-lock"+ "allow-presentation allow-scripts allow-top-
navigation allow-popups');"+
"}"+
"a = document.createElement('a');"+
"a.href = 'https://google.com';"+
"a.target = '_blank';"+
"a.innerHTML = 'Link';"+
"el.appendChild(a);")
I also tried to explicitly use a click handler so the browser would know that the click is coming from a user and allow the new window to be opened with this
"a.addEventListener('click', (event) => { window.open(a.href); event.preventDefault(); }, false);"
I've had no luck with this and would appreciate any help, thanks
Related
I know that when you manually copy and paste a slide from GSlides to GDocs, there is an option to 'Link to presentation', which allows the pasted image/object in GDocs to remain linked to the original presentation. When the original presentation is updated, a 'Refresh' button appears on the linked object in GDocs, and clicking it syncs the object with the original slide. However, doing this for a big presentation with dozens/hundreds of slides is tedious and time-consuming, so I am trying to write a script in GSlides, which automates copying and pasting linked thumbnails of slides into a GDocs file.
I have found a way to get an image of the thumbnail from GSlides to a GDocs file using Apps Script, but this thumbnail remains as a static image, and there is no way to 're-sync' it to reflect future changes in the presentation. I have also tried programmatically setting a 'LinkUrl' for the pasted image, and setting this Url to the Url which points to the exact slide which the image corresponds to, but this is not the same as manually pasting the slide in, and doesn't link it in the same way - the image still remains static.
This is my Apps Script code which does what I've described above:
function exportSlideImages(presentationId) {
let presentation = SlidesApp.openById(presentationId);
let doc = DocumentApp.create('Synced doc');
presentation.getSlides().forEach(function(slide, i) {
let thumbnail = Slides.Presentations.Pages.getThumbnail(presentationId, slide.getObjectId(), {
'thumbnailProperties.thumbnailSize': 'SMALL'});
let response = UrlFetchApp.fetch(thumbnail.contentUrl);
let blob = response.getBlob();
blob.setName('slide' + (i + 1) + '.png');
let url = SlidesApp.getActivePresentation().getUrl();
let sldId = SlidesApp.getActivePresentation().getSlides()[i].getObjectId();
url = url + '/edit#slide=id.' + sldId;
doc.getBody().insertImage(i,blob).setLinkUrl(url);
});
}
function test() {
exportSlideImages(SlidesApp.getActivePresentation().getId())
}
I am working on a web application that requires the user be able to run a report and have it automatically display the print dialog on the client machine for printing.
I have got that all working fine.
When the user clicks the print button an RDLC LocalReport is generated and returned as a pdf document with the assistance of iTextSharp in a new window/form and the print dialog is displayed.
I would like to be able to automatically close the form after the user either prints or cancels from the print dialog.
The aspx is currently as below (slightly stripped down version):
<body>
<form id="form1" runat="server">
<div>
<iframe id="frmPrint" name="IframeName" width="500" height="200" runat="server"> </iframe>
</div>
</form>
</body>
The code within the aspx.cs:
FileStream LFileStream = new FileStream(HttpContext.Current.Server.MapPath(Session[LReportNameSrcString].ToString()), FileMode.Create);
LFileStream.Write(LResult, 0, LResult.Length);
LFileStream.Close();
//Open existing PDF
Document LDocument = new Document(PageSize.A4);
PdfReader LPdfReader = new PdfReader(HttpContext.Current.Server.MapPath(Session[LReportNameSrcString].ToString()));
//Getting a instance of new PDF writer
PdfWriter LPdfWriter = PdfWriter.GetInstance(LDocument, new FileStream(HttpContext.Current.Server.MapPath(Session[LReportNameString].ToString()), FileMode.Create));
LDocument.Open();
PdfContentByte LPdfContentByte = LPdfWriter.DirectContent;
int LPageNumber = 0;
int LNumberOfPages = LPdfReader.NumberOfPages;
//Add Page to new document
while (LPageNumber < LNumberOfPages)
{
LDocument.NewPage();
LPageNumber++;
PdfImportedPage LPdfImportedPage = LPdfWriter.GetImportedPage(LPdfReader, LPageNumber);
LPdfContentByte.AddTemplate(LPdfImportedPage, LLocalReport.GetDefaultPageSettings().Margins.Left, LLocalReport.GetDefaultPageSettings().Margins.Top);
}
//Attach javascript to the document
//PdfAction LPdfAction = PdfAction.JavaScript("alert('loaded');parent.beginPrint();\r", LPdfWriter);
PdfAction LPdfAction = PdfAction.JavaScript("this.print();\r", LPdfWriter);
LPdfWriter.AddJavaScript(LPdfAction);
LDocument.Close();
//Attach pdf to the iframe
frmPrint.Attributes["src"] = Session[LReportNameString].ToString();
I have tried various methods using JavaScript to close the window but have been so far unsuccessful.
Any ideas would be greatly appreciated.
I found the solution myself in the end.
Using some code I found elsewhere for handling messages from the PDF document. This enabled me to add a listener for the PDF printed event and fire a message at the host container which can be picked up by the JavaScript.
In the ASPX:
// Acrobat JavaScript event handler to handle messages returned from Acrobat document
function messageFunc(messageArray) {
window.close();
}
// Waits until the HTML objects ready / loaded state has been reached
// then add a listener for JavaScript messages being returned from Acrobat document
function loadListener() {
var pdfObject = document.getElementById("pdfObj");
if (typeof pdfObject.readyState === 'undefined') { // ready state only works for IE, which is good because we only need to do this for IE because IE sucks in the first place
pdfObject.messageHandler = { onMessage: messageFunc };
return;
}
if (pdfObject.readyState == 4) {
pdfObject.messageHandler = { onMessage: messageFunc };
} else {
setTimeout(loadListener, 500);
}
}
// Wait until main HTML document has loaded then call function to set up JavaScript event listeners
jQuery(document).ready(function() {
loadListener();
});
In the Code behind:
// Add event listener to detect when the print has begun then return a message (in this case an empty string) to the browser
// window to be picked up by a JavaScript event listener which can then close the window
const string LPostMessageString = "try { this.hostContainer.postMessage(['']); } catch(e) {app.alert(e.message);}";
LPdfAction = PdfAction.JavaScript(LPostMessageString, LPdfWriter);
LPdfWriter.SetAdditionalAction(PdfWriter.DID_PRINT, LPdfAction);
This works well apart from if the user clicks cancel in the print dialog, of which I found no way to detect.
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!
For my first JavaScript application I am building a widget based designer, and use a variety of widgets based on SVG included in the main HTML body with object tags. I'm trying to associate a bootstrap tooltip when the user clicks on the widget object, however I'm getting strange errors that don't crop up when using tooltips on other non object HTML elements.
As an object tag swallows mouse events it's not possible to trigger a tooltip with a hover and the only combination I can get to work to show the tooltip is the following code (nothing else works, bootstrap complains about ):
document.getElementById(widgetName).setAttribute("title", param0);
setTimeout(function () {
$("#" + widgetName).tooltip("show");
}, 1); // attribute needs to be set after the next tick so the DOM is refreshed.
setTimeout(function () { $("#" + widgetName).tooltip("hide"); }, 2000); // 2 sec delay before hiding
This code shows the tooltip but errors out with Unable to get property 'originalTitle' of undefined or null reference in IE10 after the 2 second timeout to hide the tooltip. I can't use tooltip object options (eg. the delay option) as I get the same error. Same problem in Chrome although Chrome does not report the error (no hiding though).
I'm sure it has something to do with trying to use tooltips on object tags as tooltips work normally otherwise. However I'm fairly new to JavaScript so let me know if I'm doing something dumb, and the bootstrap/Jquery code is too complex for me to trace the error.
Using: HTML5, IE10, latest twitter bootstrap, visual studio 2012 web
Thanks for any help / pointers.
UPDATE: Added code that inserts the object into the DOM
var objWidget = document.createElement("object");
objWidget.type = "image/svg+xml";
objWidget.data = "widgets/" + widgetFile + "." + widgetExt // location of widget
objWidget.className = "widget"
var widgetName = "objWidget" + widgetNum;
targetDiv = "widgetContainer"
objWidget.id = widgetName;
document.getElementById(targetDiv).appendChild(objWidget); // Add to Div
var objID = document.getElementById(widgetName);
objID.addEventListener("load", function () { // access properties once the file is loaded
var objDoc = objID.contentDocument;
objDoc.addEventListener("dragstart", drag_start, false);
objDoc.addEventListener("dragover", drag_over, false)
objDoc.addEventListener("drop", drop, false)
objDoc.getElementById("widget").setAttribute("data-widgetName", widgetName); // set a data attribute on the SVG that points to the parent object as object that created the event isn't recorded in the event.currentTarget
objID.setAttribute("draggable", "true")
objID.style.setProperty("position", "absolute");
objID.style.setProperty("left", objLeft + "px");
objID.style.setProperty("top", objTop + "px");
objID.style.setProperty("z-index", widgets[widgetNum].zOrder);
objDoc.defaultView.loaded(widgetName); // run widget startup routine only if it isn't a new widget
objDoc.defaultView.addEventListener("click", widgetClick, false);
objDoc.defaultView.addEventListener("dblclick", widgetDblClick, false);
}, false);
i test your code (add the tooltips to the svg tag) see: http://bootply.com/64598 FF and chrome don't have a problem
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.