I am an absolute beginner in JS.
1) What I'm trying to do:
My web pages are composed of an index.php which is the same for all the files of a directory and one of a set of content.inc, like this: index.php?open=content.inc. This is done by a PHP snippet in the index.php and works well.
However, Google indexes all the content.inc files. The user's browser then displays the content.inc without the framing index.php. This I want to avoid. I therefore add a modest script at the beginning of each content.inc (which I would convert into a function once it runs) to tell the browser that instead of displaying the content.inc, it should display index.php?open=content.inc.
2) My unworkable solution:
var url = window.location.pathname;
var filename = url.substring(url.lastIndexOf('/')+1);
if (filename.indexOf("index.php") = -1)
{ var frame_name = "index.php?open="+filename;
window.location.replace(frame_name);
};
The browser (Firefox 60) ignores this; it displays content.inc. (I also have versions of this script which get the browser into an endless loop.)
What is wrong here? Please help!
PS: Please be assured that I have done extensive web search on this problem and found many pages of complaints about location.replace getting into an infinite loop; but none matches my situation. However, I gratefully accept a helpful link as an answer.
For starters, you have an error in this line:
if (filename.indexOf("index.php") = -1)
That's an assignment and will always evaluate to true, you need to use == or === (which should be more performant).
The guilty line is on your test case (see JP de la Torre answer). And to improve, here's a snippet to demo how to analyze the url with a regular expression :
function redirect(url) {
if(url && url.indexOf('.inc') >= 0) {
return url.replace(/\/(\w+)\.inc/, '/index.php?open=$1');
}
return url;
}
let urls = [
window.location.href,
'http://google.fr',
'http://example.com/index.php?open=wazaa',
'http://example.com/wazza.inc'
];
urls.forEach(url => {
console.log(url, ' => ', redirect(url));
});
The regexp will capture any text between a / and .inc. You can use it then as replacement value with the $1.
And applied to your case, you simply need :
if(window.location.href.indexOf('.inc') >= 0) {
window.location.href = window.location.href.replace(/\/(\w+)\.inc/, '/index.php?open=$1');
}
You can also use .htaccess server side to redirect request for .inc files on your index.php if mod_rewrite is enabled.
The solution to the problem of including an INC file called separately is the one proposed by Bertrand in his second code snippet above. It presupposes (correctly) that the inc extension is omitted in the replacement.
As I reported above, Firefox may get into an endless loop if it opens a PHP file directly, i.e. without involving the local host (with its php module).
This question is about scripting the main youtube site, client side from javascript.
While it looks easy as a click, I found no way to change the current video by a new non in context video ID without reloading.
This seems to be related with the polymer library in use, with a lot of shadow dom and some special behavior.
Here is the context: I am making for my own use a bookmarklet that load videos from the reddit json api, wich supports CORS calls.
So far so good, I can load many videos, image previews and links into the youtube sidebar, with this simple enough handcrafted script.
Bookmarklet to call the script:
javascript:void%20function(){target=document.getElementsByTagName(%22script%22)[0],inj=document.createElement(%22script%22),inj.src=%22https://webdev23.github.io/reddube/reddube.js%22,target.appendChild(inj)}();
This bookmarklet is loading into the DOM a js file, that is parsing the json api to get what I need.
Here is the content of the called file:
var reds = ["/r/videos","/r/unknownvideos","/r/DeepIntoYouTube","/r/newsreels","/r/fullmoviesonyoutube","/r/SF_Videos","/r/classicfilms","/r/Documentaries","/r/artdocumentaries","/r/ShowsonYT","/r/YTPL","/r/NotTimAndEric","/r/youtubehaiku","/r/PlayItAgainSam","/r/ObscureMedia","/r/360video","/r/AccidentalComedy","/r/amibeingdetained","/r/ArtisanVideos","/r/AwfulCommercials","/r/bestofworldstar","/r/cringe","/r/CommercialCuts","/r/contagiouslaughter","/r/cookingvideos","/r/curiousvideos","/r/deepintoyoutube","/r/documentaries","/r/educativevideos","/r/FastWorkers","/r/fightporn","/r/FuckingWithNature","/r/fullmoviesonyoutube","/r/happycrowds/","/r/idiotsfightingthings","/r/lectures","/r/mealtimevideos","/r/motivationvideos","/r/ObscureMedia","/r/playitagainsam","/r/Prematurecelebration","/r/PublicFreakout","/r/Roadcam","/r/streetfights","/r/sweetjustice","/r/TheWayWeWereOnVideo","/r/trailers","/r/UnexpectedThugLife","/r/videoporn","/r/vids","/r/vines","/r/virtualfreakout","/r/woahtube","/r/listentothis/","/r/Tekno/","/r/reggae/","/r/RootsReggae","r/ska","/r/dub","/r/hip_hop","/r/treemusic/","/r/stonerrock/","/r/frenchrap/","/r/trance/","/r/minimal/"]
var rview = ["","/new/","/rising/","/controversial/","/top/"]
related.innerHTML = "<div style='filter: sepia(38%) invert(100%) saturate(100%) brightness(1) grayscale(0%) hue-rotate(360deg) contrast(100%)'><span id='subR' data-ccc='25' style='color:white;background:#141e1b;font-size:1.44em;width:20px'></span><input type='range' value='0' max='64' id ='redR' style='float:right;width:230px' onchange='redList.innerHTML=\"\";redd(this.value)'><br><span onclick='redList.innerHTML=\"\";' style='float:right;margin:3px 0 0 0'><button id='rflt' data-filter='0' onclick='this.dataset.filter=0;redd(redR.value)'>hot</button><button onclick='rflt.dataset.filter=1;redd(redR.value)'>new</button><button onclick='rflt.dataset.filter=2;redd(redR.value)'>rising</button><button onclick='rflt.dataset.filter=3;redd(redR.value)'>controversial</button><button onclick='rflt.dataset.filter=4;redd(redR.value)'>top</button></span><hr /><hr /><hr /><hr /><hr /><tr><br></div><div id='redList'>"
function redd(it){
console.log(it)
console.log(reds[1])
subR.innerHTML = reds[it]
xhr = new XMLHttpRequest
xhr.open("GET","https://www.reddit.com"+reds[it]+rview[rflt.dataset.filter]+".json?limit=200",true)
xhr.send(null)
xhr.onreadystatechange = function() {
if (xhr.readyState === xhr.DONE) {
if(this.status === 200) {
vids = JSON.parse(xhr.responseText)
cc = subR.dataset.ccc
for (var j=0;j<=cc;j++){
try{
var rt = vids['data']['children'][j]['data']['title'],
rl = vids['data']['children'][j]['data']['url'],
rp = vids['data']['children'][j]['data']['secure_media']['oembed']['thumbnail_url'],
rr = vids['data']['children'][j]['data']['permalink']
redList.innerHTML += "<td><a href='"+rl+"'><img style='width:150px;height:auto;max-width:120px' src='"+rp+"'></img></a><span style='max-width:68%;float:right;text-align:center;font-size:1.23em'><a class='yt-simple-endpoint style-scope ytd-compact-video-renderer' style='text-decoration:bold;font-size:1.23em;text-align:left;min-width:260px' href='"+rl+"'>"+rt+"</a><a target='blank' style='text-decoration:bold;color:black;float:right' href='https://www.reddit.com"+rr+"'>⮊</a></span></td><br>"
}catch(e){console.log(e)}
}
}
}
}
}
related.innerHTML += "</tr><button onclick='redList.innerHTML=\"\";redd(redR.value)'>Load more</button>"
redd(0)
window.onscroll = function() {
var d = document.documentElement,
offset = d.scrollTop + window.innerHeight,
height = d.offsetHeight
if (offset >= '2000' && offset <= '2300') {
subR.dataset.ccc = 25
}
if (offset >= '2000' && offset <= '2100') {
subR.dataset.ccc = 50
}
if (offset >= '3400' && offset <= '3500') {
subR.dataset.ccc = 100
}
if (offset >= '5400' && offset <= '5500') {
subR.dataset.ccc = 150
}
if (offset >= '7400' && offset <= '7500') {
subR.dataset.ccc = 200
}
}
At this stage, clicking a link is just reloading the page.
I tried many things, changing the content of elements, try to alter the "next" recommended video.
Also creating a link in the DOM, isn't working, it is reloading.
Here is the problem in a simple way:
Let's say you are in this yt page https://www.youtube.com/watch?v=YgGzAKP_HuM
From the console, how to load this non related id -q7ZVXOU3kM
into the page, just like a link click on the recommendation sidebar?
The following is NOT working: Visibility monitor is not attached
xhr = new XMLHttpRequest
xhr.open("GET","https://www.youtube.com/watch?v=-q7ZVXOU3kM",true)
xhr.send(null)
document.body.innerHTML = xhr
18 OF MARCH 2018: END OF BOUNTY: QUESTION UNRESOLVED!!!
This is a fairly complex stuff.
The dom content is constantly changing at every reload, and it include recommended video id into the changing scripts. This id's only are allowed to use the ajax capabilities.
This recommendation are changing at any reload, but they are coming back in loop.
I am building a tool to deeply analyse differences, and i found many interesting things, much more that I was searching.
This topic isn't close!
It's not about the destination, it's about the journey.
Despite the videoId being YgGzAKP_HuMif you inspect the <video> you will see something like that:
<video class="video-stream html5-main-video" src="blob:https://www.youtube.com/8e1ef216-1901-ec44-9b76-ea8276e368c6"></video>
You need to find how youtube create their Blob from a videoId and change the src of the player if you want to avoid reloading the page.
But maybe for your project you should think about using the IFrame Player API. It does exactly what you want. And if you want to stay on youtube.com you can replace the youtube original player by an iframe in the DOM.
Good Luck!
it appears that there is no (public) api for the player on youtube :/
but there is one for the iframe youtube player - there you can just call
player.loadVideoById("Vw4KVoEVcr0", 0, "default");
for details see https://developers.google.com/youtube/iframe_api_reference#loadVideoById
That is a quick example I found where you see it in action: http://jsfiddle.net/QtBlueWaffle/8bpQ8/1/
If you really want to directly modify youtube you probably have to dig around in the obfuscated code :/ I tried to find it... but it's obfuscated so you can't easily find it. And even if you find it it will be something like _yt_player.h.xx.xy.h(). Also whenever it will be generated new (and maybe even it is even different for countries... ) your code may break.
Also, it appears to have nothing to do with polymer as there is a player element but it does not have a function to change the video. Apparently, it is only to place the player... control still resides within the js function.
I'm sorry to not have any better news - maybe someone else knows more.
Trying to find a hidden YouTube API is incredibly difficult and it's likely that the next tweak Google makes to YouTube will break your bookmarklet and you'd be back where you started. I think you should take another route altogether. Google provides an API to create, delete, and otherwise manipulate YouTube playlists here: https://developers.google.com/youtube/v3/docs/playlists.
If you’ve never used YouTube API before, see here: https://developers.google.com/youtube/v3/getting-started
Then, (finally!) you can write some JavaScript that creates YouTube playlists from reddit at your command.
My Javascript is poor, but I have made a site with subpages that are loaded by revealing divs using Javascript functions: http://thenethersphere.com/ Observe the Gateway page is loaded by default, which is fine.
My objective is to determine which of the three URL is being requested by the client, e.g. #gateway (default), #comms, or #library and trigger the requisite function to actually load a subpage if the user goes to, e.g. thenethersphere.com/#comms or thenethersphere.com/gateway.vs#comms would cause the page to run showComms(), which looks basically like this:
function showComms() {
hideGateway();
hideLibrary();
document.getElementById("comms").style.left = "11em";
document.getElementById("comms").style.visibility = "visible";
document.getElementById("lcarsmain1").style.color = "#FF9900";
document.getElementById("lcarsmain2").style.color = "#FF9900";
document.getElementById("lcarsmain3").style.color = "#FF9900";
}
Use the location.hash to get the relevant part of the url and call the appropriate function ..
example
var section = location.hash.slice(1);
if (section == 'comms') showComms();
Client has two websites: desktop and mobile (don't ask why desktop isn't responsive).
Desktop site has many pages that are actually just anchors within a page. E.g. aboutus.html#team that now has to redirect to team.html when someone is viewing on a small mobile device. And all mobile pages have different names than desktop pages (aboutus.html = about-us.html).
Rather than put code on every single page to redirect that individual page (which leaves no way to redirect the anchored URLs) it's been suggested to use an array for the desktopURLs and a related array for the mobileURLs.
So (note I omitted the // after http: so they don't show up as links since I don't have enough points to post links):
var desktopURL = ['http:domain.com/aboutus.html','http:domain.com/aboutus.html#/team','http:domain.com/contactus.html']
var mobileURL = ['http:m.domain.com/about-us.html','http:m.domain.com/team.html','http:m.domain.com/contact-us.html']
Once I have that set up, where desktopURL index 1 = mobileURL index 1.
I need to basically say this in code:
Get the window.location.href and look it up in desktopURL and return the index value.
Once you have the index value of desktopURL for the current window, update window.location.href with the object of the matching index number from the mobileURL array.
So that, when I'm a person on a phone and I go to domain.com/aboutus.html I am automatically redirected to m.domain.com/about-us.html
Note that I cannot change the names of any of the pages on the mobile site (making them match the original site would have made this easy). So I need to figure out a code way to do this and I have researched extensively but am just not sure how to achieve this simple task.
Here is the JS:
var desktopURL = ['aboutus.html','aboutus.html#team','contactus.html']
var mobileURL = ['about-us.html','team.html','contact-us.html']
//Get the name of current page
var currPage=(window.location.href).split("/")[(window.location.href).split("/").length-1];
console.log(currPage);
var index=desktopURL.indexOf(currPage);
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
window.location.href=mobileURL[index];
}
Check redirecttest[dot]webuda[dot]com
What you are looking to accomplish is better handled with an object lookup. Managing two arrays, as you have suggested, is very fragile solution (no real relationship exists there, which will make it difficult to scale/maintain).
var MOBILE_ROOT = 'm.domain.com';
var LOOKUP = {
'/aboutus.html': '/about-us.html',
'/aboutus.html#/team': '/team.html',
'/contactus.html': '/contact-us.html'
};
function redirect () {
var path = window.location.pathname;
var hash = window.location.hash;
window.location.href = MOBILE_ROOT + LOOKUP[ path + hash ];
}
...
if ( //user agent lookup goes here ) {
redirect();
}
So I've been stuck on this for quite a while. I asked a similar question here: How exactly does done() work and how can I loop executions inside done()?
but I guess my problem has changed a bit.
So the thing is, I'm loading a lot of streams and it's taking a while to process them all. So to make up for that, I want to at least load the streams that have already been processed onto my webpage, and continue processing stream of tweets at the same time.
loadTweets: function(username) {
$.ajax({
url: '/api/1.0/tweetsForUsername.php?username=' + username
}).done(function (data) {
var json = jQuery.parseJSON(data);
var jsonTweets = json['tweets'];
$.Mustache.load('/mustaches.php', function() {
for (var i = 0; i < jsonTweets.length; i++) {
var tweet = jsonTweets[i];
var optional_id = '_user_tweets';
$('#all-user-tweets').mustache('tweets_tweet', { tweet: tweet, optional_id: optional_id });
configureTweetSentiment(tweet);
configureTweetView(tweet);
}
});
});
}};
}
This is pretty much the structure to my code right now. I guess the problem is the for loop, because nothing will display until the for loop is done. So I have two questions.
How can I get the stream of tweets to display on my website as they're processed?
How can I make sure the Mustache.load() is only executed once while doing this?
The problem is that the UI manipulation and JS operations all run in the same thread. So to solve this problem you should just use a setTimeout function so that the JS operations are queued at the end of all UI operations. You can also pass a parameter for the timeinterval (around 4 ms) so that browsers with a slower JS engine can also perform smoothly.
...
var i = 0;
var timer = setInterval(function() {
var tweet = jsonTweets[i++];
var optional_id = '_user_tweets';
$('#all-user-tweets').mustache('tweets_tweet', {
tweet: tweet,
optional_id: optional_id
});
configureTweetSentiment(tweet);
configureTweetView(tweet);
if(i === jsonTweets.length){
clearInterval(timer);
}
}, 4); //Interval between loading tweets
...
NOTE
The solution is based on the following assumptions -
You are manipulating the dom with the configureTweetSentiment and the configureTweetView methods.
Ideally the solution provided above would not be the best solution. Instead you should create all html elements first in javascript only and at the end append the final html string to a div. You would see a drastic change in performance (Seriously!)
You don't want to use web workers because they are not supported in old browsers. If that's not the case and you are not manipulating the dom with the configure methods then web workers are the way to go for data intensive operations.