java script failing because of white spaces caracters - javascript

I have in my views some code as this
$(".someclass").hover(function(){
$(this).append("#{render "layouts/show_some_file", title: "some_file"}");
});
The show_some_file.html.haml file consists of two nested basic divs
In my browser, I get
$(".someclass").hover(function(){
$(this).append("<div>
<div>some text</div>
</div>
");
});
On hover, I get in my chrome console SyntaxError: Unexpected token ILLEGAL. I deleted my white spaces in my console, and it worked. But how to clean the white spaces in my ruby rendering ?

I am not entirely certain it will help, but you probably should use the "<%= render ... %>" variant rather than the #{}
And since it's for javascript, the correct way would be "<%= escape_javascript(render ...) %>"
If using HAML, substitute the ERB for however the markup is written there.
Edit: might be
!= "$(this).append("#{escape_javascript(render "layouts/show_some_file", title: "some_file")}");"

Since the result of your {#render} is HTML, and although you might use it once, it might make more sense to store it in HTML, and retrieve it with JavaScript. Mimicking templating, here's an example of what I mean:
<script id="my_render" type="text/template">
#{render "layouts/show_some_file", title: "some_file"}
</script>
<script type="text/javascript">
$(document).ready(function () {
var render_content = $("#my_render").html();
$(".someclass").hover(function () {
$(this).append(render_content);
});
});
</script>
It kind of acts like a template. You use a script tag, but you set its type to something that doesn't cause it to be executed. Since script tags are never visible on a page, you would never have visual problems...unlike doing this inside of a div...the HTML is then "separate" from the rest of the page.
I'm sure there's a better solution using Ruby, but if you're outputting a partial view to JavaScript code, I'd have to ask why. It makes more sense to me to put in a "template". I understand this doesn't directly answer your immediate question, but it's an alternative :)

In fact, I got it, one of the right thing to do is :
$("someclass").hover(function(){
$(this).append("#{escape_javascript render "layouts/show_some_file", title: "some title"}");
});

The obvious thing to do is edit layouts/show_some_file & remove white space. It's not really whitespace that's the problem, but carriage returns. Javascript doesn't like multi-line strings. If I knew Ruby, I could probably write a regex that gets rid off stuff like "\r\n", which is carriage return line feed in PHP/C syntax.

Related

Fill a Javascript-Array within a Fluid foreach

i try to create a js-array with a fluid-foreach but i just get the "{obj.background.title}" output. when i put it in a console.log it works.
<script>
<f:for each="{settings.backgrounds}" as="obj" iteration="itemIteration">
{f:if(condition: itemIteration.isFirst, then: 'var backgrounds = [')}
{
src: "fileadmin/user_upload/configurator_1/background1.jpg",
isdark: true,
title: "{obj.background.title}",
},
{f:if(condition: itemIteration.isLast, then: ']')}
</f:for>
</script>
Use f:format.raw around the opening or closing curly braces. This prevents the Fluid parser from seeing it as an inline accessor.
The JavaScript-{ probably confuses the Fluid parser (off topic: what a catastrophic idea to use a JavaScript syntax token in an HTML templating engine and even forget about a clean way to escape it!).
That said it is sadly very common for JavaScript-in-Fluid to be parsed half-way or not at all or anything in between (as you just experienced). I used to use f:format.cdata() but even that has caveats. It often depends on the position of your <script> in the template so moving it more to the end of your template might help if you want to go the trial-and-error path...
I recommend passing over dynamic data to JavaScript by assigning the whole JavaScript to a template variable in your controller and outputting it via {script -> f:format.raw()}. This means ugly frontend-related stuff in your controller but it is the quickest and a very reliable way.
Or you can use a vhs-ViewHelper to convert your data to JSON and assign a HTML-data-property and process it via an external JavaScript logic. This also works reliably and is quite clean in my eyes.
In Fluid:
<x-mytag data-backgrounds="{v:format.json.encode(value: setting.backgrounds)}" />
Ideally in an external JavaScript (actually, this would even work inside Fluid):
var backgrounds = JSON.parse(
document.querySelector('[data-backgrounds]').dataset.backgrounds
)
Everybody made this experience once... I am very open to learn about other approaches.

Convert Html to document.write javascript

I've see a web page that when I try to view the source, I only see a single JavaScript statement. I searched and could not figure out how they have done that. you can do and see yourself.
The web page is: Weird Page
when I view the source I only see something like below which also looks like a comment:
<script type='text/javascript' language='Javascript'>
<!--document.write(unescape('%3C%2........................
................
How they have done that? How I can change my web page so when someone view the source it look like that?
This article may help to clarify what's happening there.
Basically, this company has encoded their entire page using standard escape characters. If you copy the bit from unencode(...) all the way to the next to last parens, and paste it into your browser console, you'll see the actual HTML content.
If you look at the source code for the page I linked, you'll see the function that converts normal text to all escape characters:
// CONVERTS *ALL* CHARACTERS INTO ESCAPED VERSIONS.
function escapeTxt(os){
var ns='';
var t;
var chr='';
var cc='';
var tn='';
for(i=0;i<256;i++){
tn=i.toString(16);
if(tn.length<2)tn="0"+tn;
cc+=tn;
chr+=unescape('%'+tn);
}
cc=cc.toUpperCase();
os.replace(String.fromCharCode(13)+'',"%13");
for(q=0;q<os.length;q++){
t=os.substr(q,1);
for(i=0;i<chr.length;i++){
if(t==chr.substr(i,1)){
t=t.replace(chr.substr(i,1),"%"+cc.substr(i*2,2));
i=chr.length;
}
}
ns+=t;
}
return ns;
}
What is happening is pretty much what it sounds like. The server is serving a single <script> element, which contains an HTML comment to make it easier for browser that don't support JS (read more here: Why does Javascript ignore single line HTML Comments?), and in the comment it's writing to the document the unescaped version of the string, which is sent escaped.

Using MVC resource in Jquery - function stops working

I have a Jquery function in MVC View that check if at least one checkbox is clicked. Function is working properly if I use hardcoded string. But when I add
#Resources.myString into, it stops working, I can't figure out why
$('.form-horizontal').on('submit', function (e) {
if ($("input[type=checkbox]:checked").length === 0) {
e.preventDefault();
alert("This is working");
alert(#Resources.myString); //with this the function is not working anymore
return false;
}
});
I need to add the the string for multilingual purpose.
I tried diferent aproches
alert(#Resources.myString);
alert(#Html.Raw(Resources.myString))
var aaa = { #Html.Raw(Resources.myString)} //and calling the aaa
I think I am missing some basic knowlage of how this should work together
During page rendering, #Resources.myString will be injected as is in the code. For instance, if myString == "abc";, you'll end up with alert(abc); which is not what you want.
Just try to enclose your string in quotes:
alert("#Resources.myString");
As an aside, putting Razor code in Javascript logic is usually considered bad practice, as it prevents you from putting Javascript code in separate files (and therefore caching), and makes the code less readable.
Take a look as this question and the provided answer which gives a simple way to deal with that.
As ASP.NET dynamically generates HTML, CSS, JS code, the best way to find the error is to read the generated sources (Ctrl + U in most modern browsers).
You will see that your code
alert(#Resources.myString);
produces
alert(yourStringContent);
and should result in a console error yourStringContent is not defined.
You need to use quotes as you are working with a JavaScript string:
alert('#Resources.myString');
It will produce a correct JavaScript code like:
alert('yourStringContent');

dust.js include partitial without trimming

I am using dust.js template engine. The main template includes a partial and the problem is that dust.js trims every line of the included template file.
For example, the main template is:
<h1>{header}</h1>
{>dust_cnt /}
The dust_cnt.dust is:
<div>
This is
the content
</div>
And I render the response by:
res.render('dust_template.dust', {header: 'TEST OK'});
The problem that there is no space between This is and the content in the output. So the output looks like:
TEST OK
This isthe content
I can't change all the contents by putting {~n} or another separator and I don't think there is any reason to do that.
On http://linkedin.github.com/dustjs/ I found the following remark GH- 166 - Added trimming of white spaces in dust templates configuration in the dust.compile ( default option is still true). But can't find the way to set set the options to avoid the trimming?
How can I make dust.js to render it the way I expect (with the spaces)?
Thank you in advance!
Ok, I found the solution :). After digging in the source code + checking the issues on the dust's GitHub I decided to use the following to prevent the formatting of the template's nodes:
dust.optimizers.format = function(ctx, node) { return node };
(Also on https://github.com/linkedin/dustjs/wiki/Dust-Tutorial#controlling-whitespace-suppression)
The default behavior is very dangerous - as it mentioned on the GitHub it can cause serious problems, for example:
<script>
//this will alert "test"
alert("this is test");
</script>
Will be rendered as:
<script>//this will alert "test" alert("this is test");</script>
This is strange and I understand that you don't want to edit your template files. However, you can workaround this in a less ugly way by adding a space at the end of the line:
<div>
This is < add space here
the content
</div>
Just for the case you cannot find a real solution for this.

Embedding C# code using <%= code %> within javascript <script> tags

I'm using ASP.NET MVC and would like to get Model information for use within my javascript. I've strongly typed the view, and thus am able to use <%= Model.Name %> within my HTML to get Model data.
But once I'm in the <script> tags, I get no intellisense (in Visual Studio) when using <%, and the information doesn't seem to be rendering properly. Is there something I'm missing to be able to use the angle bracket scheme within Javascript?
Thanks.
CLARIFICATION: I should have posted the code I'm trying to use the first time around. To elaborate a bit more, I'm trying to use JQuery's $.getJSON to get data from the Model (via the Controller), and populate a JSON object. The javascript I'm using is below:
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("<%=Url.Action("PopulateJournalOptions", "Evaluation", Model.ID) %>", populateJSON);
});
</script>
PopulateJournalOptions is my Controller Action, Evaluation is my Controller Name, and Model.ID is what I'm trying to pass to it. Incidentally, I should be able to achieve the same thing using:
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("/Evaluation/PopulateJournalOptions/<%= Model.ID %>", populateJSON);
});
</script>
But even here, I'm not sure those angle brackets are being used correctly. It definitely looks a bit off. Thanks for the help.
UDPATE: Went ahead and tried the second method above and it does indeed work. I'm still having trouble using the first method that uses Url.Action(), which is a shame because I think it's the better method. But the <% tags are definitely rendering data now. I guess it just threw me when there was no intellisense and they didn't highlight like normal. Thanks for the quick responses. Any ideas on the right format for the first option above?
Generally speaking, <%= %> blocks should only be used within quotes in Javascript. Because you're inside quoted text, Intellisense may not work.
It ought to work - your C# should execute server side before the JavaScript does clientside. Intellisense may just be confused by the context.
I use this technique with PHP and JavaScript sometimes.
You need to be careful when writing strings into script tags, because as it is javascript the expectation is that the string has special characters encoded properly. Additionally, if that string contains something like "</script>" you run the risk of browsers that aren't running javascript ending the script block early.
An easy way to encode the strings is with a JSON serializer, perhaps JavaScriptSerializer().
<script>
var targetUrl = <%= (new JavaScriptSerializer()).Serialize("http://url/") %>;
</script>
I think this is safer. You'd want to put this code in a helper function, I just instantiate JavaScriptSerializer() in-place there so its the simplest example possible.
One side effect of this is that the <%= %> expression is not within quotes, which sounds like it would help your original autocomplete support issures. Note that Serialize() will not only properly escape the string for javascript, it will also escape-encode the '<' and '>' characters so that "</script>" scenario can't happen.
Correct me if I'm wrong, but I've never seen Url.Action used like this:
<%= Url.Action("PopulateJournalOptions", "Evaluation", Model.ID) %>
shouldn't it be like this?
<%= Url.Action("PopulateJournalOptions", "Evaluation", new { ID = Model.ID } ) %>
Note new { ID = Model.ID }
Url.Action uses reflection on an object's properties to figure out what the route values are. Since an int object has no fields/properties, it will not detect anything.
You might try single quotes:
$.getJSON('<%=Url.Action("PopulateJournalOptions", "Evaluation", Model.ID) %>', populateJSON);

Categories