Refreshing elements inside ul that find place in a iframe - javascript

I have a div that contains a iframe from another website. In that website you can find a UL and its updates every time user adds a feedback. This is the ul:
Is it any way I can refresh only this ul every x seconds so I get the feedbacks in realtime?
Thanks

No if they are in a different domains. Using Javascript you can't get information from another website due the Same Origin Police. It's a security restriction that browsers implements and you can't bypass.
Same Origin Police policy permits scripts running on pages originating
from the same site – a combination of scheme, hostname, and port
number – to access each other's DOM with no specific restrictions, but
prevents access to DOM on different sites.
If you want to keep updated from another website you may need use a server side language (JAVA, PHP, NodeJS, etc...) to make a request, parse the return HTML from other website and find the information you need.
EDIT:
If you just need update the iframe every X seconds you can use setInterval:
var refreshFrame= function () {
var iFrames = document.getElementsByClassName("yourClassName");
for(var i = 0; i < iFrames.length; i++) {
if(iFrames[i].className === "yourClassName") {
iFrames[i].src = iFrames[i].src;
}
}
}
window.setInterval(refreshFrame, 3000); // Time in ms
look this FIDDLE

Related

How to reference HTML from external webpage

I apologize in advance for the rudimentary question.
I have web page A that has a link to web page B on it. I need to locate the link to web page B (easy enough), and then store the HTML from web page B in a variable in my javascript script.
To store the HTML from web page A, I know it's a simple:
html_A = document.body.innerHTML;
How do I store the HTML from web page B? I believe I need to use AJAX correct? Or can I do it with javascript? And if it's the former, let's just assume the server for web page B allows for it.
Thank you in advance!
If youre trying to load HTML from a website that resides on a different server you will get a Cross-Origin Request Blocked Error. I dealt with this in the past and found a way to do it using YQL. Try it out:
//This code is located on Website A
$(document).ready(function() {
var websiteB_url = 'http://www.somewebsite.com/page.html';
var yql = '//query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from html where url="' + websiteB_url + '"') + '&format=xml&callback=?';
$.getJSON(yql, function(data) {
function filterDataCUSTOM(data) {
data = data.replace(/<?\/body[^>]*>/g, '');// no body tags
data = data.replace(/[\r|\n]+/g, ''); // no linebreaks
return data;
}
if (data.results[0]) {
var res = filterDataCUSTOM(data.results[0]);
$("div#results").html(res);
} else {
console.log("Error: Could not load the page.");
}
});
});
This is only possible if web page B is on the same domain due to the same-origin policy security feature of all major browsers.
If both pages are on the same domain you could do
$.get("/uri/to/webpage/b").then(function(html) {
//do something with the html;
});
Note that the html will be available only once the ajax request finishes inside the .then(...) function. It will NOT be available on the line after this code block.
Hard to tell without knowing more about your situation but this is rarely the correct thing to do. You might want to look into $.fn.load() (is limited by SOP) or using iframes (is not limited by SOP) as one of these might be more appropriate.
I should note that the standard way of doing this when you need access to html from another domain is to pull it down on your webserver and then re-serve it from there. That being said, it is probably a violation of that website's terms of use.

Getting Backbutton to work in single page website and implementing "speaking" URLs

