Executing javascript mixed with HTML from a jQuery ajax response - javascript

Or, not precisely "executing," but updating a function that exists before the response with a function returned in the response.
Step 1
I have an HTML5 page that describes a location.
On the server side this page includes a ColdFusion file "MapFunction.cfm." (Which is used for consistent mapping all over the site at large.)
MapFunction.cfm outputs a javascript function "loadMap" mixed with the HTML.
loadMap() contains all the javascript needed to place a Bing map of the location on the page.
Some javascript in a separate js file actually calls loadMap().
This works when the page is first loaded.
Step 2
Search & results stuff is all fine too. Nothing needs to be done with the map here.
Step 3
When a search result is clicked, the result detail is loaded asynchronously via a jQuery $.get() request.
It returns mixed HTML and javascript which I use jQuery to traverse through.
With the jQuery objects I update specific areas of the page to show different details.
One of the areas I need to update is the map. That part isn't working.
What I'm working with is mixed HTML and Javascript that is identical in both Step 1 and Step 3:
<section id="mod-map" class="module mod-map">
<header class="mod-head">
Map <span class="arrow"></span>
</header>
<div id="map" class="mod-body">
<div id="cmMap" style="position:relative;width:369px;height:303px;"></div>
<script type="text/javascript" id="cfLoadMap">
// ...some global variables are defined to use...
function loadMap()
{
// ...Bing/Virtual Earth Map Stuff...
// This part here is unique to each location's detail
var propertypoint = new VELatLong(parseFloat(36.707756),parseFloat(-78.74204));
// ...More Bing/Virtual Earth Map Stuff...
// This part here is unique to each location's detail
var label = "<div class=\"wrapper\"><img onerror=\"replaceImage(this);\" src=\"noimage.jpg\" width=\"100\" class=\"thumb\" alt=\"\" /><div class=\"caption\"><br />City<br /> State, 12345</div></div>";
// ...More Bing/Virtual Earth Map Stuff...
}
</script>
</div>
</section>
Now, in Step 3 loadMap() does get called again, but it just refreshes the map to the same location. The loadMap() function as the browser knows it doesn't get updated with the one retrieved via ajax.
That updated block of mixed HTML & javascript above does get successfully added to the page after each ajax call. It is placed right where it originally is, but with different coordinates and captions where indicated by the comments above. The ajax callback looks like (slightly simplified):
$.get(urlToLoad, {}, function(data, status, request){
var newData = $(innerShiv(data, false)),
newModules = newData.find(".module");
// (innerShiv is used to make HTML5 tags work in IE. It's possible I'm going a little overboard with using it, but I had a lot of issues with IE. :-))
newModules.each(function(i){
var thisId = "#" + $(this).attr("id"),
thisBody = $(this).find(".mod-body").html(),
toReplaceAll = $("body").find(thisId),
toReplaceBody = toReplaceAll.find(".mod-body");
// These variables are used to choose add content in different ways based on thisID. Below is the one the map area is subject to.
toReplaceBody.html(innerShiv(thisBody));
}); // each
// Various things including loadMap() get called/re-initiated/etc. here
}, "html"); // get
This works in Firefox 3.6, but nowhere else I've tested (Opera 11, IE 7, Chrome 8).
I have done this before in a similar situation with dynamically PHP generated javascript written to a separate js file--$.getScript works great there. But this is mixed into the HTML of the ajax response.
I've been looking and have found and tried the following (among other things):
Attempted Solutions
1. var myScript = new Function($('script#cfLoadMap', data).text()); myScript();
2. eval(newData.text());
3. eval(newData.find("#cfLoadMap").text());
4. $("head").append(newData.find("#cfLoadMap"));
None of these so far seem to be doing any good.
I know there are a few other ways this could theoretically be done. But as it stands at the moment, I do not have any ability to change much of anything but what I do with the mixed HTML & javascript response. I need a solution where,
The details will be updated via ajax.
The javascript will be mixed in with the HTML.
The javascript will be a javascript function generated dynamically by ColdFusion.
Very similar questions have been asked & resolved before, so I hope this can be done. However, none of the solutions I've found are working for me. Might be making a mistake or missing something, or maybe it's just different when it's a function?
Any help would be appreciated.
Answer
It suddenly started working with the following code:
$.get(urlToLoad, {}, function(data, status, request){
var safeData = $(innerShiv(data, false)),
newModules = safeData.find(".module"),
newScript = safeData.find("script#cfLoadMap");
// Update Each module
newModules.each(function(i){
var jqoThis = $(this),
thisId = "#" + jqoThis.attr("id"),
newModule = jqoThis,
newModBody = jqoThis.find(".mod-body"),
curModule = $("body").find(thisId),
curModBody = curModule.find(".mod-body");
// Varies by id, this one is used by the map area.
curModBody.html(innerShiv(newModBody.html()));
}); // each
// Make sure plugins are bound to new content
$("body").oneTime(100, function(){
// Various things get initiated here
// Maps -- this one works: Chrome, Firefox, IE7, Opera
$("head").append(newScript);
// Maps -- these did not work
/*
// Firefox only (but Firefox always works)
runScript = new Function(newScript.text());
runScript();
*/
/*
// Firefox only (but Firefox always works)
eval(newScript.text());
*/
}); // oneTime
}, "html"); // get
One thing I did notice for sure was that without innerShiv, in all my browsers, $(data).find("script#cfLoadMap").text() was blank -- which I did not expect.

