开发者

JavaScript HERE-doc or other large-quoting mechanism?

Is开发者_Python百科 there a convenient way to quote a large block of HTML that has both single and double quotes in JavaScript?

Is there anything like a HERE-doc <<EOF, a multi-quote character """, or custom delimiters q{}?

Any creative or inventive solutions to this problem?


Some people don't like this, so be prepared for scorn and derision, but one trick is to dump your "big block of stuff" into a <script language="text"> block:

<script id='blockOfStuff' language="text">
  Hi this is random stuff
  <h1>Including HTML markup</h1>
  And quotes too, or as one man said, "These are quotes, but
  'these' are quotes too."
</script>

John Resig has used that technique (or that abomination, if you prefer) for examples of his templating mechanism.

You can get at the contents with "innerText" or "innerHTML" as appropriate, or through the services of your favorite framework.

edit — note that via jQuery (contrary to what I said in a comment below) .text() does not work, though I think it should. Use .html() instead.


Not supported natively.

But since we're talking ways to make it work, here's one that (in my experience) does:

<script type="text/javascript">  

    var name = "Mud";

    var str = "\
        My name is " + name + "\
        not to be confused with Bill\
        or Jack or Pete or Dennis\
        my name is " + name + " and it's always been\
    ";

    alert("Les'n one: " + str);

</script>

Those back-slashes'll do the trick. Just make sure to backslash-escape any double quotes in your string since the whole block is quoted with them.

Note that this doesn't retain newlines, you have to insert them manually as "\n" prior to trailing slash on each line. On the other hand, any whitespace indentation at the beginning of each line will be included in the output.

Really this works best when you have to declare a long multiline string in a script (e.g. XML), not as good when you need to keep that string formatted exactly the way you define it.

Cheers


JavaScript can't do it but CoffeeScript, which is a thin layer on top of JavaScript, can.

Follow the link and scroll down to "Multiline Strings and Heredocs".


I remember seeing a clever solution a while ago that used multi-line comments in a function:

(function () {
   /*
      "This is an example of a multi-line string.  It's really just a mult-line
      comment, and it's wrapped in quote marks.  You might also notice the 
      apostrophe's ;-)"; 
   */
});

Note: that last apostrophe is intentionally incorrect ;-P

The trick is to call the function's toString() method and parse out the multi-line comment using a regular expression. Clever, but much like Pointy's suggestion, a bit of an abomination.

I didn't actually think the question to be looking for a seriously viable method for production uses -- my own fault for jumping to conclusions -- I'm not really sure why you wouldn't just escape the relevant string literal delimiters. As Tim Down pointed out in the comments below, ECMAScript 3rd edition defines toString() for functions as being implementation dependant.

For funsies, I decided to check out browser compatibility and this method is feasible in IE, Opera, Safari and Chrome but not Firefox, which does not include comments in the returned string. http://jsfiddle.net/2yvXG/


ECMAscript 6, now the standard, allows use of back-ticks (accent grave) to quote multi-line literal strings. Unfortunately, this is not supported in IE 11, so it should not be used on most websites. (Credit: Adam Katz, above)

Example:

var str=
`Line 1
Line 2`;


HereDoc For JavaScript

FuncToHereDoc ("delemiter", uncalled function with commented HEREDOC)

function FuncToHereDoc(here,str) {
    var reobj = new RegExp("/\\*"+here+"\\n[\\s\\S]*?\\n"+here+"\\*/", "m");
    str = reobj.exec(str).toString();
    str = str.replace(new RegExp("/\\*"+here+"\\n",'m'),'').toString();
    return str.replace(new RegExp("\\n"+here+"\\*/",'m'),'').toString();
}

Usage:

FuncToHereDoc("HERE", MyHereDoc);

function MyHereDoc(){
/*HERE
<p>
This is written ing the HEREDOC, notice the multilines :D.
</p>
<p>
HERE
</p>
<p>
And Here
</p>
HERE*/
}


I actually worked out a kludgy variant similar to user742675, where you put the text in a div, then set its visibility to none, and pull the contents. But just quoting a lot of HTML wasn't enough, so I added a functionality that picked up all the variables you'd declared in your script, so if you had var a = 'Steve', any instance of $a in your heredoc text would be rendered as 'Steve'.

<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>


Based on previous answers and different use cases, here is a small example:

https://gist.github.com/lavoiesl/5880516

/*!
 * Extract a function's comment, useful to have multiline string
 * @link https://gist.github.com/lavoiesl/5880516
 *
 * Don't forget to use /*! to avoid the comment being removed in minification 
 */

function extractFuncCommentString(func) {
  var matches = func.toString().match(/function\s*\(\)\s*\{\s*\/\*\!?\s*([\s\S]+?)\s*\*\/\s*\}/);
  if (!matches) return false;

  return matches[1];
}

var myString = extractFuncCommentString(function(){/*!
  <p>
    foo bar
  </p>
*/});


I was interested in this question because I want to use javascript to add a new row to an edit screen (e.g., for multiple phone numbers). (i could use ajax for this but wanted to avoid an extra server request.)

I like Pointy's answer about using the tag to enclose blocks of html you want to use:

<script id='blockOfStuff'>
  Hi this is random stuff
  <h1>Including HTML markup</h1>
</script>

But Firefox and Chrome complained about syntax errors when I tried this. My solution was to change that 'script' tag to a 'div', hide its display from users via css, and move it within the body. e.g.:

<div style="display: none;" id="new_row_innerhtml">
  <td><a href="#" onclick="removeCurrentRow(this); return false;">Remove</a></td>
  <input type="hidden" name="id[]" value="new" />
  <td><input name="name[]" type="text" /></td>
</div>

That removed the syntax errors.

Here's how I used that block:

I had an "Add" link that called the appendRow function:
<a href="#" onclick="appendRow(this); return false;">Add</a>

here's the appendRow function:

function appendRow() {
  var tbl = document.getElementById('my_table');
  var row = tbl.insertRow(-1); // add to end of table
}


// js heredoc - http://stackoverflow.com/a/32915549/466363
// a function with comment with eval-able string, use it just like regular string

function extractFuncCommentString(func,comments) {
  var matches = func.toString().match(/function\s*\(\)\s*\{\s*\/\*\!?\s*([\s\S]+?)\s*\*\/\s*\}/);
  if (!matches) return undefined;
  var str=matches[1];

   // i have made few flavors of comment removal add yours if you need something special, copy replacement lines from examples below, mix them
  if(comments===1 )
  {
   // keep comments, in order to keep comments  you need to convert /**/ to / * * / to be able to put them inside /**/ like /*    / * * /    */
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   )
  }
  else if(comments===2)
  {
   // keep comments and replace singleline comment to multiline comment
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
   )
  }
  else if(comments===3)
  {
   // remove comments
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
     )
  }
  else if(comments===4)
  {
   // remove comments and trim and replace new lines with escape codes
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
      .trim() // after removing comments trim and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else if(comments===5)
  {
   // keep comments comments and replace strings, might not suit when there are spaces or comments before and after quotes 
   // no comments allowed before quotes of the string
   // url html links
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */
      .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
      .trim() // trim space around quotes to not escape it and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else if(comments===6)
  { // good for html with links
   // remove comments and trim and replace new lines with escape codes
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .trim() // after removing comments trim and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else 
  return str
}

example

var week=true,b=123;
var q = eval(extractFuncCommentString(function(){/*!

// this is a comment     


'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc
'
*/},4));

with cache: - make a simple template function, and save the function:

var cache={};
function myfunction(week,a){


    if(!cache.myfunction_sql1) eval('cache.myfunction_sql1=function(week,a){return ('+extractFuncCommentString(function(){/*!
'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc

'*/},4)+')}');
    q=cache.myfunction_sql1(week,a);
    console.log(q)
}
myfunction(true,1234)

simple text (not eval'd):

//var cache={};
function myfunction2(week,a){


    if(!cahce.myfunction_sql2) cahce.myfunction_sql2=extractFuncCommentString(function(){/*!

some multiline text
with <html>
and a link://to.url
and a / * comment * / 
*/},6);
    q=cahce.myfunction_sql2;
    console.log(q)
}


Here is your answer. In the body of your page make a span or div, it does not matter which, with a unique id and put all the text you want in it with all the quotes you want. Make the style of the span or div "display:none; visibility:hidden;". Then when you want it get the DOM object from the id and retrieve the innerHTML to do with what you will.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