HAML - a very weird indentation difference - bug? - ruby

This HAML
%script{:type => "text/javascript"}
:plain
$(document).ready(function() {
bar();
var foo = foo_func("#{}");
});
as expected gives this:
<script type='text/javascript'>
$(document).ready(function() {
bar();
var foo = foo_func("");
});
</script>
But this ALMOST IDENTICAL HAML (changed only bar()to prep()):
%script{:type => "text/javascript"}
:plain
$(document).ready(function() {
prep();
var foo = foo_func("#{}");
});
gives this:
<script type='text/javascript'>
$(document).ready(function() {
prep();
var foo = foo_func("");
});
</script>
NOTE THE MESSED UP INDENTATION in the second case.
Why would changing bar()to prep() cause this weird difference?

This is being caused by the characters pre in prep() matching a regex that Haml is using to deal with whitespace.
In Haml you use whitespace to specify the contents of elements, and normally this is okay since when viewing HTML whitespace is “squashed” so that it appears as a single character. However, whitespace is important in some HTML elements (pre, code and textarea), and Haml tries to detect and deal with these elements. In this case the regex is matched and the block after the first line isn’t indented.
This code has been changed in the latest version (currently 4.0.1.rc.1) and this doesn’t happen in that version. I’ve also created a pull request that fixes the regex in the 3-1 branch.

Related

Ace editor YAML syntax highlighting error on a non-quoted string starting with a number

I'm using the ACE editor (http://ace.c9.io/) with this code:
<script src="https://cdn.jsdelivr.net/g/ace#1.2.6(min/ace.js+min/theme-cobalt.js+noconflict/mode-yaml.js)"></script>
<script>
function tuneEditor( editor )
{
editor.setTheme( "ace/theme/cobalt" );
editor.getSession().setMode( "ace/mode/yaml" );
editor.setShowPrintMargin( false );
editor.setShowInvisibles( true );
editor.setReadOnly( true );
editor.focus();
}
var contactEditor = ace.edit( "contactEditor" );
tuneEditor( contactEditor );
</script>
The YAML syntax highlighting in the ACE editor works well when coloring an unquoted key-pair, for example name: Alice.
Nevertheless, if the value is a string, but starts with a number, it colors part of the value as a number and part of it as a string, instead of interpreting that the value data-type is a string.
For example: title: 123hello would contain 123 in one color and hello in another one.
Source of truth
According to this official page: http://yaml.org/spec/1.2/spec.html#style/flow/plain:
Plain scalars must not begin with most indicators, as this would cause ambiguity with other YAML constructs.
Ie: The only restriction to the "plain scalar" (ie: non-quoted) is to not begin with "indicators" (like :, | and so on). It does not say anything about it not starting with digits.
If we look into the "indicators" section here http://yaml.org/spec/1.2/spec.html#indicator// we don't see that digits count as indicators.
Usability threat: It confuses users
This is specially ugly for sha1 identifiers and similar situations, like in this image. This confuses very much my users:
Question
How can I make the ace editor do this syntax highlight to appear coloring only with one color the full value?
It's been corrected as a bug... but it seems jsdeliver does not make it easy to get the links for newer versions. I used v1.2.6 and the latest is v1.4.1
Changing
<script src="https://cdn.jsdelivr.net/g/ace#1.2.6(min/ace.js+min/theme-cobalt.js+noconflict/mode-yaml.js)"></script>
for
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.1/ace.js" integrity="sha256-kCykSp9wgrszaIBZpbagWbvnsHKXo4noDEi6ra6Y43w=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.1/theme-cobalt.js" integrity="sha256-OEJvWvZJvQ8cFFLk43d1UF5DHqWdikG1n8CJQSP70TA=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.1/mode-yaml.js" integrity="sha256-95xNUgbfIXvRXJezV53+JM5HPO6PnJ+wZ7/GwdesKAE=" crossorigin="anonymous"></script>
did the trick:

Get requested page <url> inside ajax call on some web page