Most likely it's that functions in JavaScript can be declared in non-global scope, so when you're inserting the <script> tag, jQuery is evaling it, but not replacing the original function (as you noticed).
A fix for this would be to change how you declare the function from this:
function loadMap()
{
...
}
to this:
window.loadMap = function loadMap() {
...
}
That way the top-level loadMap will always be the latest one that came down from the server.
You may want to consider not modifying the client code this way as it can make debugging trickier, but that's totally up to you. Hopefully this answer works for you either way.

It suddenly started working with the following code:
$.get(urlToLoad, {}, function(data, status, request){
var safeData = $(innerShiv(data, false)),
newModules = safeData.find(".module"),
newScript = safeData.find("script#cfLoadMap");
// Update Each module
newModules.each(function(i){
var jqoThis = $(this),
thisId = "#" + jqoThis.attr("id"),
newModule = jqoThis,
newModBody = jqoThis.find(".mod-body"),
curModule = $("body").find(thisId),
curModBody = curModule.find(".mod-body");
// Varies by id, this one is used by the map area.
curModBody.html(innerShiv(newModBody.html()));
}); // each
// Make sure plugins are bound to new content
$("body").oneTime(100, function(){
// Various things get initiated here
// Maps -- this one works: Chrome, Firefox, IE7, Opera
$("head").append(newScript);
// Maps -- these did not work
/*
// Firefox only (but Firefox always works)
runScript = new Function(newScript.text());
runScript();
*/
/*
// Firefox only (but Firefox always works)
eval(newScript.text());
*/
}); // oneTime
}, "html"); // get
One thing I did notice for sure was that without innerShiv, in all my browsers, $(data).find("script#cfLoadMap").text() was blank -- which I did not expect.
However, I don't really see how this is different from what I had tried before and which failed. If someone spots a substantive difference, please let me know, for future reference?
(Note: it doesn't seem to make a difference that the Map bit is placed in the timeout, it works as well above it.)

Related

How can I create a dynamic product page using HTML, CSS, and Javascript

I currently only know javascript. But the thing is I looked up how to do it and some people talk about something called localStorage. I have tried this and for some reason when I jump to a new page those variables aren't kept. Maybe I am doing something wrong? I jump to a new page via
and all I want do do is select a certain image. take that image to a new page and add it to that page.
I tried using the localStorage variables and even turning it into JSON.stringify and doing JSON.parse when trying to call the localstorage to another script. It didn't seem to work for me. Is there another solution?
This is some of my code. There are two scripts.
document.querySelectorAll(".card").forEach(item => {
item.addEventListener("click", onProductClick);
})
var div;
var productImg;
var ratingElement;
var reviewCount;
var price;
function onProductClick(){
// This took a week to find out (this.id)
// console.log(this.id);
div = document.getElementById(this.id);
productImg = div.getElementsByTagName('img')[0];
ratingElement = div.getElementsByTagName('a')[2];
reviewCount = div.getElementsByTagName('a')[3]
price = div.getElementsByTagName('a')[4];
console.log(div.getElementsByTagName('a')[4]);
var productData = [div, productImg,ratingElement,reviewCount,price];
window.localStorage.setItem("price", JSON.stringify(price));
}
function TranslateProduct(){
console.log("Hello");
}
This is script 2
var productPageImage = document.getElementById("product-image");
var myData = localStorage['productdata-local'];
var value =JSON.parse(window.localStorage.getItem('price'));
console.log(value);
// function setProductPage(img){
// if(productImg != null){
// return;
// }
// console.log(window.price);
// }
To explain my thought process on this code in the first script I have multiple images that have event listeners for a click. I wanted to Click any given image and grab all the data about it and the product. Then I wanted to move that to another script (script 2) and add it to a dynamic second page. yet I print my variables and they work on the first script and somehow don't on the second. This is my code. in the meantime I will look into cookies Thank you!
Have you tried Cookies
You can always use cookies, but you may run into their limitations. These days, cookies are not the best choice, even though they have the ability to preserve data even longer than the current window session.
or you can make a GET request to the other page by attaching your serialized object to the URL as follows:
http://www.app.com/second.xyz?MyObject=SerializedData
That other page can then easily parse its URL and deserialize data using JavaScript.
you can check this answer for more details Pass javascript object from one page to other

Filter Link Tracking issue in Adobe DTM

I am facing issue with adobe image request in network tab, I can proper see results in console, but while in image request I am not seeing Evar55 current value.
Actually there is bug Analytics tracking issue- Evar55
Evar55 should capture the value of filter selected by users on search result page and PLP.
So now the next thing I have written the code, which is working absolutely fine in Console, and I can see the result but in network tab the image request is giving previous value not giving the current value of facet.
Here I am sharing the screenshot and code with you, please tell what issue is.
In DTM, I have created page load rule – conditions trigger rule at DOM ready –then adobe analytics open editor I have pasted this code
Code
var oldXHR = window.XMLHttpRequest;
function newXHR() {
var realXHR = new oldXHR();
realXHR.addEventListener("readystatechange", function() {
if(realXHR.readyState==4 && realXHR.status==200){
//run your code here
window.setTimeout(function() {
if(s.pageName && (s.pageName.indexOf('plp:')>-1 || s.pageName.indexOf('search')>-1)){
var PFF = document.getElementsByClassName('selected-categories')[0].innerText;
PFF_Final = PFF.replace(/ /g, '').replace(/:/g, '|');
if(PFF_Final.indexOf('Categories|')>-1 || PFF_Final.indexOf('search|')>-1){
console.log('N/A');
}
else if(PFF_Final && typeof PFF_Final !== 'undefined' && PFF !== 'null' && PFF !== ''){
//PFF_Final = PFF.replace(/ /g, '').replace(/:/g, '|');
s.linkTrackVars = 'eVar91';
s.eVar91 = PFF_Final.trim();
//s.tl(this, 'o');
console.log(PFF_Final);
}
}
},1500);
}
}, false);
return realXHR;
}
window.XMLHttpRequest = newXHR;
Note : - I have change the Evar55 to Evar91 because Evar 55 which is already in use.
enter image description here
enter image description here
Thanks,
Payal
At face value, the immediate reason the code you posted does not make a request because you have the s.tl call commented out...
Second, a note: if you are filtering for image requests in the network tab, you will almost certainly not see the Adobe Analytics (AA) request there, because unless you are using a very ancient browser or else have javascript turned off and using the <img> tag method, it will show up as either a javascript request or ajax (xhr) request (depending on what version of the AA library and how long the request is).
If you are still not seeing the request, there are a couple additional things to try. One or more of these may or may not be true/necessary, depending on what version of the AA library you are using:
1) When you pass this as the first argument, it must be a valid anchor element with an href attribute <a href='..'></a>. Since this is not applicable within the context of your posted code, try changing the first argument to boolean true.
2) Add a 3rd argument to the s.tl call. This argument is supposed to be a description for the link click, e.g. s.tl(true,'o','some link'); It can be anything you want; it's what shows up in the native link reports in AA (that you will almost certainly ignore, in favor of looking at that eVar91 report, instead). All versions of the AA library require this 3rd argument if you want to track it as a click/interaction server call. Without it, in more recent versions of AA, it will trigger the request as a page view call, but in older versions of the AA library, it will not trigger a call at all.
3) Again, depending on your AA lib version, it will not include anything above eVar75. I don't remember the exact AA version where eVar76+ was introduced (edit: Looks like Starting AM1.4. Legacy H code not supported). As a quick check, try using eVar75 or lower to see if it shows up in the request. Note: I'm only putting this for completeness sake, but I don't think this your issue, since it seems from your post you may have tried with eVar55 already? But may as well be certain. If this is the case, I would suggest updating to the latest AppMeasurement library. If for some reason you are unable to do that, and still need to use eVar91, then the alternative is to pop it as a contextData variable, e.g. s.contextData['eVar91']='foo'; and then map it to the real eVar91 in a Processing Rule within the AA interface. If your AA library is old enough that even contextData variables don't work (H23.2 or lower).. then I suggest you make it your highest priority in life to upgrade to a more recent version of the AA lib..
If after all of this you still do not see an AA call, just type s.t(true,'o','foo'); into the js console. Do you see an http request? If you do not see a request, then you have some deeper issue not directly related to the posted code. Perhaps your AA library is not present, or it is not loaded before this is triggered, or is under a different namespace than the default s namespace. But it's not really feasible to write lots of random guesses here vs. looking at the site.
If you do see a request, then my best guess at this point is you having a timing issue. Perhaps there is a page (re)load happening and it is not getting a chance to trigger? But again, it's not very feasible to speculate on a site unseen.

