Javascript blank page on web - javascript

I wanted to make my webpage a multi language page so I used the following js code:
let langs = ['en', 'it', 'sp', 'sv', 'de', 'pt', 'nl'];
let lang = 'en';
setLangStyles(lang);
function setStyles(styles) {
var elementId = '__lang_styles';
var element = document.getElementById(elementId);
if (element) {
element.remove();
}
let style = document.createElement('style');
style.id = elementId;
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = styles;
} else {
style.appendChild(document.createTextNode(styles));
}
document.getElementsByTagName('head')[0].appendChild(style);
}
function setLang(lang) {
setLangStyles(lang);
}
function setLangStyles(lang) {
let styles = langs
.filter(function (l) {
return l != lang;
})
.map(function (l) {
return ':lang('+ l +') { display: none; }';
})
.join(' ');
setStyles(styles);
}
I named it "lang.js" and I tagged it on my html this way:
<!-- jquery -->
<script src="js/jquery-2.1.4.min.js"></script>
<!-- Bootstrap -->
<script src="js/bootstrap.min.js"></script>
<script src="js/scripts.js"></script>
<script src="js/lang.js"></script>
Locally it works perfectly, but when it's on server, it doesn't open the webpage at all, all I see is a blank page.
I tried also to write it inside the html with script> tag, it didn't work either.
In network tab of dev tools, the jquery-2.1.4.min.js file and bootstrap files showing as 200 status.
There are no errors on console
Can anyone help please?
Thank you in advance

Here is my version of your function. It loops through the array of langs, then grabs a queryselectorAll of the matching lang elements. If the passed language matches the array element in the loop the display is set to block, else its set to none.
langs = ["en", "es"];
function setLangStyles(lang) {
for (z = 0; z < langs.length; z++) {
l = langs[z]
objs = document.querySelectorAll(":lang(" + l + ")");
objs.forEach(function(el) {
el.style.display = (l == lang) ? "block" : "none";
});
}
}
btns = document.querySelectorAll("button");
btns.forEach(function(e){
e.addEventListener("click",function(ev){
setLangStyles(ev.target.dataset.lang);
});
});
setLangStyles("es");
<div lang="en">EN</div>
<div lang="es">ES</div>
<button type="button" data-lang="es">View ES</button>
<button type="button" data-lang="en">View EN</button>

Related

csv does not seem to appear due to reference error