I have a single page website and would like to achieve the following:
back button working as if it was a normal website
and instead of say,
www.mysite.com/index.php?p=#this-is-a-great-product
I'd like to have this url
www.mysite.com/this-is-a-great-product
while still having back button working properly.
Regarding 1.) I use the following code ive found which works great:
<!-- Getting BackButton to work properly -->
<script type="text/javascript">
var times = 0;
function doclick() {
times++;
}
function doclick() {
times++;
location.hash = times;
}
window.onhashchange = function() {
if (location.hash.length > 0) {
times = parseInt(location.hash.replace('#',''),10);
} else {
times = 0;
}
}
</script>
…but of course it just changes any anchors to /#1, then /#2 and so forth ro get the backbutton to work. But as I'm not a programmer I don't know how to change it… :(
Regarding 2.) i can add in htaccess this:
>RewriteEngine On
>RewriteRule ^([^/.]+)/?$ /index.php?page=$1
and this changes /index.php?p=products to /products.
So how do I change the above code (under 1.) so it doesn't change all anchors to #1, #2, etc. but instead references / uses the urls I achieved under 2, like
www.mysite.com/this-is-a-great-product
And (probably a very dumb question, but a very important one) -given I use only the new url links on my site- is there any danger that this still might result in duplicate content in any way?
Regarding this, should I (for that reason or any other) sefreferential my single page index.php to itself using rel canonical link=index.php?
Thanks so much in advance!
As mentioned, you will want to use the HTML5 History API. Please note, this API is relatively new and therefore browser support is a concern. At the time of writing, approximately 71% of global Internet users have support for it (see http://caniuse.com/#feat=history for browser support information). Therefore, you will want to ensure you have a fall-back solution for this. You will likely want to use the older #! solution that was popular before the HTML 5 History API was adopted.
If you use the history API to replace, for example, example.com/#!settings with example.com/settings and a user bookmarks that nicer URL, then when they go to visit it, their browser will make a request to the server for /settings (which doesn't actually exist in the web server's context). Therefore, you will need to make sure your web server has some redirection rules (i.e. RewriteEngine) such that it can take the pretty URLs and redirect them to the #! version (and then if the user's browser supports the history API it can replace that with the nice URL).
If you aren't very comfortable programming yourself, I'd recommend using a JavaScript library that does a lot of the work for you. I did some quick searching and discovered the following, though there might be better ones out there: https://github.com/browserstate/history.js
Basically i have created a small prototype on jsfiddle which tracks all the urls accessed via ajax calls.
Also contains navigation to access links back and forth .
How It Actually Works:
I have created a global array called history, which keeps track of all urls accessed via ajax in sequence.
also there a global index defined to keep track of the url being accessed when navigating back and forth the links in history array.
There is History section at the bottom of the jsfiddle, which shows the sequence in which the links are accessed by capturing the link names and posting them in the order in which they were accessed.
JS Code:
$(function () {
var history = [];
var index = 0;
$('.links').on('click', function () {
$('#history').append($(this).text());
var address = $(this).attr('data-ref');
index += 1;
history[index] = address;
$('.links').attr('disabled', 'disabled');
loadExternalPage(address);
console.log('list:' + history);
});
$('#back').on('click', function () {
console.log(index);
index -= 1;
console.log(index);
console.log(history[index]);
loadExternalPage(history[index]);
});
$('#forward').on('click', function () {
console.log(index);
index += 1;
console.log(index);
console.log(history[index]);
loadExternalPage(history[index]);
});
var loadExternalPage = function (address) {
console.log(history[index]);
$('#result-section').load(address, function () {
console.log('data-loaded');
$('.links').removeAttr('disabled');
});
};
});
Live Demo # JSFiddle:http://jsfiddle.net/dreamweiver/dpwmcu0b/8/
Note: This solution is far from being perfect, so dont consider it as final solution but rather use it as a base to build upon
On using BACK and FORWARD functions in the browser top-left button:
In principle, there is no great problem with this as long as you work with the existing storage object (a stack) for previously visited web pages on your browser. This object is the history object and you can see what is in it anytime by right-clicking and selecting "Inspect", then selecting the "Console" tab, then enter window.history and enter.
Check out the Browser Object Model (BOM) section of Pro Java For Web Developers (Frisbee) for the background to the history object. (Just a few pages, an easy read, don't worry.) Just remember that in this process you are storing the new page that you move to, not the old page that you are leaving !
For a simple SPA example, look at this example. codepen.io/tamjk/pen/NWxWOxL
In regard to the URL, the method that the history object uses to load a new page state into the history stack, i.e. pushState(...), has an optional third parameter for associating a dummy URL for each web page that is stored.
Personally, when I first sorted out the BACK & FORWARD functions, I did not use dummy URLs as the browser was being confused by them and I had enough to do sorting out the history sequence using just the first two parameters, i.e.
the state object - a JSON holding enough data to recreate the page stored
a title for the page I expect that you could also use a dummy URL but I will leave that to the student as an exercise, as they say.
But you can add the URL of the new page if you want to.
In the example above, for the state object I just used the IDs of the page's nav link and its content element.
For the title, I programmatically changed the HTML's page title element with each change of page. I did this after noticing that the browser listed the previous pages according to the title element in the HTML code.
Unfortunately, this title does not show up on CodePen when you right-click on the browser BACK and FORWARD buttons due to CodePen's system not allowing it. But it will show on your own sites.
It's important that whatever method you use to store current web page states when using the navbar links to navigate, you DO NOT ADD page states to the browser history when you arrive at them using BACK or FORWARD buttons. Otherwise your history stack will have repetitions of entries going back and deletion of entries going forward.
In the CodePen, this was achieved by having the addToHistory(..) function separate to and outside the scope of the switchPage(...) function. This allows you use of the switchPage function in both normal navbar navigation and browser BACK/FORWARD navigation. The third parameter of switchPage(...) is a boolean indicating if the page is to be stored in history or not.
Anyway, this is just something to get you started.

Detecting :first-letter by javascript

I need to know if an element is styled with a :first-letter style, and it should be a general solution so I won't depend on class names or special style attributes. Is there any way? Example:
<p class="initial">First</p>
<p>Second</p>
.initial:first-letter {
float: left;
font-size: 1.5em;
font-weight: bold;
}
$('p').click(function(){
// how to determine if :first-letter is applied to current paragraph?
});
If your CSS is self-hosted, you can:
Get a list of all CSS blocks
Filter out CSS blocks which do not contain :first-letter in the block's selector
Iterate over the list of remaining CSS blocks, and run matchesSelector() with the target element as a receiver and the current CSS block's selector as the argument.
If matchesSelector() returns true, then the current CSS block's rules affect the target element's first letter.
Otherwise move on to the next CSS block in the list
If the CSS isn't self-hosted and the CDN doesn't send CORS headers, then you cannot read the CSS file source
due to privacy issues and this cannot be done.
I have also left out figuring out rule-cascading from the algorithm. Another bump in the road is to figure out what pseudo-selectors affect matchesSelector in a false way.
Like consider:
p.webkitMatchesSelector("p:first-letter") //false
So one would have to remove pseudos like :first-letter from the string before attempting to match as these are irrelevant (but pseudos like :nth-child are not because they truly affect matching).
Demo http://jsfiddle.net/PBuzb/5/ (keep in mind the problems I mentioned are not handled really well here) (The base of code originally by Crush)
Why is it not allowed to read CSS source in cross-origin situation?
The reason you can only show images, run css/js etc.. from other domains BUT absolutely not access their data in any way is privacy.
The case is easiest to make for images. Let's say I am logged in to facebook, and facebook uses url for private photo like
http://facebook.com/myprofile.png. Now I go to evil.com, and evil.com can load the image because I am logged in to facebook,
the facebook will give them that image. Normally they cannot access the image or steal it in anyway, but if we enabled
cross-origin data access, they could now access my private photo and spread it out.
The same can happen in CSS, there could be user-specific CSS generated by the facebook server that contains user ids of my private
friends. They are not so private anymore if any website I can go to can just link to that css and start reading it.
And yes, the main issue is how browsers send cookies with cross-origin request, if the browser didn't send cookies when requesting
facebook images/css from evil.com, then facebook could not respond with user-specific css or my private photos because the cookies
were necessary to recognize me.
Now imagine if browsers didn't send cookies. Evil.com could still access any intranet data this way because my browser has access to the intranet. Being able to show http://intranet/Myboss.jpg as an image on evil.com website is not a problem, but Evil.com being able to read the image data and thus be able to copy and spread it is a problem.
You can iterate over the cssRules, build an array of all the ::first-letter rules, and then check if the element has one of these rules.
Working DEMO (Tested in Chrome only)
(function() {
var firstLetterRules = [];
var loadRules = function() {
var stylesheets = document.styleSheets;
for (var i = 0; i < stylesheets.length; i++) {
var stylesheet = stylesheets[i];
var rules = stylesheet.cssRules;
for (var k = 0; k < rules.length; k++) {
var rule = rules[k];
if (rule.selectorText.indexOf("::first-letter") !== -1) {
//It is a ::first-letter selector. Add the rule to a list of ::first-letter rules.
firstLetterRules.push(rule.selectorText.toUpperCase());
}
}
}
};
window.hasFirstLetterStyle = function(element) {
var fullSelector = element.nodeName;
if (element.className != '')
fullSelector += '.' + element.className;
fullSelector = fullSelector.toUpperCase() + "::FIRST-LETTER";
for (var i = 0; i < firstLetterRules.length; i++) {
if (fullSelector == firstLetterRules[i])
return true;
}
return false;
};
loadRules();
})();
var element = document.getElementById("init");
if (hasFirstLetterStyle(element)) {
console.log("Element has a first-letter style rule.");
}
You cannot.
Pseudo-selectors and their styles are not accessible from your JS code.
The closest you can do is check whether the element has the relevant class that would trigger the first-letter styles, and make the assumption in your JS code that if the class is there, then the first-letter style must have been applied.
There really isn't any other way, short of parsing your way through the whole CSS file manually.
This also applies to other pseudo-selectors and pseudo-elements (you'll find a number of similar questions around here asking similar questions about :before and :after, with similar answers)

Making a Same Domain iframe Secure

tl;dr Can I execute un-trusted scripts on an iframe safely?
Back story:
I'm trying to make secure JSONP requests. A lot of older browsers do not support Web Workers which means that the current solution I came up with is not optimal.
I figured I could create an <iframe> and load a script inside it. That script would perform a JSONP request (creating a script tag), which would post a message to the main page. The main page would get the message, execute the callback and destroy the iframe. I've managed to do this sort of thing.
function jsonp(url, data, callback) {
var iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
var iframedoc = iframe.contentDocument || iframe.contentWindow.document;
sc = document.createElement("script");
sc.textContent = "(function(p){ cb = function(result){p.postMessage(result,'http://fiddle.jshell.net');};})(parent);";
//sc.textContent += "alert(cb)";
iframedoc.body.appendChild(sc);
var jr = document.createElement("script");
var getParams = ""; // serialize the GET parameters
for (var i in data) {
getParams += "&" + i + "=" + data[i];
}
jr.src = url + "?callback=cb" + getParams;
iframedoc.body.appendChild(jr);
window.onmessage = function (e) {
callback(e.data);
document.body.removeChild(iframe);
}
}
jsonp("http://jsfiddle.net/echo/jsonp/", {
foo: "bar"
}, function (result) {
alert("Result: " + JSON.stringify(result));
});
The problem is that since the iframes are on the same domain, the injected script still has access to the external scope through .top or .parent and such.
Is there any way to create an iframe that can not access data on the parent scope?
I want to create an iframe where scripts added through script tags will not be able to access variables on the parent window (and the DOM). I tried stuff like top=parent=null but I'm really not sure that's enough, there might be other workarounds. I tried running a for... in loop, but my function stopped working and I was unable to find out why.
NOTE:
I know optimally WebWorkers are a better isolated environment. I know JSONP is a "bad" technique (I even had some random guy tell me he'd never use it today). I'm trying to create a secure environment for scenarios where you have to perform JSONP queries.
You can't really delete the references, setting null will just silently fail and there is always a way to get the reference to the parent dom.
References like frameElement and frameElement.defaultView etc. cannot be deleted. Attempting to do so will either silently fail or throw exception depending on browser.
You could look into Caja/Cajita though.
tl;dr no
Any untrusted script can steal cookies (like a session id!) or read information from the DOM like the value of a credit card input field.
JavaScript relies on the security model that all code is trusted code. Any attempts at access from another domain requires explicit whitelisting.
If you want to sandbox your iframe you can serve the page from another domain. This does mean that you can't share a session or do any kind of communication because it can be abused. It's just like including an unrelated website. Even then there are possibilities for abuse if you allow untrusted JavaScript. You can for instance do: window.top.location.href = 'http://my.phishing.domain/';, the user might not notice the redirect.

Count visits to various sites in JavaScript

I am trying to write a Chrome extension that keeps track of how many times one visits a given news site and directs the user to other sites when they've been reading the same one too often. is there a way to do this by looking at the URL on each page load? The pseudocode would be, taking the NY Times as an example:
var nytimesCount = 0;
if (URL includes "nytimes.com")
{
nytimesCount++;
}
Pretty simple. Is there a way to do this? Would using cookies (as per this question: Counting page visits with javascript and cookies), or some other method altogether, be easier?
You can get the URL origin with javascript using window.location.origin, and store your data in an array with the indices being the name of the origin, such as:
if (typeof visitedSites[window.location.origin] !== 'undefined') {
visitedSites[window.location.origin] += 1;
} else {
visitedSites[window.location.origin] = 1;
}
In terms of saving the data, I would look into using HTML5 local storage, which will work great in Chrome. http://diveintohtml5.info/storage.html

Categories

Resources