How write to page without document.write length limitation - javascript

I'm very much not a javascript/html/css person.
Even so I find myself in the position of having to do a webpage. It's static the only thing you can do on it is click on flags to change dispay-language based on a cookie.
If the cookie says "this" I write text in one language, and if the cookie says "that" I write in another language. This works perfectly but I have to use lots of document.write statements and it's ugly and cumbersome.
Right now I type the text I want and use a macro in emacs to fold the text at about
80 chars and put document.write(" in the beginning of each line and "); at the end. I then paste it into the web page in a if(cookie_this) { } else { }.
There must be a better way to do it... Please?
Edit:
I was looking workaround for the limitations in document.write
Constraints:
No server side magic, that means no ruby/php/perl
One page only, or rather only one visible url
The solution should be simpler than the working one I have

Expanding on artlung's answer:
You can display or hide things given a lang attribute (or any other criteria, such as a class name). In jQuery and HTML:
<p>Language:
<select id="languageSelector">
<option value="en">English</option>
<option value="es">EspaƱol</option>
</select>
</p>
<div lang="en-us">
Hello
</div>
<div lang="es">
Hola
</div>
<script type="text/javascript">
var defaultLanguage = 'en';
var validLanguages = ['en', 'es'];
function setLanguage(lang, setCookie) {
if(!$.inArray(languages, lang))
lang = defaultLang;
if(typeof(setCookie) != 'undefined' && setCookie) {
$.cookie('language', lang);
}
// Hide all things which can be hidden due to language.
$('*[lang]').filter(function() { return $.inArray(languages, $(this).attr('lang')); }).hide();
// Show currently selected language.
$('*[lang^=' + lang + ']).show();
}
$(function() {
var lang = $.cookie('language'); // use jQuery.cookie plugin
setLanguage(lang);
$('#languageSelector').change(function() {
setLanguage($(this).val(), true);
});
});
</script>

jQuery can do this with I lot less ease, but you could create an element then set that elements innerHTML property. You may have to change your call slightly so that you append the child element. See createElement function for more info. For example
<script type="text/javascript">
function writeElement(language, elementId) {
var newElement = document.createElement("span");
if (language = "this") {
newElement.innerHTML = "text for this";
}
else {
newElement.innerHTML = "text for that";
}
var element = document.getElementById(elementId);
element.appendChild(newElement);
}
</script>
Usage
<span id="data1"></span>
<script type="text/javascript">
writeElement("this", "data1")
</script>
Add a comment if you can support jQuery and you want a sample of that instead.

I think that the right way to approach this is to parse the Accept-Language header, and do this server-side.
But in the instance that you are stuck with client-side scripting. Say your content was marked like this
<script type="text/javascript">
if(cookie_this) {
document.getElementById('esContent').style.display = 'block';
} else {
document.getElementById('enContent').style.display = 'block';
}
</script>
<div id="esContent" style="display:none">
Hola, mundo.
</div>
<div id="enContent" style="display:none">
Hello, world.
</div>
This does not degrade for people with CSS enabled, and JavaScript disabled. Other approaches might include using Ajax to load content based on a cookie value (you could use jQuery for this).

If you just want one visible URL, but can host multiple pages on the server you could also try XHR. I use jQuery because I am most familiar with it although it would be possible to implement in javascript alone:
<html>
<head>
<script type="text/javascript" src="path/to/jquery.js"> </script>
<script type="text/javascript">
$(document).ready(function () {
if (cookie_this) {
$("body").load("onelanguage.html body");
} else {
$("body").load("otherlanguage.html body");
}
});
</script>
</head>
<body>
</body>
</html>

The detection should be on the server (preferably based on the Accept-Language header the client sent), and you should send a static file that has already been localized.

This does not fit the (edited) criteria of the original question, but may be useful regardless.
Use a server-side script. What you're looking for can easily be done in PHP. You'd probably want a hierarchy of documents based on language, and would look up given that. For example, a directory tree:
/en/
/en/page1.html
/en/page2.html
/es/
/es/page1.html
/es/page2.html
In PHP it's as simple as
$language = $_GET['lang'];
$page = $_GET['page'];
include($language . '/' . $page);
// URL is: /whatever.php?lang=LANGUAGE_HERE&page=PAGE_HERE
However, that has many security issues along with it. Sanitize your input and make sure the directory and file exist. Fuller example:
$contentRoot = './'; // CHANGE ME. Do include trailing /.
$defaultLanguage = 'en'; // CHANGE ME.
$defaultPage = 'home'; // CHANGE ME.
if(isset($_GET['lang']))
$language = $_GET['lang'];
else
$language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 2);
if(isset($_GET['page']))
$page = $_GET['page'];
else
$page = $defaultPage;
$languageDir = basename($_GET['lang']) . '/';
$pageFile = basename($page) . '.html';
if(!file_exists($contentRoot . $languageDir) || !is_dir($contentRoot . $languageDir))
$languageDir = $defaultLanguage;
$fullFileName = $contentRoot . $languageDir . $pageFile;
if(!file_exists($fullFileName) || !is_file($fullFileName) || !is_readable($fullFileName))
$pageFile = $defaultPage;
readfile($fullFileName);
// Or, if you want to parse PHP in the file:
include($fullFileName);
You may also want to use mod_rewrite (Apache) to allow URL's such as http://www.mysite.com/en/page1. (Just be sure to hide the actual page.)
// TODO mode_rewrite rules
Another approach is putting the above hierarchy into the document root and handing out URL's directly. This gives you less power (e.g. templating is more difficult), however, and you have to worry about external media being referenced properly.
If you're looking for a dynamic approach, on the client side use Javascript to fetch the data using Ajax. This is also trivial, and does not require a dynamic server backend. I recommend a Javascript framework such as jQuery to make this as easy as possible.