I am quite new to this all, so i am pretty sure this is a simple oversight on my part, but i cant get it to run.
When i deploy the code below and click on the button, it does not do anything. When i inspect the html in my browser, it says "userCodeAppPanel:1 Uncaught ReferenceError: csvHTML is not defined
at HTMLInputElement.onclick"
When i run the function csvHTML from Code.gs, I can see the expected results in my Logger.log, so it seems the problem does not lie in my code.gs
What i am trying to achieve is showing the csv results in html. When all works fine, i will want to work with the data in some other way.
Attached below is my code.
Index.html:
<!DOCTYPE html>
<!-- styles -->
<?!= HtmlService.createHtmlOutputFromFile("styles.css").getContent(); ?>
<div class="content">
<h1>csv representation</h1>
<input class="button" type="submit" onclick="html();" value="Refresh" id="refresh"><br>
<div id="tabel"></div>
<svg class="chart"></svg>
</div>
<!-- javascript -->
<script src="//d3js.org/d3.v3.min.js"></script>
<?!= HtmlService.createHtmlOutputFromFile("chart.js").getContent() ?>
<?!= HtmlService.createHtmlOutputFromFile("main.js").getContent() ?>
<script>
function html()
{
var aContainer = document.createElement('div');
aContainer.classList.add('loader_div');
aContainer.setAttribute('id', 'second');
aContainer.innerHTML = "<div class='loader_mesage'><center>Fetching csv list. Please be patient!<br /> <br /><img src='https://i.ibb.co/yy23DT3/Dual-Ring-1s-200px.gif' height='50px' align='center'></img></center></div>";
document.body.appendChild(aContainer);
google.script.run
.withSuccessHandler(showTable)
.csvHTML();
}
function showTable(tabel)
{
document.getElementById("tabel").innerHTML = tabel;
var element = document.getElementById("second");
element.parentNode.removeChild(element);
}
</script>
and Code.gs:
function doGet(e) {
return HtmlService.createTemplateFromFile("index.html")
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
// Fecth Data and make a csv output.
function csvHTML()
{
var query = "{ 'query': 'SELECT * FROM `<some table>` limit 1000;', 'useLegacySql': false }";
var job = BigQuery.Jobs.query(query, <projectName>);
var json = JSON.parse(job);
var tabel = json2csv(json);
Logger.log(tabel)
return tabel;
}
function json2csv(json, classes) {
var headerRow = '';
var bodyRows = '';
classes = classes || '';
json.schema.fields.forEach(function(col){
headerRow +=col.name+",";
})
json.rows.forEach(function(row){
row.f.forEach(function(cell){
bodyRows +=cell.v+",";
})
})
return headerRow + bodyRows }
So thanks to the suggestions by TheMaster, i rewritten it into the following:
index.html:
<!-- javascript -->
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
function html()
{
var aContainer = document.createElement('div');
aContainer.classList.add('loader_div');
aContainer.setAttribute('id', 'second');
aContainer.innerHTML = "<div class='loader_mesage'><center>Fetching csv list. Please be patient!<br /> <br /><img src='https://i.ibb.co/yy23DT3/Dual-Ring-1s-200px.gif' height='50px' align='center'></img></center></div>";
document.body.appendChild(aContainer);
google.script.run
.withSuccessHandler(showTable)
.csvHTML();
}
function showTable(tabel)
{
document.getElementById("tabel").innerHTML = tabel;
var element = document.getElementById("second");
element.parentNode.removeChild(element);
}
</script>
<!DOCTYPE html>
<div class="content">
<h1>csv representation</h1>
<input class="button" type="submit" onclick="html();" value="Refresh" id="refresh"><br>
<div id="tabel"></div>
<svg class="chart"></svg>
</div>
Code.gs has not been modified.
It appears that the <?!= htmlService.createHtmlOutputFromFile("styles.css").getContent(); ?> and other createHtmlOutputFromFile were getting in the way. Eventually i need these, but I will figure out how to incorporate that at a later stage.
Thanks for all the advice and help!
Disclaimer: I have zero experience with Google Apps Script, so take this with a grain of salt.
Looking at their documentation for BigQuery, it seems you are not querying the database correctly. I am surprised by your claim that Logger.log() shows the correct output. It does not appear that it should work.
In case I am right, here is what I propose you change your Code.gs file to:
function doGet(e) {
return HtmlService.createTemplateFromFile("index.html")
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
// Fetch Data and make a csv output.
function csvHTML() {
var results = runQuery('SELECT * FROM `<some table>` limit 1000;');
var tabel = toCSV(results);
Logger.log(tabel);
return tabel;
}
/**
* Runs a BigQuery query and logs the results in a spreadsheet.
*/
function runQuery(sql) {
// Replace this value with the project ID listed in the Google
// Cloud Platform project.
var projectId = 'XXXXXXXX';
var request = {
query: sql,
useLegacySQL: false
};
var queryResults = BigQuery.Jobs.query(request, projectId);
var jobId = queryResults.jobReference.jobId;
// Check on status of the Query Job.
var sleepTimeMs = 500;
while (!queryResults.jobComplete) {
Utilities.sleep(sleepTimeMs);
sleepTimeMs *= 2;
queryResults = BigQuery.Jobs.getQueryResults(projectId, jobId);
}
// Get all the rows of results.
var rows = queryResults.rows;
while (queryResults.pageToken) {
queryResults = BigQuery.Jobs.getQueryResults(projectId, jobId, {
pageToken: queryResults.pageToken
});
rows = rows.concat(queryResults.rows);
}
var fields = queryResults.schema.fields.map(function(field) {
return field.name;
});
var data = [];
if (rows) {
data = new Array(rows.length);
for (var i = 0; i < rows.length; i++) {
var cols = rows[i].f;
data[i] = new Array(cols.length);
for (var j = 0; j < cols.length; j++) {
data[i][j] = cols[j].v;
}
}
}
return {
fields: fields,
rows: rows
};
}
function toCSV(results) {
var headerRow = results.fields.join(',');
var bodyRows = results.rows.map(function(rowData) {
return rowData.map(function(value) {
// for proper CSV format, if the value contains a ",
// we need to escape it and surround it with double quotes.
if (typeof value === 'string' && value.indexOf('"') > -1) {
return '"' + value.replace(/"/g, '\\"') + '"';
}
return value;
});
})
.join('\n'); // join the lines together with newline characters
return headerRow + '\n' + bodyRows;
}
Reminder: I have not tested this, I'm purely writing this based on my knowledge of Javascript and their documentation and sample code.

style.display="none" works in else{} but not in if{}

JS:
function ToggleShow(lang_option){
var elements = document.getElementsByClassName(lang_option);
var langs = document.getElementsByClassName("lang");
for(var i=0,l=elements.length;i<l;i++){
if(elements[i] in langs){
elements[i].style.display="block";
}else{
elements[i].style.display="none";
}
}
}
HTML:
<button type="button" class="btn btn-primary" data-toggle="button" aria-pressed="false" autocomplete="off" onclick="ToggleShow('lang-compiled')">
Compiled
</button>
<div class="lang lang-interpreted">Python 3</div>
<div class="lang lang-compiled">C</div>
works, but if I reverse the two display functions (change elements[i].style.display="block"; to elements[i].style.display="none"; and vice versa), the buttons stop functioning without any errors in console.
if(elements[i] in langs){ tests if the element in question is a property of the langs HTMLCollection, which is of course always false. If you wanted to check if the element is included in the HTMLCollection, you might turn the HTMLCollection into an array and use .includes:
function ToggleShow(lang_option) {
var elements = document.getElementsByClassName(lang_option);
var langs = [...document.getElementsByClassName("lang")];
for (var i = 0, l = elements.length; i < l; i++) {
if (langs.includes(elements[i])) {
elements[i].style.display = "block";
} else {
elements[i].style.display = "none";
}
}
}
Or, you might trim your function to something like this, to keep your code DRY:
function ToggleShow(lang_option) {
var langs = [...document.getElementsByClassName("lang")];
document.querySelectorAll('.' + lang_option).forEach(element => {
element.style.display = langs.includes(element)
? 'block'
: 'none';
});
}
we use in to check a property in an object, not a value. Just need to change the expression of if block to make the code work...
function ToggleShow(lang_option) {
var elements = document.getElementsByClassName(lang_option);
var langs = document.getElementsByClassName("lang");
for(var i=0,l=elements.length;i<l;i++) {
elements[i].style.display= langs.includes(elements[i]) ? "block" : "none";
}
}

Will this loop correctly and be able to list tag names?

I want to prompt user to enter a tag and it will list it in the console.log and will ask again until they type "quit". if that happens then I will use the documentwrite to list in the innertext what the previous tags been searched for.
var selector = prompt("Please enter a selector: ");
var selectorr = document.getElementsByTagName(selector);
var breaker = "quit";
breaker = false;
var textlogger = "elements have been found that match the selector ";
var lengthfinder = selectorr.length;
while(true) {
console.log(lengthfinder + textlogger + selector);
if (selector == breaker) {
for (var i=0; i<divs.length; i++) {
document.write.innerText(textlogger);
}
}
}
If you wanna try jQuery and something fun, take this:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Loop with jquery deferred</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
var loop = function () {
return $.Deferred(function (deferred) {
var selector = prompt("Please enter a selector: ");
var quit = 'quit';
var selectors = [];
while (selector && selector != quit) {
selectors.push(selector);
var elements = $(selector);
console.log(elements.length + " elements have been found that match the selector " + selector);
selector = prompt("Please enter a selector: ");
}
if (selector)
{
deferred.resolve(selectors);
}
else
{
deferred.reject();
}
}).promise();
};
$(function () {
loop().done(function (selectors) {
$($.map(selectors, function (item, index) {
return '<div>' + item + '</div>';
}).join('')).appendTo($('body'));
});
});
</script>
</head>
<body>
<div>
<iframe src="http://stackoverflow.com/questions/40392515/will-this-loop-correctly-and-be-able-to-list-tag-names"/>
</div>
</body>
</html>
Here is the version with comments and suggestions on where to put your necessary code for it to work.
Code Preview
var breaker = "quit",
textlogger = "elements have been found that match the selector ",
textList = new Array();
while (true) {
var selector = prompt("Please enter a selector: ");
if (selector == breaker) {
/*
Write your necessary output here
*/
/*
After output you break out
*/
break;
} else {
/*
Write It inside list
*/
textList.push(selector);
}
/*
Write necessary output in console
*/
console.log(selector);
}
I want to prompt user to enter a tag and it will list it in the
console.log and will ask again until they type "quit"
while ("quit" !== prompt("Tag name selector, type `quit` to exit", "quit")) {
console.log("in loop");
}
console.log("exit loop");
I will use the documentwrite to list in the innertext what the
previous tags been searched for.
Either you use: document.write("some text") to append to existing dom or you can use selectorr[i].innerText="some text"
Here is my small example that might help you:
var selector;
while ("quit" !== (selector = prompt("Tag name selector. Use `quit` to cancel search", "quit"))) {
var elements = document.getElementsByTagName(selector);
var count = elements.length;
while (count--) {
elements[count].innerHTML += " [matched]";
}
}
<span>This is my <span> tag 1</span>
<p>This is my <p> tag 1</p>
<div>This is my <div> tag 2</div>
<p>This is my <p> tag 3</p>
<span>This is my <span> tag 2</span>

Extract the text out of HTML string using JavaScript

I am trying to get the inner text of HTML string, using a JS function(the string is passed as an argument). Here is the code:
function extractContent(value) {
var content_holder = "";
for (var i = 0; i < value.length; i++) {
if (value.charAt(i) === '>') {
continue;
while (value.charAt(i) != '<') {
content_holder += value.charAt(i);
}
}
}
console.log(content_holder);
}
extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>");
The problem is that nothing gets printed on the console(*content_holder* stays empty). I think the problem is caused by the === operator.
Create an element, store the HTML in it, and get its textContent:
function extractContent(s) {
var span = document.createElement('span');
span.innerHTML = s;
return span.textContent || span.innerText;
};
alert(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>"));
Here's a version that allows you to have spaces between nodes, although you'd probably want that for block-level elements only:
function extractContent(s, space) {
var span= document.createElement('span');
span.innerHTML= s;
if(space) {
var children= span.querySelectorAll('*');
for(var i = 0 ; i < children.length ; i++) {
if(children[i].textContent)
children[i].textContent+= ' ';
else
children[i].innerText+= ' ';
}
}
return [span.textContent || span.innerText].toString().replace(/ +/g,' ');
};
console.log(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>. Nice to <em>see</em><strong><em>you!</em></strong>"));
console.log(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>. Nice to <em>see</em><strong><em>you!</em></strong>",true));
One line (more precisely, one statement) version:
function extractContent(html) {
return new DOMParser()
.parseFromString(html, "text/html")
.documentElement.textContent;
}
textContext is a very good technique for achieving desired results but sometimes we don't want to load DOM. So simple workaround will be following regular expression:
let htmlString = "<p>Hello</p><a href='http://w3c.org'>W3C</a>"
let plainText = htmlString.replace(/<[^>]+>/g, '');
use this regax for remove html tags and store only the inner text in html
it shows the HelloW3c only check it
var content_holder = value.replace(/<(?:.|\n)*?>/gm, '');
Try This:-
<!DOCTYPE html>
<html>
<body>
<script type="text/javascript">
function extractContent(value){
var div = document.createElement('div')
div.innerHTML=value;
var text= div.textContent;
return text;
}
window.onload=function()
{
alert(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>"));
};
</script>
</body>
</html>
For Node.js
This will use the jsdom library, since node.js doesn't have dom features as in browser.
import * as jsdom from "jsdom";
const html = "<h1>Testing<h1>";
const text = new jsdom.JSDOM(html).window.document.textContent;
console.log(text);
Use match() function to bring out HTML tags
const text = `<div>Hello World</div>`;
console.log(text.match(/<[^>]*?>/g));
You could temporarily write it out to a block level element that is positioned off the page .. some thing like this:
HTML:
<div id="tmp" style="position:absolute;top:-400px;left:-400px;">
</div>
JavaScript:
<script type="text/javascript">
function extractContent(value){
var div=document.getElementById('tmp');
div.innerHTML=value;
console.log(div.children[0].innerHTML);//console out p
}
extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>");
</script>
Using jQuery, in jQuery we can add comma seperated tags.
var readableText = [];
$("p, h1, h2, h3, h4, h5, h6").each(function(){
readableText.push( $(this).text().trim() );
})
console.log( readableText.join(' ') );
you need array to hold values
function extractContent(value) {
var content_holder = new Array();
for(var i=0;i<value.length;i++) {
if(value.charAt(i) === '>') {
continue;
while(value.charAt(i) != '<') {
content_holder.push(value.charAt(i));
console.log(content_holder[i]);
}
}
}
}extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>");

HTML-Only Website w/ Theme Options

I am creating a html-only(no server sided code) website that supposed to have multiple themes,
Wherein user can select/change a theme to view the website.
Can you suggest some concepts on how to do this or at least point me into some helpful articles.
Thank you for your help in advance.
The most common approach is to use different external CSS stylesheets, that will get switched based on the selected theme. You also need to structure your DOM wisely, so as to allow different layouts provided by themes.
Probably overkill... but here is a font selector example I came up with using Google Font API and a Document Fragment Builder script I wrote a while ago.
var FragBuilder = (function() {
var applyStyles = function(element, style_object) {
for (var prop in style_object) {
element.style[prop] = style_object[prop];
}
};
var generateFragmentFromJSON = function(json) {
var tree = document.createDocumentFragment();
json.forEach(function(obj) {
if (!('tagName' in obj) && 'textContent' in obj) {
tree.appendChild(document.createTextNode(obj['textContent']));
} else if ('tagName' in obj) {
var el = document.createElement(obj.tagName);
delete obj.tagName;
for (part in obj) {
var val = obj[part];
switch (part) {
case ('textContent'):
el.appendChild(document.createTextNode(val));
break;
case ('style'):
applyStyles(el, val);
break;
case ('childNodes'):
el.appendChild(generateFragmentFromJSON(val));
break;
default:
if (part in el) {
el[part] = val;
}
break;
}
}
tree.appendChild(el);
} else {
throw "Error: Malformed JSON Fragment";
}
});
return tree;
};
var generateFragmentFromString = function(HTMLstring) {
var div = document.createElement("div"),
tree = document.createDocumentFragment();
div.innerHTML = HTMLstring;
while (div.hasChildNodes()) {
tree.appendChild(div.firstChild);
}
return tree;
};
return function(fragment) {
if (typeof fragment === 'string') {
return generateFragmentFromString(fragment);
} else {
return generateFragmentFromJSON(fragment);
}
};
}());
function jsonp(url) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.getElementsByTagName('body')[0].appendChild(script);
}
function replacestyle(url) {
if (!document.getElementById('style_tag')) {
var style_tag = document.createElement('link');
style_tag.rel = 'stylesheet';
style_tag.id = 'style_tag';
style_tag.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(style_tag);
replacestyle(url);
}
document.getElementById('style_tag').href = url;
}
function loadFonts(json) {
var select_frag = [
{
'tagName': 'select',
'id': 'font-selection',
'childNodes': [
{
'tagName': 'option',
'value': 'default',
'textContent': 'Default'}
]}
];
json['items'].forEach(function(item) {
var family_name = item.family,
value = family_name.replace(/ /g, '+');
if (item.variants.length > 0) {
item.variants.forEach(function(variant) {
value += ':' + variant;
});
}
select_frag[0].childNodes.push({
'tagName': 'option',
'value': value,
'textContent': family_name
});
});
document.getElementById('container').appendChild(FragBuilder(select_frag));
document.getElementById('font-selection').onchange = function(e) {
var font = this.options[this.selectedIndex].value,
name = this.options[this.selectedIndex].textContent;
if (font === 'default') {
document.getElementById('sink').style.fontFamily = 'inherit';
} else {
document.getElementById('sink').style.fontFamily = name;
replacestyle('https://fonts.googleapis.com/css?family=' + font);
}
};
}
jsonp("https://www.googleapis.com/webfonts/v1/webfonts?key=AIzaSyDBzzPRqWl2eU_pBMDr_8mo1TbJgDkgst4&sort=trending&callback=loadFonts");​
Here is the Kitchen Sink example...
You could use jQuery style switchers. Check out below link which also have step-by-step tutorials on how to do it:
http://www.net-kit.com/10-practical-jquery-style-switchers/
There is also an article of how to do it here:
http://net.tutsplus.com/tutorials/javascript-ajax/jquery-style-switcher/
Cudos answered already to this question but I'll post this anyway.
You can modify this tutorial (http://net.tutsplus.com/tutorials/javascript-ajax/jquery-style-switcher/) posted by Cudos to consist only of client side code with these modifications to index.php file.
Remove the PHP block and add this function.
<script language="javascript" type="text/javascript">
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
var js_style = readCookie(style);
</script>
And replace the PHP style switcher with this.
<script language="javascript" type="text/javascript">
if (typeof js_style == 'undefined') { js_style = 'day'; }
document.write('<link id="stylesheet" type="text/css" href="css/' + js_style + '.css" rel="stylesheet" />');
</script>
Worked for me...
As Alexander Pavlov writes in his answer, use different external style sheets. To make it possible to users to select a theme persistently (i.e., so that the theme is preserved when moving to another page of the site, or when returning to the site next day), use either HTTP cookies or HTML5-style localStorage. They let you store information locally in the user’s computer, without any server-side code.
There are many tutorials on localStorage (also known as HTML storage or Web storage), and it’s difficult to pick up any particular. They are more flexible than cookies, and they could be used to store large amounts of data, even user-tailored stylesheets. The main problem with localStorage is lack of support on IE 7 and earlier. You might decide that people using them just won’t get the customizability. Alternatively, you can use cookiers, userData (IE), dojox.storage, or other tools to simulate localStorage on antique browsers.

Categories

Resources