I'm using Nokogiri, at this moment, I have variable which contains code of some page: doc = Nokogiri::HTML(open(page)). There is script in code, ajax calls:
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
$("#menu").kendoMenu();
$('.menu_item').on('click', function (e){
$.ajax({
url: '/movie/101299-the-hunger-games-catching-fire/images?kind=backdrop&language=' + $(this).attr('alt') + '&translate=false',
cache: false
}).done(function(response) {
$('#image_panel').html(response);
});
});
$.ajax({
url: '/movie/101299-the-hunger-games-catching-fire/images?kind=backdrop&language=&translate=false', //goal
cache: false
}).done(function(response) {
$('#image_panel').html(response);
});
});
</script>
There is some way to get second request url, and place it to the variable, I need to go to this url. Unfortunately I didn't find something about it, maybe phantomjs can help me?
I think you will to manually parse the script element. You can do this by using Nokogiri to get the text of the script element. Then use a regexp to find the last url:
Assuming the script is the first on the page, you can do:
url = doc.at_css('script').text.scan(/url: '(.*)'/).last.first
The following breaks the script down to provide explanation of each step:
# Get the text of the script element
# Note that this assumes it is the first script element (you may need to be more specific)
script = doc.at_css('script').text
# Find all urls in the script
urls = script.scan(/url: '(.*)'/)
# Of the urls found, take the last one
url = urls.last
# url is actually an array of length 1, since we used a matching group in the regex
# Take the first element of the array to get the url as a string
url = url.first
#=> "/movie/101299-the-hunger-games-catching-fire/images?kind=backdrop&language=&translate=false"

how to make ajax answer for slim?

in destroy.js.erb it works
$("<%= escape_javascript(render #comment) %>").appendTo("#commentlist");
how to do it for slim?
I have tried
$("= escape_javascript(render #comment)").appendTo("#commentlist");
and renamed to destroy.js.slim, but its not works
By default, Slim tries to convert your code into HTML markup, so your current code produces an error. You can check it by viewing http://<website_adress>/something/destroy.js
To fix this, you have to use pipe symbol, here is excerpt from official documentation:
The pipe tells Slim to just copy the line. It essentially escapes any processing. Each following line that is indented greater than the pipe is copied over.
http://rdoc.info/gems/slim/frames
Also, ruby embedding work a bit different for Slim, you have to use #{ruby code} instead of equal sign, if you embedding it into string.
To sum things up this is how it should look like to work:
|
$("#{escape_javascript(render #comment)}").appendTo("#commentlist");
This way you can add more lines without prepending code with pipe each time.
Just to note, there is also shortcut for escape_javascript called simply j, so you could've used this code:
|
$("#{j(render #comment)}").appendTo("#commentlist");
in view
- url_ajax = 'http://gilcierweb.com.br'
- content_for :js do
javascript:
var ids = new Array();
$('input[type=checkbox]:checked').each(function () {
var id = $(this).val();
ids.push($(this).val());
$('.' + id).fadeOut("slow").hide(1600).remove();
});
$.ajax({
type: "POST",
url: "#{escape_javascript(url_ajax)}",
data: {id_img: ids},
success: function (data) {
$('.contestants_list').append(data);
}
});
in layout
-if content_for?(:js)
== yield(:js)

coffeescript syntax error "unexpected REGEX"

I'm trying to convert jquery into coffeescript but I'm getting syntax error
SyntaxError: unexpected REGEX
This is my code:
container = document.querySelector('#style-container');
msnry = new Masonry( container, {
// options
columnWidth: 200
itemSelector: '.item'
});
What am I doing wrong?
Thanks!
That's not CoffeeScript. This is CoffeeScript:
container = document.querySelector "#style-container"
msnry = new Masonry(container,
columnWidth: 200
itemSelector: ".item"
)
You can convert JavaScript to CoffeeScript using this tool.
The specific error is referring to the comment tag. // doesn't mean a comment in CoffeeScript, so it falls back to an empty regular expression. A more useful regular expression would be /[0-9]+/, however the contents are optional in CoffeeScript.
// this is a JS comment
# this is a CS comment
The error is you are using // for a comment instead of #.
In addition to that, you example still looks more like JavaScript than CoffeeScript, but that's the specific error you are getting. See also http://js2coffee.org/
CoffeeScript comments start with #, instead of //. As noted above the // is used for a blank regex. When learning CoffeeScript, I recommend http://coffeescript.org/ and the Try CoffeeScript tool, so that you can see the JavaScript that your CoffeeScript would give rise to.