There is no good way to do this in JS. The best way is to use VERY simple PHP code.
But, if you want, there is a way in JS - prepare pages like these:
some pages with different language versions, like index_en.html, index_ru.html
main index.html page, where you have code like
if(cookie) windows.location.replace('index_en.html') else ...

Related

How do I define a variable in my index.html file? (window.parentPage = true;)

https://stackoverflow.com/a/43635720
On this answer, it says to define a variable (window.parentPage = true;) in the index.html page. How can I go about doing this?
You would need to define the variable using JavaScript. You can embed some JavaScript in the HTML file by encasing it in a script tag like so:
<script type="text/javascript">
window.parentPage = true;
</script>
First you need to clearly realize your reason... what you want to achieve.
After that defining that to yourself:
First option:
You can store/save some data as stated on the link you added to your question inside a tag, like that:
<script>
var myLittleBox = "box content";
</script>
And access it later like:
<script>
myLittleBox = myLittleBox + " extra content";
console.log(myLittleBox);
//this will print "box content extra content"
</script>
You need to use the tag to access the javascript environment.
Second option:
You can save/store data with pure HTML using an with type "hidden" to not show it on screen as an input box, and changing it's value, like that:
<input type="hidden" value="box content">
But this way you'll not be able to access the data directly without aid of javascript code, unless you send this input somewhere reachable as GET or POST within a and recover it getting the respective GET or POST.
Javascript variables:
https://www.w3schools.com/js/js_variables.asp
Ex: https://www.w3schools.com/js/tryit.asp?filename=tryjs_variables
HTML input:
https://www.w3schools.com/tags/tag_input.asp
HTML form handling:
https://www.w3schools.com/php/php_forms.asp
You're probably trying to understand the first option, but you question do not make that clear. Anyway, good studies.
Whatever you do you will have to use JavaScript in order to access the variable. An orthodox way of doing it that is not mentioned yet is using an data-attribute inside the html and than you access it by JavaScript:
const attributeName = 'data-parentPage';
const setup = () => {
let parentPageBool = document.querySelector(`html[${attributeName}]`).getAttribute(attributeName);
console.log(parentPageBool)
};
window.addEventListener('load', setup);
<html data-parentPage="true">
</html>

How do adjust html output based on operating system?

