I have these scripts which are almost the same but I'm unable to merge them into one..
also I want remove "CDATA" and keep the script functioning in blogger XML template
<script type='text/javascript'>// <![CDATA[
!function(){const e=document.querySelectorAll(".vplayer");for(var t=0;t<e.length;t++){console.log(e[t].dataset.v);const a="//i.ytimg.com/vi_webp/"+e[t].dataset.v+"/hqdefault.webp";var n=new Image;n.src=a,n.addEventListener("load",void e[t].appendChild(n)),e[t].addEventListener("click",function(){const e=document.createElement("iframe");e.setAttribute("allowfullscreen",""),e.setAttribute("frameborder","0"),e.setAttribute("src","//www.youtube.com/embed/"+this.dataset.v+"?rel=0&showinfo=0&autoplay=1&iv_load_policy=3&modestbranding=1&noCookie=false&origin=https%3A%2F%2Fwww.xotaku.com&widgetid=1"),this.innerHTML="",this.appendChild(e)})}}();// ]]></script>
and that the second
<script type='text/javascript'>// <![CDATA[
!function(){const e=document.querySelectorAll(".vplayerold");for(var t=0;t<e.length;t++){console.log(e[t].dataset.v);const a="//i.ytimg.com/vi/"+e[t].dataset.v+"/hqdefault.jpg";var n=new Image;n.src=a,n.addEventListener("load",void e[t].appendChild(n)),e[t].addEventListener("click",function(){const e=document.createElement("iframe");e.setAttribute("allowfullscreen",""),e.setAttribute("frameborder","0"),e.setAttribute("src","//www.youtube.com/embed/"+this.dataset.v+"?rel=0&showinfo=0&autoplay=1&iv_load_policy=3&modestbranding=1&noCookie=false&origin=https%3A%2F%2Fwww.xotaku.com&widgetid=1"),this.innerHTML="",this.appendChild(e)})}}();// ]]></script>
the scripts are the same and I dont want write the whole of it twice
I want this
const e = document.querySelectorAll(".vplayer");
to work with that
const a = "//i.ytimg.com/vi_webp/" + e[t].dataset.v + "/hqdefault.webp";
and this
const e = document.querySelectorAll(".vplayerold");
to work with that
const a="//i.ytimg.com/vi/"+e[t].dataset.v+"/hqdefault.jpg";
the rest of scripte work with both as well
I want remove "CDATA" and keep the script functioning in blogger XML template
That's not possible. It's pretty much required for valid XML unless you want to use escape sequences for <>'".
the scripts are the same and I dont want write the whole of it twice
Make that IEFE a named function declaration, give it parameters, call it twice with different arguments.
<script type="text/javascript">//<![CDATA[
function createPlayer(selector, makeUrl) {
const e = document.querySelectorAll(selector);
for (var t = 0; t < e.length; t++) {
console.log(e[t].dataset.v);
const a = makeUrl(e[t].dataset.v);
var n = new Image;
n.src = a;
n.addEventListener("load", void e[t].appendChild(n));
e[t].addEventListener("click", function() {
const e = document.createElement("iframe");
e.setAttribute("allowfullscreen", "");
e.setAttribute("frameborder", "0");
e.setAttribute("src", "//www.youtube.com/embed/" + this.dataset.v + "?rel=0&showinfo=0&autoplay=1&iv_load_policy=3&modestbranding=1&noCookie=false&origin=https%3A%2F%2Fwww.xotaku.com&widgetid=1");
this.innerHTML = "";
this.appendChild(e);
})
}
}
createPlayer(".vplayer", v => "//i.ytimg.com/vi_webp/" + v + "/hqdefault.webp");
createPlayer(".vplayerold", v => "//i.ytimg.com/vi/" + v + "/hqdefault.jpg");
//]]></script>
Merged example
You mean like this?
<script type='text/javascript'>// <![CDATA[
!function(){const e=document.querySelectorAll(".vplayer");for(var t=0;t<e.length;t++){console.log(e[t].dataset.v);const a="//i.ytimg.com/vi_webp/"+e[t].dataset.v+"/hqdefault.webp";var n=new Image;n.src=a,n.addEventListener("load",void e[t].appendChild(n)),e[t].addEventListener("click",function(){const e=document.createElement("iframe");e.setAttribute("allowfullscreen",""),e.setAttribute("frameborder","0"),e.setAttribute("src","//www.youtube.com/embed/"+this.dataset.v+"?rel=0&showinfo=0&autoplay=1&iv_load_policy=3&modestbranding=1&noCookie=false&origin=https%3A%2F%2Fwww.xotaku.com&widgetid=1"),this.innerHTML="",this.appendChild(e)})}}();
!function(){const e=document.querySelectorAll(".vplayerold");for(var t=0;t<e.length;t++){console.log(e[t].dataset.v);const a="//i.ytimg.com/vi/"+e[t].dataset.v+"/hqdefault.jpg";var n=new Image;n.src=a,n.addEventListener("load",void e[t].appendChild(n)),e[t].addEventListener("click",function(){const e=document.createElement("iframe");e.setAttribute("allowfullscreen",""),e.setAttribute("frameborder","0"),e.setAttribute("src","//www.youtube.com/embed/"+this.dataset.v+"?rel=0&showinfo=0&autoplay=1"),this.innerHTML="",this.appendChild(e)})}}();
// ]]>
</script>
Adding them in separate script tags should also work, depending what your backend allows you to do.
Related
I have made an offline web application:
<!DOCTYPE html>
<html dir="rtl">
<head>
<meta charset="utf-8">
<style><!-- some style here --></style>
<script>
var rqid = location.hash.replace('#','');
var js = Math.ceil(rqid / 100);
var id = rqid - ((js - 1) * 100) - 1;
var tg = document.createElement('script')
tg.src = js + '.js'
tg.type = 'text/javascript'
document.head.appendChild(tg);
window.onload = function load() {
var body='<h1>' + title[id] + '</h1> <article>' + content[id] + '</article>';
document.getElementById("body").innerHTML = body;}
</script>
</head>
<body id='body'>
</body>
</html>
The above is the simplified article.html file, which shows articles stored inside external .js files, each with two variables.
1.js contains
title = ['title of article1','title of article2',...,'title of article100'];
content = ['content of article1','content of article2',...,'content of article100'];
2.js contains
title = ['title of article101','title of article102',...,'title of article200'];
content = ['content of article101','content of article102',...,'content of article200'];
For example, article.html#1 loads 1.js into the html, and then shows article1, and article.html#101 loads 2.js and shows article101.
It works fine, but there's a problem with the search engine I have written for this application. The search engine code is quite bulky. Sharing it here will not be possible.
The problem is the identical variables in the .js files, which are overridden one after one.
<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
So, search is done only in 3.js.
The question is: Is it possible to dynamically join title/content arrays in those .js files and have a unified title/content variable like the following, so the search can be performed in all articles?
title = ['title of article1',...,'title of article200'];
content = ['content of article1',...,'content of article200'];
If it is not possible, simply say no but please do not recommend to restructure the stored data.
I would add that the speed/performance is not a problem, in case it is going to be slow.
Here is a simple example of how you could do this without having to restructure your 1.js, 2.js..
For the purpose of this example I've created a pretend fetch, that can get 1.js, & 2.js, if you have any real URL's to test, we should be able to replace the fetch mock with a real one.
const pretenddata = {
"1.js":
`title = ['title of article1','title of article2','title of article100'];
content = ['content of article1','content of article2','content of article100']`,
"2.js": `title = ['title of article101','title of article102','title of article200'];
content = ['content of article101','content of article102','content of article200'];`
};
//lets create a pretend fetch..
function fetch(url) {
function astext() {
return new Promise((resolve) => {
resolve(pretenddata[url]);
});
}
return new Promise((resolve) => {
resolve({text: astext});
});
}
async function test() {
var combined_title = [];
var combined_content = [];
async function getData(url) {
const r = await(await fetch(url)).text();
var d = new Function(`${r}; return [title, content]`)();
combined_title = combined_title.concat(d[0]);
combined_content = combined_content.concat(d[1]);
}
await Promise.all([
getData("1.js"),
getData("2.js")
]);
console.log(combined_title);
console.log(combined_content);
}
test();
When working with globals across multiple files, it is always a good idea to use some kind of globals structure, that way it is much more explicit as to the fact that the data is, in fact, global, and it makes it much less likely to cause issues with scope pollution.
In your case, you can create a basic object called "globals", which will have a title and content property, just like you were with your global variables. In fact, those actually go on the window object by default, so it works exactly the same - just instead of saying window.title, you can say globals.title, etc. The only difference being that the variables will never be accessed accidentally by default scoping.
window.globals = {};
// file1
(function () {
var title = ['title of article1','title of article2','title of article100'];
var content = ['content of article1','content of article2','content of article100'];
globals.title = globals.title ? globals.title.concat(title) : title;
globals.content = globals.content ? globals.content.concat(content) : content;
})();
// file2
(function () {
var title = ['title of article101','title of article102','title of article200'];
var content = ['content of article101','content of article102','content of article200'];
globals.title = globals.title ? globals.title.concat(title) : title;
globals.content = globals.content ? globals.content.concat(content) : content;
})();
// file3
(function () {
var title = ['title of article201','title of article202','title of article300'];
var content = ['content of article201','content of article202','content of article300'];
globals.title = globals.title ? globals.title.concat(title) : title;
globals.content = globals.content ? globals.content.concat(content) : content;
})();
// final results
console.log(globals.title);
console.log(globals.content);
I'm trying to create a script that will make it easier for users to use a custom button and I have something like
<script src="http://host.com/file.js?id=12345"></script>
What I wonder is how can I, in the file.js get that id parameter.
if I use document, it will get the original html page that has the script line and what I need is that id.
is there any way i can get that id successfully? What should be the scope?
added
the idea is that I can have several buttons in the page for example to have a small and simply list:
<ul>
<li><script src="http://host.com/file.js?id=12345"></script></li>
<li><script src="http://host.com/file.js?id=23456"></script></li>
<li><script src="http://host.com/file.js?id=34567"></script></li>
</ul>
this will ultimately translate to
<ul>
<li><a class="view40btn" href="#" data-id="12345"><strong>V40</strong> Watch the video</a></li>
<li><a class="view40btn" href="#" data-id="23456"><strong>V40</strong> Watch the video</a></li>
<li><a class="view40btn" href="#" data-id="34567"><strong>V40</strong> Watch the video</a></li>
</ul>
the list above will look like this in HTML:
My only issue is that I can't assign the correct id to the data-id attribute as this is generated in the file.js.
result
from Paulpro answer I got it working with his idea and knowing that the client will have much more scripts loaded and several with id's I changed it a bit for the final and working version:
var id = (function(){
var scripts = document.getElementsByTagName('script');
for(var i = 0, result = {}; i < scripts.length; i++)
if(scripts[i].hasAttribute('data-viewfileid'))
result['id'] = decodeURIComponent(scripts[i].getAttribute('data-viewfileid'));
return result['id'];
})();
var html = '<a class="view40btn" href="#" data-id="' + id + '"><strong>V40</strong> Watch the video</a>';
document.write(html);
the script for the user would only be:
<script data-viewfileid="4444" src="file.js" type="text/javascript"></script>
You can get the last script element on the page (which will always be the currently executing one):
var scripts = document.getElementsByTagName('script');
var s = scripts[scripts.length - 1];
Then modify one of the query string parsers from this question to work with that scripts src property:
var url = s.src;
var qs = url.substring(url.indexOf('?') + 1).split('&');
for(var i = 0, result = {}; i < qs.length; i++){
qs[i] = qs[i].split('=');
result[qs[i][0]] = decodeURIComponent(qs[i][2]);
}
That will give you an object containing all the query string properties on the current script. You can just access the properties like:
result['id']; // '12345'
In summary
To get the id parameter from within file.js, add the following code to the top of file.js:
var id = (function(){
var scripts = document.getElementsByTagName('script');
var s = scripts[scripts.length - 1];
var qs = s.src.substring(s.src.indexOf('?') + 1).split('&');
for(var i = 0, result = {}; i < qs.length; i++){
qs[i] = qs[i].split('=');
result[qs[i][0]] = decodeURIComponent(qs[i][3]);
}
return result['id'];
})();
Make sure it is not in any callback functions like a DOMReady callback.
Edit: You can probably reduce your script to:
var scripts = document.getElementsByTagName('script');
var id = scripts[scripts.length - 1].getAttribute('data-viewfileid');
var html = '<a class="view40btn" href="#" data-id="' + id + '"><strong>V40</strong> Watch the video</a>';
document.write(html);
JavaScript doesn't know anything about the script tag that loaded it. However, there are a few workarounds.
If the file is being preprocessed on the server, you could make the server render the value in the response:
(function() {
var id = <%= params.id %>;
//other stuff here
}());
Or you could give the script tag an id, and make your code find it and pull out the URL.
HTML:
<script src="http://host.com/file.js?id=12345" id="myscript"></script>
JS:
var id = document.getElementById('myscript').split('id=')[1];
Or in modern browsers you could perhaps do something like this to find script tags that match where you know the script is.
var scriptTag = document.querySelector('script[src^="http://host.com/file.js"]');
var id = scriptTag.src.split('id=')[1];
One more solution is to parse .js files with php interpreter. For example in apache configuration:
AddType application/x-httpd-php .js
And in JS:
alert('<?=$_GET["id"]?>');
You can put an ID on anything, including a script tag. So you can do something like this:
HTML:
<script id="myScript" src="http://host.com/file.js?id=12345"></script>
JS:
document.getElementById('myScript').src.split('=')[1]; to get the ID from that particular example string.
If that query string represents a timestamp (in which case you need the latest version) you can modify the JavaScript code to fetch the latest <script> tag like so:
var scripts = document.getElementsByTag('script');
var latestScriptId = scripts[scripts.length-1].src.split('=')[1];
EDIT: In the context of your new edit, you would then take latestScriptId and assign it to the data.id attribute corresponding to the button you would like to create...though again, semantically, it would just make more sense to use HTML's given id attribute, and additionally, since you are not using the href property for the anchor <a> tag, you're better off using a <button> element. So something like this would suffice:
var myButton = document.createElement('button');
myButton.className += 'view40btn';
myButton.id = latestScriptId;
According to your clarifications, what you asking how to do is not what you want to do.
Instead, include one script, and have multiple placeholder nodes.
HTML:
<ul>
<li class="mybutton" data-id="12345"></li>
<li class="mybutton" data-id="23456"></li>
<li class="mybutton" data-id="34567"></li>
</ul>
<script src="myscript.js"></script>
JS:
// myscript.js
var buttons = document.getElementsByClassName('mybutton');
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];
button.innerHTML = "my button html template here with id: "+ button.dataset.id;
}
See it work here: http://jsfiddle.net/zAdnB/
Javascript code does not "realise", that it is a part of some file. JS file is not "executable", there is no main method, which should be run after loading the file. You can not pass GET parameters to it - it is not clear how they should be interpreted.
In your HTML page, you should listen to "onload" method and then call the function from your file with your parameter.
I have this form:
<form id="searchForm" class="search_field" method="get" action="">
...
...
</form>
Then this javascript:
var form = document.getElementById("searchForm");
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
form.showFeatureChoices.onclick = function( )
{
var cbs = form.featType;
for ( var c = 0; c < cbs.length; ++c )
{
cbs[c].checked = false;
}
document.getElementById("featuresDiv").style.display = "block";
}
function searchPage()
{
var form = document.getElementById("searchForm");
var searchText = form.searchBox.value.replace(/-/g,"");
form.searchBox.value = searchText;
if (searchText != "")
{
// collect features to search for:
var features = [ ];
var featTypes = form.featType;
for ( var f = 0; f < featTypes.length; ++f )
{
if ( featTypes[f].checked ) features.push( featTypes[f].value );
}
featureList = "'" + features.join("','") + "'";
searchMsg("Searching for '" + searchText + "' ...");
// startStatusUpdate(1000);
// findTask.execute(findParams, showResults);
var accord = dijit.byId("accordianContainer");
var resultsPane = dijit.byId("resultsPane");
accord.selectChild(resultsPane,true);
doSearch( searchText, featureList );
}
else
{
searchMsg("No search criteria entered, enter search text");
}
}
If I embed this code in same file as the <form..., it works fine.
If however, I have this js in another file and use as include file:
<script type="text/javascript" src="Views/JS/main.js"></script>
I get following error: "Object required" and it points to these lines:
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
Any ideas how to fix this?
Just a bit more info, the js code shown above in a file called main.js which is in a folder called JS and Js is in a folder called Views. The
Thanks a lot in advance
When you include the JavaScript code in the same page, where is it in relation to the form element? (Before or after it?) How about when you reference the external JavaScript file?
I'm guessing that in the former case the code is at the end of the file, while in the latter case the script reference tag is at the beginning?
If that's true then what's happening is this code is being executed before the DOM is ready:
var form = document.getElementById("searchForm");
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
If the form tag hasn't been rendered to the DOM yet then that first line won't find anything, and the subsequent lines will fail as a result. One approach is to put the script reference tags at the end, but that seems like a hack to me. Sometimes there are good reasons to keep them in the page header, not the least of which is cleaner management of the code in many cases. There are other ways to hold off on executing JavaScript code until the DOM is ready.
For example:
<script>
$(document).ready( function() {
alert( $(this).getBelowElementToThisScript('form').id );
});
</script>
<form id="IamTheNext"></form>
<form id="Iamnot"></form>
This code should show this message: IamTheNext
In addition, the solution needs to work with this example too:
<script src="getbelowelement.js"></script>
<form id="IamTheNext"></form>
<form id="Iamnot"></form>
Thanks
Try this:
var form = $('script[src="getbelowelement.js"]').next();
But I would suggest using the forms id:
var form = $('#IamTheNext');
You could also try giving the script tag an id.
This kind of approach is dangerous; script should never depend that much on where it is in the page.
That said, the following works in Firefox and Chrome and should work in the major browsers (use at your own risk).
See it in action at jsBin. Both <script> ... and <script src="..."> approaches are shown in the same page.
$(document).ready( function () {
invocationsOfThis = (typeof invocationsOfThis == 'number') ? invocationsOfThis + 1 : 1;
var scriptTags = document.getElementsByTagName ('script');
var thisScriptTag = null;
//--- Search scripts for scripts of this type.
for (var foundCnt = 0, J = 0, L = scriptTags.length; J < L; ++J)
{
/*--- Since the script can be either inline or included, search
both the script text and the script src link for our unique
identifier.
*/
var thisTag = scriptTags[J];
var scriptCode = thisTag.innerText || thisTag.textContent;
var scriptSrc = thisTag.src;
//--- IMPORTANT, change pastebin.com to the filename that you use.
if (/invocationsOfThis/i.test (scriptCode) || /pastebin.com/i.test (scriptSrc))
{
//--- Found a copy of this script; is it the right one, based on invocation cnt?
foundCnt++;
if (foundCnt == invocationsOfThis) {
thisScriptTag = thisTag;
break;
}
}
}
if (thisScriptTag) {
//--- Get the target node.
var nextForm = $(thisScriptTag).next ('form');
var nextFormId = nextForm.attr ('id');
//--- Act on the target node. Here we notify the user
nextForm.text ('This is form: "' + nextFormId + '".');
}
} );
I would like to change the id of a tag from within the external script it points to. What is the proper way of doing this?
Here is my script tag:
<script id="ID1" type="text/javascript" src="PATH_TO_EXTERNAL_JS"></script>
And here is what I'm trying to do from within my external script:
var sessionID = generateSessionID();
var scripts = document.getElementsByTagName('script');
var script = scripts[scripts.length - 1];
script.id = script.id + "_" + sessionID;
However, when I look at the live DOM tree in firebug, i see 2 scripts referenced in the DOM. One with the original ID, and one with the new ID.
Thanks!
Use setAttribute
script.setAttribute("id", script.id + "_" + sessionID);
I think You should modify Your code, to somewhat like this:
var i = 0
var sessionID = generateSessionID();
var scripts = document.getElementsByTagName('script');
var script = null;
for (i = 0; i < scripts.length; i++)
if (scripts[i].src.toString() == 'PATH_TO_EXTERNAL_JS'){
script = scripts[i];
break;
}
if (script)
script.id = script.id + "_" + sessionID;
In other words. Get all the SCRIPT elements, iterate through this collection to look for an element that has some known attribute (src in this example) and if it's found, set it's new id.
You need to remove the old script, if your going to do it that way. Although Mike Lewis answer has a better method.
document.removeChild(originalScript)