I'm pulling in a 3rd party JavaScript file which makes use of document.write, but what's being written needs to be manipulated - preferably before it hits the page. What I've come up with is the following:
// Hijack document.write to buffer all output...
var dwrite = document.write;
var hijacked = '';
document.write = function(content) {
hijacked += content;
};
// Call the script...
dwrite("<script type='text/javascript' src='http://www.example.com/file.js'></script>");
// Manipulate the output...
hijacked
.replace(/a/gi, '4')
.replace(/e/gi, '3')
.replace(/i/gi, '1')
.replace(/o/gi, '0');
// Write the output into the page...
dwrite(hijacked);
// Restore document.write and free our buffer...
document.write = dwrite;
hijacked = null;
With this, I'm getting NS_ERROR_XPC_BAD_CONVERT_JS wherever I attempt to call dwrite. Can anyone offer a suggestion on why this is happening? I don't see why calling document.write through a different name would blow up.
UPDATE I'm seeing this in Firefox 4.0.1.
I tried this and it worked. Basically I replaced document.write after using it.
document.write(""
+ "<script>"
+ "var hijacked = '';"
+ "var dw = document.write;"
+ "document.write = function(content) { hijacked += content; }"
+ "<" + "/script>"
+ "<script type='text/javascript' src='test.js'><" + "/script>"
+ "<script>"
+ "document.write = dw;"
+ "dw = null;"
+ "document.write(hijacked.replace(/e/gi, '4'));"
+ "<" + "/script>");
Related
I have a webpage that displays a news story in the main body, and has a side navigation bars where four other stories are listed. I am trying to use json files to swap out the html text in the main body. Each story has it's own json file. Here is my current javascript code:
$(document).ready(function() {
$("#nav_list a").click(function(evt) {
buildName = "../json_files/" + $(this).attr("title") + ".json";
alert(buildName);
document.getElementById("main").innerHTML = "";
$.getJSON(buildName, function(data) {
$.each(data, function() {
$.each(this, function(key, value) {
$("#main").append(
"<h1>" + value.title + "</h2>" +
"<img src='" + value.image + "'>" +
"<h2>" + value.month + "<br>" + value.speaker + "</h2>" +
"<p>" + value.text + "</p>";
);
}); // inner each
}); // outer each
)}; // end of getJSON
}); // end click
}); // end ready
Notes:
The alert(buildName) is for my own testing.
The next line (w. the innerHTML) should clear the current body content.
** NOTE: This works if I have the $.getJSON method commented out! Otherwise both this and my alert() are entirely ignored.
Because each store has it's own json file, I questioned the necessity of the muliple $.each methods within the getJSON. It didn't make a difference (the format I have below is from my textbook and has worked on a single json file with multiple entries).
I even tried not clearing the initial innerHTML and overwriting, but I may have had some syntax wrong. Here is that attempt:
$.getJSON(buildName, function(data) {
$.each(data, function(key, value) {
$("#main").append(
("#main h1").innerHTML.replace("<h1>" + value.title + "</h2>");
("#main img").innerHTML.replace("<img src='" + value.image + "'>");
("#main h2").innerHTML.replace("<h2>" + value.month + "<br>" + value.speaker + "</h2>");
("#main p").innerHTML.replace("<p>" + value.text + "</p>");
)
}); // endeach
)}; // end of getJSON
What do you guys think? I am absolutely stumped.
Remove the semi-colon at the end inside your .append(). Otherwise, I'm not sure. I wanted to comment this instead of answering but I lack the reputation. With your second attempt, those replace calls shouldn't be made inside the .append(). Good luck!
I think that the problem might be your json path that you construct.
Try using a standard path "../file.json" or "file.json" to check if you have the result you want or if the $.getJSON() is still ignored.
About the other errors: What is your devel. environment?
I also noticed that you have a bracket mismatched in your append function at the title part. So,
"<h1>" + value.title + "</h2>" +
would have to be changed to..
"<h1>" + value.title + "</h1>" +
I have re-created a sample of your site and it all seems to run fine using your code and .json files.
I just needed to modify the code as shown below. In this case, if you have a heading it will also clear the heading in your website.
<!--json retrieve script starts here -->
<script>
$(document).ready(function(){
$(":button").click(function() {
buildName = "../json_files/" + $(this).attr("title") + ".json";
alert(buildName);
//$("#main").empty();
document.getElementById("main").innerHTML = "";
$.getJSON(buildName, function(data){
//$.each(data, function() {
// $.each(data, function(key, value){
$("#main").append(
"<h1>" + data.title + "</h2>" +
"<img src='" + data.image + "'>" +
"<h2>" + data.month + "<br>" + data.speaker + "</h2>" +
"<p>" + data.text +"</p>"
);
// });
//});
});
});
});
</script>
<!--json script end here -->
NOTE: I have swapped the link with button to wire the event for this example.
You can also use multiple file entries in a single .json file in the format shown below:
{
"story1":"/jsonfile1.json",
"story2":"/jsonfile2.json",
"story3":"/jsonfile3.json"
}
which you would then parse with an $.each(data,function(key,value) where value would be the filename to be requested via $.getJSON so you can have multiple entries handled by a single file.
There were a few syntax errors - a parenthesis and curley bracket out of order, misplaced semi-colon, things of the like. The logic was correct.
Thanks all for the replies!
I have the following code which works on the first time around:
$("#CompDD").change(function () {
//var parts = (window.location.pathname.split("/"));
var ctrlName = '#ViewContext.RouteData.Values["Controller"].ToString()';
var actnName = '#ViewContext.RouteData.Values["Action"].ToString()';
var url = (ctrlName + "/" + actnName + "/?SearchString=" + $('#CompDD option:selected').text() + "&atton=" + $('#AttDD option:selected').val());
//delete ctrlName;
// delete actnName;
//window.location = ($(location).attr('href') + "/?SearchString=" + $('#CompDD option:selected').text() + "&atton=" + $('#AttDD option:selected').val());
//window.location = (ctrlName + "/" + actnName + "/?SearchString=" + $('#CompDD option:selected').text() + "&atton=" + $('#AttDD option:selected').val());
//$(location).attr('href', url);
window.location.href = url;
//alert(ctrlName + "\n" + actnName);
});
However on subsequent changes of the drop down in question (#CompDD) it will add another controller/action to the end of the link, ex. it adds another "Patrons/Index" to the end of the existing "Patrons/Index", thenit adds the searchsrting variables etc.
Please excuse the comments and stuff on my code. How do i get Jquery (or javascript) to redirect without appending the controller name and action names over and over, or whats the best way to do this?
EDIT: Such an easy fix! I had to add the root slash to the URL string, example this worked:
var url = ("/" + ctrlName + "/" + actnName + "/?SearchString=" + $('#CompDD option:selected').text() + "&atton=" + $('#AttDD option:selected').val());
Notice the forward slash at the start of the string I construct....Yikes!
Use the Url.Action helper method to build path to action methods.
$("#CompDD").change(function () {
var baseUrl="#Url.Action("Home","Search")";
alert(baseUrl);
// Now append your query string variables to baseUrl
// Ex : baseUrl=baseUrl+"?searchString=testing";
window.location.href=baseUrl;
});
Assuming you want to navigate to the search action method in Home controller.
function RedirectUrl() {
if (domElement.textfor.val() == "Index") {
window. location.href = E_host.AppVar.AppHost + "/Home/index";
}
}
Adding knockout templates at runtime empties the HTML DOM
var templateEngine = new ko.nativeTemplateEngine();
templateEngine.addTemplate = function (templateName, templateMarkup) {
document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
};
templateEngine.addTemplate("gridTable","<table></table");
All the earlier content goes and The DOM becomes
<html><head><script type="text/html" id="gridView"><table></table></script></head></html>
As #nemsev said,
eveloper.mozilla.org/en-US/docs/Web/API/Document/write: calling document.write on a closed (loaded) document automatically calls document.open which will clear the document
So, I modified my code to,
var templateEngine = new ko.nativeTemplateEngine();
templateEngine.addTemplate = function (templateName, templateMarkup) {
//document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
var scriptTag = document.createElement("script");
scriptTag.type = "text/html";
scriptTag.id = templateName;
scriptTag.innerHTML = templateMarkup;
var node = document.getElementsByTagName("head")[0];
node.appendChild(scriptTag);
};
templateEngine.addTemplate("gridTable","<table></table");
I would recommend you to create separate div in your html structure and then load the template in that div. For instance you can use jquery for it.
$("#someDiv").append(templateMarkup);
I am attempting to access Google Books in order to an ISBN Code to get details of a book, I have a number of problem, which are:
A) I am trying to assemble a script request e.g. with the ISBN code concatenated into the URL. I have not managed to do this successfully - and I don't know why.
B) I then want to update a div in the DOM with this generated script dynamically, such that it will then execute.
C) I am finding it a bit of a puzzle as to the format of the returned data and the argument name of the function call contained in the Google response.
Has anyone else encountered the same problem and can offer guidance re A thru C above.
I enclose JavaScript code below.
$(document).ready(function() {
$('#viewbook-button').live('click', function() {
isbnCode = this.text;
alert("ISBN is : " + isbnCode + " " + this.text + " as well");
alert("Getting JSONP Google Books data");
isbnCode = "0451526538";
JSONPstr = '<' + 'script ' + 'src="' + 'https://www.googleapis.com/books/v1/volumes?q=ISBN' + isbnCode;
JSONPstr = JSONPstr + '&callback=handleJSONPResponse">' + '</script>';
alert("un-Escaped JSONP string" + JSONPstr);
escJSONPstr = escape( escJSONPstr );
alert("Escaped JSONP string");
//divstr = "";
//divstr = divstr + escape(<script src=");
//divstr = divstr + encodeURIComponent(https://www.googleapis.com/books/v1/volumes?q=ISBN);
//divstr = divstr + escape(isbnCode);
//divstr = divstr + encodeURIComponent(&callback=handleJSONPResponse);
//divstr = divstr + escape("></);
//divstr = divstr + escape(script);
//divstr = divstr + escape(>);
$('#jsonp-call').html(escJSONPstr);
// This will cause the handleJSONPResponse function to execute when the script is dynamically loadedinto div.
// The data wrapped in a function call will be returned from the Google Books server.
// This will cause the handleJSONPResponse function to execute below.
}); // end viewbook-button
}); // end document.ready
function handleJSONPResponse(response) {
var tmp = response;
alert(tmp);
};
</script>
</head>
<body>
<h2>Show Details of Books Ordered by a Customer</h2>
Get Customer Details
<br/><br/>
<div id="tablist">Tables will be Listed Here</div>
<br/><br/>
<div id="Google-call">The JSONP generated src= statement will go here and execute</div>
</body>
</html>
EDIT:
Problem solved - thanks everyone.
You're reinventing the wheel: jQuery has built-in JSONP support, so you don't need to faff about implementing it yourself. Use the $.ajax method:
$.ajax({
url: 'https://www.googleapis.com/books/v1/volumes?q=ISBN' + isbnCode,
dataType: 'jsonp',
success: function(response) {
console.log(response); // log the response object to the console
}
});
That should be all you need to do.
This is a follow-up to a question I asked yesterday.
I have a userscript (kind of like GreaseMonkey script, but for Chrome).
The idea is to add a textbox and a button to the page. Then when the user clicks the button, it kicks off a function that does stuff. So I inject the textbox, button and the function into the page, but when the user clicks the button, the Chrome console tells me "Uncaught TypeError: object is not a function". So obviously it does not see the function I just injected and that is specified in the onclick event for the button.
So I have code like this:
initialize();
function initialize() {
var dropDown = document.getElementById("tstGlobalNavigation_ddlChooseProject");
// add a textbox
dropDown.innerHTML = dropDown.innerHTML + " <input type='text' name='txtSearch' style='position:absolute;top:8px;left:800px;width:50px' >";
// add a button
dropDown.innerHTML = dropDown.innerHTML + " <input type='button' name='btnSearch' value='Go' onclick='fn()' style='position:absolute;top:8px;left:860px;width:35px'>";
addScript("var obj = document.getElementById('txtSearch'); "
+ "if (obj != null) { "
+ " var incidentId = document.getElementById('txtSearch').value; "
+ " var currentURL = location.href; "
+ " var splitResult = currentURL.split('/'); "
+ " var projectId = splitResult[4]; "
+ " location.href = 'http://dev.myApp.com/ProductTeam/' + projectId + '/Incident/' + incidentId + '.aspx'; "
+ " }"
, "fn");
}
function addScript(contents, id) {
var head, script;
head = document.getElementsByTagName('head')[0];
script = document.getElementById(id);
if(script != undefined) {
head.removeChild(script);
}
script = document.createElement('script');
script.type = 'text/javascript';
script.id = id;
script.innerHTML = contents;
head.appendChild(script);
}
What am I missing here?
You're not calling the function you created, you're using the id that you give to the script tag... Try changing the code to
addScript("function fn() { var obj = document.getElementById('txtSearch'); "
+ "if (obj != null) { "
+ " var incidentId = document.getElementById('txtSearch').value; "
+ " var currentURL = location.href; "
+ " var splitResult = currentURL.split('/'); "
+ " var projectId = splitResult[4]; "
+ " location.href = 'http://dev.myApp.com/ProductTeam/' + projectId + '/Incident/' + incidentId + '.aspx'; "
+ " } }"
, "fn");
and you will have a fn() function that can be called
The problem is that you're trying to use the onclick element attribute to bind an event handler. These attributes are only parsed when the page is first loaded, at which time the function you're trying to bind as the callback doesn't exist.
Avoid binding event handlers in element on* attributes whenever possible. This is called writing unobtrusive JavaScript.
That said, if you absolutely must stick with using onclick, you can bind to a dummy function which does nothing but turn around and call the function that you inject:
<button onclick="wrapper()"
Where wrapper looks something like this:
function wrapper() {
return functionThatWillEventuallyBeInjected();
}
I'm not sure you can actually create script tags on the fly and push content in it.
You could instead create the script tag and modify the src attribute to some JS file:
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "path/to/your/javascript.js";
document.body.appendChild(script);
If you really need to execute a code stored in a string, maybe you could simply eval() it when required!