While working on a recent project, I found myself with a need to insert blocks of text via javascript and wishing I could do the heredoc style parsed multiline string. If you're not familiar with it, you might have a bit of code...
<?php
$fred = $_REQUEST["fredinput"];
$ted = <<<EOM
This is a multiline<br>
string, that outputs<br>
the value of "fredinput" as<br>
$fred.
EOM;
echo $ted;
?>
Now, let's say that in whatever form you'd posted to this script, the value of the "fredinput" variable was "Loquacious", the output of that bit of code would be:
This is a multiline
string, that outputs
the value of "fredinput" as
Loquacious.
Now, let's say you had large blocks of HTML you'd want to specify in this way for a javascript application. It gets a little painful because it all has to be a single line, or at the end of each line, you have to escape the line break, you have to make sure you escape your single or double quotes, and to put in any variables, you have to close your quotes, insert the variable surrounded by pluses, and then reopen the quotes. It makes that HTML hard to read and easy to screw up if you need to edit it.
Wouldn't it be nice to just type the big old block of text as straight HTML with lots of whitespace for readability, not have to escape anything, and just prefix variable names with dollar signs to have the variable's value appear?
You can, and all you need is this very short function. It's a bit of a klunky hack because the text is in a hidden div in the HTML document instead of within the script. But otherwise it works nicely.
Here's a sample using the function.
<script type="text/javascript">
// set variables named andy and handy, which we can use as $andy and $handy in our text
var andy = "Fred Flintstone";
var handy = "Steve Austin";
function hereDoc(divid){
var obj = window; // gets an object containing all the variables
var str = document.getElementById(divid).innerHTML; // gets the HTML block
for(var i in obj){
/* the for loop recurses through all the objects in the page - remember strings are objects in Javascript */
if((typeof(obj[i])=="string")||(typeof(obj[i])=="number")){
/* Type of makes sure it only executes replacement for strings and numbers. The function worked without this test in Firefox and Safari, but threw errors on Opera until it was added. */
myregex = new RegExp('\\$'+i,"g");
/* To replace globally, you need to use a regular expression and use the "g" option, but within the string.replace() method, the regular expression is unquoted, so you can't use a variable in it directly. So we create it and assign it to a RegExp object that works in the string.replace() method. */
str = str.replace(myregex, obj[i]);
/* we replace instances of the variable name with a dollar sign before it with the variable's value */
}
}
return str;
/* and when the loop is done, we return the processed text to be used however needed */
}
function gotoit(){
/* fill the "steve" div with the processed contents of the "randy" div. */
document.getElementById("steve").innerHTML = hereDoc("randy");
}
</script>
<a href="javascript:gotoit();">Run the script</a>
<div id="randy" style="display:none;">
The interesting thing about $andy is that he's not nearly as popular with young kids as $handy.<br><br>
What I really find 'interesting' is that this "multiline" thing works as well as $handy's bionic arm. <br><br>
</div>
<div id="steve"></div>
Note the unescaped single and double quotes on the last line. You can do much more complex HTML like a form, but I'm just trying to keep this simple for the example.
In the end, this is more a proof of concept than anything else. You can do this a bunch of ways, but I like the way it iterates through the javascript variables in the document and processes the text the same way you'd see that handled in a PHP script. Of course, I haven't added in the handling of array variables, but it could be done.
There's also the reverse option of using regular expressions to search for single words meeting string naming rules, prefixed with $, then checking to see if there's a variable with that name that's a string or number value and doing a global replace for it. If you had a whole lot of variables in a highly complex script, it might be faster.
Anyway, I'm rambling. I've tested it on Firefox, Safari, and Opera on my MacBook Pro running Tiger. Try it out on your browser if you like...
Run the script
The interesting thing about $andy is that he's not nearly as popular with young kids as $handy.
What I really find 'interesting' is that this "multiline" thing works as well as $handy's bionic arm.