Problem definition
I need to put text similar to the following on a web page:
If the user is operating on a Windows based system, I want them to see:
Look for the file C:\Users\yourname\dir1\dir2\filename on your Windows PC
If the user is operating on an OS X based system, I want them to see:
Look for the file /Users/yourname/dir1/dir2/filename on your Macintosh PC
If the user is operating on[any other|Linux] based system, I want them to see:
Look for the file /home/yourname/dir1/dir2/filename on your Linux PC
Research
I have managed to create three almost identical javascripts that partially work. One script gives me the value of the osHomeDir, another osType, and the other gives me the value of the osSeparator. My problem is that I don't know how to get these values out of the java script and into my webpage consistently. What I get is that the first substitution works, but I can't repeat it - for instance, on my Mac I see:
Look for the file /Users/yournamedir1dir2filename on your Macintosh PC rather than the desired:
Look for the file /Users/yourname/dir1/dir2/filename on your Macintosh PC
Note how only the FIRST substitution of osSeparator worked.
Desired outcome
I'm hoping someone can show me two things:
How to make the scripts more efficient - three almost identical
scripts could surely be changed into one that returned three values
The ability to be able to use the result more than once (as happened
in my example)
Notes
Don't get too concerned about THIS example - I have simplified it to make it readable. I have the same problem in many places. I know I COULD solve this one my returning the whole sentence in the one script, but that would miss the point entirely.
My code
<!DOCTYPE html>
<html>
<body>
<p> Look for the file <a id="osHomeDirId"></a><a id="osSeparatorId"></a>yourname<a id="osSeparatorId"></a>dir1<a id="osSeparatorId"></a>dir2<a id="osSeparatorId"></a>filename on your <a id="osTypeId"></a> PC</p>
<script>
var osHomeDir = "/home";
if (window.navigator.platform.indexOf("Win") != -1) osHomeDir="C:&#92Users";
if (window.navigator.platform.indexOf("Mac")!=-1) osHomeDir="/Users";
document.getElementById("osHomeDirId").innerHTML=osHomeDir;
</script>
<script>
var osType = "Linux";
if (window.navigator.platform.indexOf("Win") != -1) osType="Windows";
if (window.navigator.platform.indexOf("Mac")!=-1) osType="Macintosh";
document.getElementById("osTypeId").innerHTML=osType;
</script>
<script>
var osSeparator = "/";
if (window.navigator.platform.indexOf("Win") != -1) osSeparator="&#92";
document.getElementById("osSeparatorId").innerHTML=osSeparator;
</script>
</body>
</html>
You use document.getElementById() which only gets the first element with the specified id. Also you shouldn't use id's multiple times. You should make it a class instead. You need to use document.getElementsByClassName() which returns an array, then loop through all the elements of that array and set the innerHTML properties to osSeparator.
var separators=document.getElementsByClassName("osSeparatorId");
for(var i=0;i<separators.length;i++){
separators[i].innerHTML=osSeparator;
}
Then you need to change the html to <a class="osSeparatorId">
Working Answer:
I changed approach to use functions instead of getElementsByClassName
I can now get the "desired" outcome, but I'm sure there could be some more efficiencies added to the script to save the if...if else...if else construction at the end.
Here's the code that works:
<script>
function localised() {
var printItem=arguments[0];
var osHomeDir="/home";
var osSeparator="/";
var osType="Linux";
if (window.navigator.platform.indexOf("Win") != -1) {
osHomeDir="C:&#92Users";
osType="Windows";
osSeparator="&#92"
}
if (window.navigator.platform.indexOf("Mac")!=-1) {
osHomeDir="/Users";
osType="Macintosh";
}
if (printItem=="osHomeDir") document.write(osHomeDir);
else if (printItem=="osType") document.write(osType);
else if (printItem=="osSeparator") document.write(osSeparator);
}
</script>
<p>Look for the file <script>localised("osHomeDir");</script><script>localised("osSeparator");</script>yourname<script>localised("osSeparator");</script>dir1<script>localised("osSeparator");</script>dir2<script>localised("osSeparator");</script>filename on your <script>localised("osType");</script> PC</p>
</body>
</html>
Not an answer...yet
Clearly someone has got #Max Meijer's answer working (because it has been marked up) but when I try it, it still doesn't work. #Max (or anyone else) I invite you to edit this answer until it does work.
Remember: Desired output (eg on OS X)=>
Look for the file /Users/yourname/dir1/dir2/filename on your Macintosh PC
Output using Max's code above=>
Look for the file /Usersyournamedir1dir2filename on your Macintosh PC
Note that in this case not even a single instance of osSeparatorId is displayed.
And I still have 3 separate scripts to do pretty much the same job.
Proof that I've implemented Max's code exactly as described:
<!DOCTYPE html>
<html>
<body>
<!--Note that the following line is now using <a class="osSeparatorId"> instead of <a id="osSeparatorId"> -->
<p> Look for the file <a id="osHomeDirId"></a><a class="osSeparatorId"></a>yourname<a class="osSeparatorId"></a>dir1<a class="osSeparatorId"></a>dir2<a class="osSeparatorId"></a>filename on your <a id="osTypeId"></a> PC</p>
<script>
var osHomeDir = "/home";
if (window.navigator.platform.indexOf("Win") != -1) osHomeDir="C:&#92Users";
if (window.navigator.platform.indexOf("Mac")!=-1) osHomeDir="/Users";
document.getElementById("osHomeDirId").innerHTML=osHomeDir;
</script>
<script>
var osType = "Linux";
if (window.navigator.platform.indexOf("Win") != -1) osType="Windows";
if (window.navigator.platform.indexOf("Mac")!=-1) osType="Macintosh";
document.getElementById("osTypeId").innerHTML=osType;
</script>
<!--Note that the following is cut and pasted from Max's answer-->
<script>
var separators=document.getElementsByClassName("osSeparatorId");
for(var i=0;i<separators.length;i++){
separators[i].innerHTML=osSeparator;
}
</script>
</body>
</html>

JavaScript - Replacing "no-js" class with "js" class not working?