How to prevent CKEditor replacing spaces with ?

I'm facing an issue with CKEditor 4, I need to have an output without any html entity so I added config.entities = false; in my config, but some appear when
an inline tag is inserted: the space before is replaced with
text is pasted: every space is replaced with even with config.forcePasteAsPlainText = true;
You can check that on any demo by typing
test test
eg.
Do you know how I can prevent this behaviour?
Thanks!
Based on Reinmars accepted answer and the Entities plugin I created a small plugin with an HTML filter which removes redundant entities. The regular expression could be improved to suit other situations, so please edit this answer.
/*
* Remove entities which were inserted ie. when removing a space and
* immediately inputting a space.
*
* NB: We could also set config.basicEntities to false, but this is stongly
* adviced against since this also does not turn ie. < into <.
* #link http://stackoverflow.com/a/16468264/328272
*
* Based on StackOverflow answer.
* #link http://stackoverflow.com/a/14549010/328272
*/
CKEDITOR.plugins.add('removeRedundantNBSP', {
afterInit: function(editor) {
var config = editor.config,
dataProcessor = editor.dataProcessor,
htmlFilter = dataProcessor && dataProcessor.htmlFilter;
if (htmlFilter) {
htmlFilter.addRules({
text: function(text) {
return text.replace(/(\w) /g, '$1 ');
}
}, {
applyToAll: true,
excludeNestedEditable: true
});
}
}
});
These entities:
// Base HTML entities.
var htmlbase = 'nbsp,gt,lt,amp';
Are an exception. To get rid of them you can set basicEntities: false. But as docs mention this is an insecure setting. So if you only want to remove , then I should just use regexp on output data (e.g. by adding listener for #getData) or, if you want to be more precise, add your own rule to htmlFilter just like entities plugin does here.
Remove all but not <tag> </tag> with Javascript Regexp
This is especially helpful with CKEditor as it creates lines like <p> </p>, which you might want to keep.
Background: I first tried to make a one-liner Javascript using lookaround assertions. It seems you can't chain them, at least not yet. My first approach was unsuccesful:
return text.replace(/(?<!\>) (?!<\/)/gi, " ")
// Removes but not <p> </p>
// It works, but does not remove `<p> blah </p>`.
Here is my updated working one-liner code:
return text.replace(/(?<!\>\s.)( (?!<\/)|(?<!\>) <\/p>)/gi, " ")
This works as intended. You can test it here.
However, this is a shady practise as lookarounds are not fully supported by some browsers.
Read more about Assertions.
What I ended up using in my production code:
I ended up doing a bit hacky approach with multiple replace(). This should work on all browsers.
.trim() // Remove whitespaces
.replace(/\u00a0/g, " ") // Remove unicode non-breaking space
.replace(/((<\w+>)\s*( )\s*(<\/\w+>))/gi, "$2<!--BOOM-->$4") // Replace empty nbsp tags with BOOM
.replace(/ /gi, " ") // remove all
.replace(/((<\w+>)\s*(<!--BOOM-->)\s*(<\/\w+>))/gi, "$2 $4") // Replace BOOM back to empty tags
If you have a better suggestion, I would be happy to hear 😊.
I needed to change the regular expression Imeus sent, in my case, I use TYPO3 and needed to edit the backend editor. This one didn't work. Maybe it can help another one that has the same problem :)
return text.replace(/ /g, ' ');

Resources