I'm creating my own Safari Extension which inserts 2 buttons into my DOM to improve the user experience on some websites.
I created an Extension using Safari Extension Builder. I created a script called end.js which is loaded after every finished HTTP request. In this script I check my DOM if a specific element exists and insert my buttons next to this element.
The buttons are created like this:
var headerElements = window.document.getElementsByClassName("headers");
if (headerElements.length > 0) {
var header = headerElements[0];
if (header.getElementsByClassName("button1").length == 0) {
var div = window.document.createElement("div");
div.setAttribute("class", "buttons-div");
var button1 = window.document.createElement("button");
button1.setAttribute("class", "button1");
button1.setAttribute("style", "width: 150px;");
button1.innerHTML = "allen folgen";
button1.onclick = function() {
alert("click button1");
};
div.appendChild(button1);
header.appendChild(div);
}
}
As soon as I press the button only an error message is displayed on the console:
onclick — end.js (Zeile 27) TypeError: alert is not a function. (In 'alert("button pressed")', 'alert' is undefined)
Why do I have access to all functions "outside" the onclick event, but as soon as the function is entered I can't access any of those functions? Even if I create my own function
function click() {
alert("test");
}
and set the button's onclick to this:
button1.onclick = click;
I get the same error message.
What am I doing wrong?
Related
I am trying to trigger an window open event such as "window.open" whenever the within the body of the document, the elements "P id" becomes true.
So when, within the body of the page, this ID happens to load:
<p id=newPlayListText>
"There is a new playlist that was sent to you, check it out here."
I can triggered the event of "window.open".
This is what i have and after inspecting it, its not flagging anything to debug and nothing happens...
//#test: check to see if the new playlist banner text pops up during ep.
window.onload = function () {
if(element.id = "nextPlaylistText") {
window.open("http://www.w3schools.com");
}
Please help
The window.onload hook is called when the page loads, but element is never defined. You'll need to assign the variable to element before using it:
var element = document.getElementById("newPlayListText");
There are two issues with your code. First as Litty correctly pointed out that element is never declared. Second you aren't comparing values within if block.
if(element.id = "nextPlaylistText") // required `===` or at-least `==`
P.S. some browsers may block this line window.open
window.onload = function() {
var p = document.getElementById('newPlayListText');
if (!p) {
alert('New playlist not found');
return;
}
var popup = window.open("http://www.w3schools.com");
if (!popup) {
alert('Kindly un-block/disable pop-up blocker');
return;
}
};
<p id="newPlayListText">There is a new playlist that was sent to you, check it out here.</p>
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.
Just like the question says, I'm trying to clear a form from a modal window while the modal stays up. I've tried:
if (myDocument.title == "Modal Window") {
parent.document.getElementById("textbox")
}
(I need it to do more than 1 tb, but used that just to try to get there. No luck.
It is contained within an iFrame, so I tried:
if (myDocument.title == "Modal Window") {
var ifr = document.getElementById("iFrame")
var form = ifr.document.getElementById("form")
ClearForm(form)
}
The ClearForm(form) function I stole from another Stack Overflow answer:
function ClearForm(form) {
$(':input', form).each(function () {
var type = this.type;
var id = this.id;
if (type == 'text' && id != 'text2')
this.value = "";
});
}
That 'text2' is one specific tb that we need to remain populated.
Any idea what I'm missing? I've been plagued with this bug for weeks.
I expect your issue is that the form is within an iFrame - most browsers won't allow you to modify elements within an iFrame, from the parent page, if they aren't from the same origin (or if the server is set up to deny it, or if you're looking at the page locally... see here for more details)
To double-check, try moving the form markup into the same page as the modal is in and run your function ClearFormfrom there. I expect that you'll then find it works.
Your only way around this would be to include the ClearForm function within the iFrame'd page, and then trigger it from the parent.
I have a textarea box where the user inputs HTML and it gets output into the body element of an iframe.
This works just fine using most HTML tags, but if you use the <script> tag (in order to add JavaScript), the script element does not get transferred to the iframe.
For example, I should be able type the following in the textarea:
<script>
function test() {
alert('test');
}
</script>
<button onclick="test()">test</button>
The button gets added to the iframe but since the script element apparently doesn't, clicking the button does not fire the alert().
One work-around for this is to declare alert() on the button click, rather than using a pre-scripted function; this work-around is shown below:
<button onclick="alert('test')">test</button>
However this only allows one javascript command (whereas the user may want to use a function with multiple commands).
You can see the webpage here
The JavaScript to fill the iframe contents is:
(function () {
$('.grid').height($(window).height());
var frame = $('iframe'),
contents = frame.contents(),
body = contents.find('body'),
styleTag = contents.find('head')
.append('<style></style>')
.children('style');
$('textarea').focus(function () {
var $this = $(this);
$this.keyup(function () {
if ($this.attr('id') === 'html') {
body.html($this.val());
} else {
styleTag.text($this.val());
}
});
});
})();
The problem is any "user-generated" scripts will be executed in the parent window's global context (which the iframe cannot [normally] access). The console shows the following error when clicking the button because the test() function is not accessible scope-wise for the iframe:
Uncaught ReferenceError: test is not defined
To fix this, scripts need to add functions to the global scope of the iframe's internal window:
<script>
(function () {
'use strict';
var iframe = document.getElementById('iframe'), //grab the iframe
win = iframe.contentWindow; //get the window of the iframe
win.test = function () { //declare function in scope of iframe's window
alert('test'); //now "test" will fire because it's defined in a scope accessible to the iframe
};
}());
</script>
<button onclick="test()">test</button>
i have a script like this
function resizeCrossDomainIframe(id, other_domain) {
var iframe = document.getElementById(id);
window.addEventListener('message', function (event) {
if (event.origin !== other_domain) return; // only accept messages from the specified domain
if (event.data === "reload") top.location.reload(); // If child page sends reload request - reload it without any questions asked
if (isNaN(event.data)) { //If this isn't integer than it is alert
alert(event.data); // Show alert if not integer
} else {
var height = parseInt(event.data) + 5; // add some extra height to avoid scrollbar
iframe.height = height + "px";
alert(event.data);
}
}, false);
}
what it does is dynamically resizes iframe. Now On a first iframe page I just get one alert, but in within iframe page i have links and when I go to second page I see 2 alerts, when I go to third page - i get 3 alerts, 4th link trigger 4 alerts etc...
In each iframed page I am calling parent to resize like:
<body class="settingspage" onload="parent.postMessage(document.body.scrollHeight, '<?php echo $_SESSION['SESS_ACCESSING_FROM']; ?>');">
I tried to clear the "event" array, but I still get Alerts, but this time they are empty, but the number of alerts equals the number of link-clicks within the iframe ?
Why is this ?
The problem is, every time you click on a link in the iframe, the load event is fired.
So you bind your message event every time a link is clicked.
On first time everything is correct, because you binded it once, on the second time you get two alerts, because you bound it twice, and so on...
So the solution is to remove the 'message'event on unload of iframe.
For this reason you have to clean your code a bit:
var listener = function (event) {
if (event.data === "reload") top.location.reload(); // If child page sends reload request - reload it without any questions asked
if (isNaN(event.data)) { //If this isn't integer than it is alert
alert(event.data); // Show alert if not integer
} else {
var height = parseInt(event.data) + 5; // add some extra height to avoid scrollbar
iframe.height = height + "px";
alert(event.data);
}
};
then you have your functions which you call onLoad and onUnload.
function iframeOnLoad(id) {
var iframe = document.getElementById(id);
window.addEventListener('message', listener, false);
}
function iframeOnUnload(id) {
var iframe = document.getElementById(id);
window.removeEventListener('message', listener, false);
}
I solved this by moving function to "main page body on load" and removing it from iframe...