I placed a class in my <html> element called "no-js". This indicates that the user isn't using javascript, (whether it be disabled or blocked). And then, in a script file I created, I want to revoke "no-js" and inject "js" so that I can determine if the user is using javascript or not via classes. I tried using the replace() method by querying the html tag, but it isn't working. Here's what I have:
var html = document.getElementsByTagName("html")[0];
if(html.className == "no-js") {
html.className.replace("no-js", "js"); // user has JS enabled
}
There are no errors in Google Chrome or Firefox's bug console, but neither is it changing no-js to js. I would use the <noscript> tag but I like to keep the markup side of it clean.
replace returns the new string, it doesn't modify the original.
Try html.className = 'js', since you've already established that it's the only class name with your if statement.
EDIT: Also, the <html> tag is already available as document.documentElement.
document.documentElement.className = 'js';
That's all you need, really. No if statement, no variable, nothing.
The accepted answer is indeed correct, but this way will replace all classes of the <html>, not only .no-js.
This little script will do the same thing, but will instead search only for the no-js class and rewrite it.
document.documentElement.className = document.documentElement.className.replace(/\bno-js\b/g, '') + ' js ';
Took script from here, very simple!
http://snipplr.com/view/63895/remove-nojs-class-from-html-tag-add-js-class/
You forgot to assign the html.className to the new value:
var html = document.getElementsByTagName("html")[0];
if(html.className == "no-js") {
html.className = html.className.replace("no-js", "js"); // user has JS enabled
}
With a little regex
(function(html) {
html.className = html.className.replace(/\bno-js\b/, 'js')
})(document.documentElement);
<!DOCTYPE html>
<html class="no-js">
<head>
</body>
</html>

Parse django template tag with custom filter for a live preview container via javascript

I need to create a live preview container (like stackoverflow and Reddit) for my django website using textile as my markup language.
Is there a way to do it on the client side? (without using ajax?)
Parsing the code from the view is as simple as:
{% load markup %}
{{ theme.content|textile }}
(Needless to say, I followed the documentation and included 'django.contrib.markup' to my INSTALLED_APPS setting.)
For simplicity's sake, lets assume I don't need IE support. My JS looks as follows:
function change_preview() {
var fragment = document.createDocumentFragment();
// I am no sure what should I put here:
fragment.appendChild(document.createTextNode('{{ theme.content|textile }}'))
document.getElementById("preview").appendChild(fragment);
}
window.onload = function() {
var content_box = document.getElementById('id_content');
content_box.addEventListener("input", change_preview , false );
}
And HTML:
<textarea id="id_content" rows="10" cols="40" name="content"></textarea>
<div id = "preview"></div>
Also I found this JS library. Is it a good idea to use it on the client-side together with PyTextile on the server-side?
What are the best practices?
I am looking for non-jQuery solutions, but I will accept one if there are no other ways to do it.
Thank you in advance.
Since textile specifies what markup corresponds to what html I don't see a big potential for incompatibilities between a JS lib and a Py lib.
In your script for an immediate preview update you might want to use the keyup event instead of the input event since the latter is only fired when the textarea looses focus.
window.onload = function() {
var content_box = document.getElementById('id_content');
content_box.addEventListener("keyup", change_preview , false );
}
To use Ben Daglish's lib, which is not based on jQuery, your event handler would look like this:
function change_preview() {
var content_box = document.getElementById('id_content');
var html = convert(content_box.value);
document.getElementById('preview').innerHTML=html;
}

Widget for webmasters in JavaScript and ID-collision

I would like to create a widget that could be placed in another websites/forums.
<script type="text/javascript" src="http://example.com/x.js" />
<div id="myid"></div>
But there is a problem - when someone put on one website two or more such widgets they will not work correctly because of the ID.
What can I do to prevent such situation?
I can't use class because I need to have access to this div from JS.
I thought about adding a random-generated number to the end of ID, but there will be still possibility of ID-collision (small, but there will be).
The best way is to be more flexible. So, instead of having a defined html id and force the user to have it, you should provide a way to let user choose its id. And so, a call must be done.
Something like this is cleaner :
<script type="text/javascript" src="http://example.com/x.js"></script>
<script type="text/javascript">
X.callMethod("myId");
</script>
<div id="myid"></div>
This method has two advantages :
it lets user define its own id
the user specifies what behavior he wants from your script. With, that, you could add other methods which can be used in same way : user doesn't have the feeling that your code is intrusive, it's him who decides if he wants a feature or not.
You could just include the script... which at processing time generates a div and assigns it a unique ID. (Within that logic, you could check for duplicates)
Presuming you don't expect your widget to be included 1,000's of times... something like this (untested) should work.
var uniqueID;
var foundUniqueID = false;
var idx = 0;
while(foundUniqueID != true){
uniqueID = 'myID_' + idx;
if(document.getElementById(uniqueID)){
idx++;
} else {
foundUniqueID = true;
}
}
//create your DIV with your uniqueID etc.

Categories