Is it possible for the admin to get the full sourcecode of my js-file if I redirect a Javascript file to a local modified Javascript file?

I created a google-chrome-extension which redirects all requests of a javascript-file on a website to a modified version of this file which is on my harddrive.
It works and I do it simplified like this:
... redirectUrl: chrome.extension.getURL("modified.js") ...
Modified.js is the same javascript file except that I modified a line in the code.
I changed something that looks like
var message = mytext.value;
to var message = aes.encrypt(mytext.value,"mysecretkey");
My question is now is it possible for the admin of this website where I redirect the javascript-file to modify his webpage that he can obtain "mysecretkey". (The admin knows how my extension works and which line is modified but doesn't know the used key)
Thanks in advance
Yes, the "admin" can read the source code of your code.
Your method is very insecure. There are two ways to read "mysecretkey".
Let's start with the non-trivial one: Get a reference to the source. Examples, assume that your aes.encrypt method looks like this:
(function() {
var aes = {encrypt: function(val, key) {
if (key.indexOf('whatever')) {/* ... */}
}};
})();
Then it can be compromised using:
(function(indexOf) {
String.prototype.indexOf = function(term) {
if (term !== 'known') (new Image).src = '/report.php?t=' + term;
return indexOf.apply(this, arguments);
};
})(String.prototype.indexOf);
Many prototype methods result in possible leaking, as well as arguments.callee. If the "admin" wants to break your code, he'll surely be able to achieve this.
The other method is much easier to implement:
var x = new XMLHttpRequest();
x.open('GET', '/possiblymodified.js');
x.onload = function() {
console.log(x.responseText); // Full source code here....
};
x.send();
You could replace the XMLHttpRequest method, but at this point, you're just playing the cat and mouse game. Whenever you think that you've secured your code, the other will find a way to break it (for instance, using the first described method).
Since the admin can control any aspect of the site, they could easily modify aes.encrypt to post the second argument to them and then continue as normal. Therefore your secret key would be immediately revealed.
No. The Web administrator would have no way of seeing what you set it to before it could get sent to the server where he could see it.

Chrome JavaScript location object

I am trying to start 3 applications from a browser by use of custom protocol names associated with these applications. This might look familiar to other threads started on stackoverflow, I believe that they do not help in resolving this issue so please dont close this thread just yet, it needs a different approach than those suggested in other threads.
example:
ts3server://a.b.c?property1=value1&property2=value2
...
...
to start these applications I would do
location.href = ts3server://a.b.c?property1=value1&property2=value2
location.href = ...
location.href = ...
which would work in FF but not in Chrome
I figured that it might by optimizing the number of writes when there will be effectively only the last change present.
So i did this:
function a ()
{
var apps = ['ts3server://...', 'anotherapp://...', '...'];
b(apps);
}
function b (apps)
{
if (apps.length == 0) return;
location.href = apps[0]; alert(apps[0]);
setTimeout(function (rest) {return function () {b(rest);};} (apps.slice(1)), 1);
}
But it didn't solve my problem (actually only the first location.href assignment is taken into account and even though the other calls happen long enough after the first one (thanks to changing the timeout delay to lets say 10000) the applications do not get started (the alerts are displayed).
If I try accessing each of the URIs separately the apps get started (first I call location.href = uri1 by clicking on one button, then I call location.href = uri2 by clicking again on another button).
Replacing:
location.href = ...
with:
var form = document.createElement('form');
form.action = ...
document.body.appendChild(form);
form.submit();
does not help either, nor does:
var frame = document.createElement('iframe');
frame.src = ...
document.body.appendChild(frame);
Is it possible to do what I am trying to do? How would it be done?
EDIT:
a reworded summary
i want to start MULTIPLE applications after one click on a link or a button like element. I want to achieve that with starting applications associated to custom protocols ... i would hold a list of links (in each link there is one protocol used) and i would try to do "location.src = link" for all items of the list. Which when used with 'for' does optimize to assigning only once (the last value) so i make the function something like recursive function with delay (which eliminates the optimization and really forces 3 distinct calls of location.src = list[head] when the list gets sliced before each call so that all the links are taken into account and they are assigned to the location.src. This all works just fine in Mozilla Firefox, but in google, after the first assignment the rest of the assignments lose effect (they are probably performed but dont trigger the associated application launch))
Are you having trouble looping through the elements? if so try the for..in statement here
Or are you having trouble navigating? if so try window.location.assign(new_location);
[edit]
You can also use window.location = "...";
[edit]
Ok so I did some work, and here is what I got. in the example I open a random ace of spades link. which is a custom protocol. click here and then click on the "click me". The comments show where the JSFiddle debugger found errors.

reading content of .aspx using javascript

i am using javascript to read the content of .aspx page. but i am not able to read it. i am using javascript as:
function edit(headtext,totext, bodytext, footertext){
alert('lll');
//var xmlDoc=new ActiveXObject("MSXML.DOMDocument");
xmlDoc.async="false";
xmlDoc.load("theme3ex.aspx");
var students = xmlDoc.documentElement;
alert('0000');
var student = students.childNodes(0);
document.getElementById('txtareahead').innerHTML = headtext;
document.getElementById('txtareato').innerHTML = totext;
document.getElementById('txtareabody').innerHTML = bodytext;
document.getElementById('txtareafooter').innerHTML = footertext;
location.href = "MailSender.aspx";
}
is there any problem eith my javascript..
First problem is that you've commented out the line which creates the AJAX object, so none of the subsequent code will work because they're trying to access an object which doesn't exist.
Second problem is that even if you uncomment that line, it's using Activex/MSXML which will only work with IE (and even then only older versions of IE).
In short, your code isn't good, and needs to be entirely redone rather than being fixed.
My recommendation is that you find a more up-to-date example of how to do AJAX code. Possibly even just use a good quality Javascript library like JQuery.
I agree with #Spudley's point.
It's also worth mentioning that if the textboxes such as txtareahead are ASP.NET TextBox Controls, then the ID's will have most likely changed during rendering.

Categories

Resources