I have a .html.erb file, with some javascript in it. I would like to do something like this:
var stuff = '<div><%= #ruby_var.title %></div>'
What is the best way to do this? I may be totally off... Thanks.
To safely do this you need to use to_json:
<%= javascript_tag do %>
var stuff = <%= #ruby_var.title.to_json %>;
<% end %>
This will ensure your code does not break if #ruby_var.title has a quote in it.
To include the divs I would do:
<%= javascript_tag do %>
var stuff = <%= "<div>#{#ruby_var.title}</div>".to_json %>;
<% end %>
Note that there are no quotes around <%= %>, to_json takes care of that for you.
<script>
var stuff = '<div><%=escape_javascript #ruby_var.title %></div>'
</script>
in your .html.erb file will work fine.
Ruby can't be run on the client, at least not with specialized browser plugins. Instead, look at using AJAX and RJS to query your Ruby web application from Javascript and insert any text it returns into your page.
Without more information, I don't think you're going to get any better answers. I might be totally off too, because I'm only guessing at what you really want to do.
You can use the javascript_tag function to include Javascript in a .html.erb file.
Example:
javascript_tag "alert('This is a test')"
in your foo.html.erb will return
<script type="text/javascript">
//<![CDATA[
alert('This is a test')
//]]>
</script>
to the browser.
Related
I am making a css grid system that relies on the concept of blocks. So I have a base file like:
$max-columns: 4;
$block-width: 220px;
$block-height: 150px;
$block-margin: 10px;
And it is used by a mixin:
#mixin block ($rows, $columns, $max-columns) {
display: block;
float: left;
margin: $block-margin 0 0 $block-margin;
box-sizing: border-box;
width: ($block-width * $columns) - $block-margin;
}
But I'd also like javascript to have access to the variables in the base file. I was thinking that I could make an invisible div, and give it the $block-width, $block-height, and $block-margin attributes and pull the values from there. But max-columns, doesn't map to anything directly, so I'd have to come up with a hacky way to render it in a div. Is there a cleaner way to share values from sass/css to javascript or vice versa?
If you use webpack you can use sass-loader to exportvariables like:
$animation-length-ms: $animation-length + 0ms;
:export {
animationMillis: $animation-length-ms;
}
and import them like
import styles from '../styles/animation.scss'
const millis = parseInt(styles.animationMillis)
https://blog.bluematador.com/posts/how-to-share-variables-between-js-and-sass/
I consider my solution to be quite hokey; but it does work...
In my _base.scss I have some variables defined:
$menu_bg: rgb(45, 45, 45);
$menu_hover: rgb(0, 0, 0);
In a menu.scss I have:
#import "base";
#jquery_vars {
.menu_bg {
background-color: $menu_bg;
}
.menu_hover {
background-color: $menu_hover;
}
}
And in a handy page template:
<span class="is_hidden" id="jquery_vars">
<span class="is_hidden menu_bg"></span>
<span class="is_hidden menu_hover"></span>
</span>
Finally this allows in a nearby jQuery script:
var menu_bg = $('#jquery_vars .menu_bg').css("background-color");
var menu_hover = $('#jquery_vars .menu_hover').css("background-color");
This is so ugly my dad is wearing a bag on his head.
jQuery can pull arbitrary CSS values from page elements; but those elements have to exist. I did try pulling some of these values from raw CSS without creating the spans in the HTML and jQuery came up with undefined. Obviously, if these variables are assigned to "real" objects on your page, you don't really need the arbitrary #jquery_vars element. At the same time, one might forget that .sidebar-left nice-menu li is the vital element being use to feed variables to jQuery.
If someone has anything else, it's got to be cleaner than this...
sass-ffi should do the trick, but the opposite way (from JS to SASS/SCSS). It will define a function called ffi-require, which allows you to require .js files from SASS:
config.js:
module.exports = {
maxColumns: 4,
};
style.scss:
$max-columns: ffi-require('./config', 'maxColumns');
Works with sass-loader (webpack) and node-sass.
You can read the sass file with a server side script, "parse" it and echo the values you need to javascript.
I would like to add that there are now several ways to share data between Sass and JavaScript using JSON. Here are some links to articles detailing various techniques:
Making Sass talk to JavaScript with JSON
SassyJSON: Talk to the browser
Sharing Data Between Sass and JavaScript with JSON
It's probably just a matter of time until JSON importing becomes supported natively in Sass.
I would recommend looking at sass-extract which uses native sass features in order to extract the computed variable values into JSON.
Also if you are using webpack the sass-extract-loader will make it very easy to just require/import the sass files as in const variables = require('sass-extract-loader!./variables.scss'); and have your sass variables in a nice JSON object.
Since it also supports #import statements you can still separate your variables in different files, and no need to add additional preprocessing or separate json files with variables.
There are many alternative ways of accomplishing this as mentioned in other answers, and which one you choose will depend on your use case and environment.
Disclaimer, I am the author of both mentioned libraries.
Another way could be to use gulp-template so you can generate any structure you want for your JavaScript.
Sharing Variables between Javascript and Sass using Gulp with gulp-template
https://youtu.be/UVeUq8gMYco
It's created from scratch so people could see it from the ground up and there is a git repo with the end result:
https://github.com/PocketNinjaCoUk/shared-js-sass-vars-using-gulp/tree/master/dev
You basically have your config object
saved at ./dev/config.js
module.exports = {
defaults: {
colours: {
primary: '#fc0'
},
sizes: {
small: '100px',
medium: '500px',
large: '1000px'
},
zIndex: {
model: 100,
dropdown: 50,
header: 10
}
}
}
Then you have both of your templates for Sass and Javascript, or less or whatever you want.
Sass underscore template
saved at ./dev/templates/sass-config.txt
<% _.each(defaults, function(category, key) { %>
// Var <%= key %>
<% _.each(category, function(value, key) { %>
$<%= key %>: <%= value %>;
<% }) %>
<% }) %>
Javascript underscore template
saved at ./dev/templates/js-config.txt
namespace.config = {};
<% _.each(defaults, function(monkey, key) { %>
namespace.config.<%= key %> = {
<% i = 1 %>
<% _.each(monkey, function(value, key) { %>
<% comma = (Object.keys(monkey).length === i) ? '': ',' %>
<% if(typeof value === 'string') {%>
<%= key %>: '<%= value %>'<%= comma %>
<%} else { %>
<%= key %> : <%= value %><%= comma %>
<% } %>
<% i++ %>
<% }); %>
};
<% }) %>
Then the gulp to compile it
var gulp = require('gulp');
var template = require('gulp-template');
var rename = require('gulp-rename');
var removeEmptyLines = require('gulp-remove-empty-lines');
var sharedVars = require('./dev/config');
gulp.task('compile', function() {
gulp.src('./dev/templates/sass-config.txt')
.pipe(template(sharedVars))
.pipe(rename('_sass-config.scss'))
.pipe(removeEmptyLines())
.pipe(gulp.dest('./dev/sass'));
gulp.src('./dev/templates/js-config.txt')
.pipe(template(sharedVars))
.pipe(rename('js-config.js'))
.pipe(removeEmptyLines())
.pipe(gulp.dest('./dev/js'));
});
This can be done using gulp-sass-vars-to-js. It generates a .js file from your .scss file. The .js file contains all variables declared in your .scss file. You can then 'require' this generated js into your .js
My website has two languages and I have a problem with the footer links.
Before my redesign I included different files. One with links pointing to /en/privacy/ or /en/contact/ etc. and another file with links like /datenschutz/ or /kontakt/
<% if Locale == en_GB %>
<% include Footer_en_GB %>
<% else %>
<% include Footer %>
<% end_if %>
That makes it hard to maintain.
Is there a better way? IS it possible to get the propper I18N link for a page?
Something like
i18ntitle('/datencshutz/')
so the EN footer will look like
Privacy
and the DE footer will look like
Datenschutz
If you are using Translatable Module and the Pages are actually Linked in the CMS, you can simply use $Link?Locale=en_US or rather /datenschutz/?Locale=en_US.
When you then visit /datenschutz/?Locale=en_US, SilverStripe will response with a redirect to the EN Link.
Or in PHP, you can use:
if ($page->hasTranslation('en_US')) {
$link = $page->getTranslation('en_US')->Link();
}
PS: this gist might also interest you: https://gist.github.com/Zauberfisch/9226142#file-translatablecontrollerextension-php-L39
I thought there is some simple solution built in SS, but couldn't find any.
Here is what I have done now
Template:
<ul class="vertical menu">
<li>Startseite</li>
<li>Über uns</li>
<li>Kontakt</li>
</ul>
Necessary code in mysite/code/page.php (inside the Page class):
public function LanguageURL($page) {
if (empty($page)) {
$page = $this;
} else {
$SQL_url = Convert::raw2sql($page);
$page = Translatable::get_one_by_lang('SiteTree', 'de_DE', "URLSegment = '$SQL_url'");
}
if ($page->hasTranslation('en_GB') && Translatable::get_current_locale() == 'en_GB') {
$link = $page->getTranslation('en_GB')->Link();
} else {
$link = $page->getTranslation('de_DE')->Link();
}
return $link;
}
Your German website outputs
<li>Kontakt</li>
… and your English website outputs
<li>Contact</li>
Actual output depends on your config, but the point is to output the proper URL for the current locale.
Perhaps anybody needs something similar or has a better solution :-)
I want to generate a PDF with our department logo in it. When I try to use the WickedPdf class in my controller (using the method described at https://github.com/mileszs/wicked_pdf):
def some_action
image_tag_string = image_tag('logo.jpg')
pdf = WickedPdf.new.pdf_from_string(image_tag_string)
save_path = Rails.root.join('testpdfs','logotest.pdf')
File.open(save_path, 'wb') do |file|
file << pdf
end
end
...the application saves the PDF to the target directory, but it has a blue-and-white '?' mark where the image should be.
If I do this instead:
image_tag_string = wicked_pdf_image_tag('logo.jpg')
pdf = WickedPdf.new.pdf_from_string(image_tag_string)
I get the following error:
NoMethodError:
undefined method `wicked_pdf_image_tag' for #<...
It would appear that my Rails app is also missing / not linking to a helper file belonging to the wicked-pdf gem.
Answers to similar questions on StackOverflow recommend writing a custom "image-tag" helper to locate the image or installing wkhtmltopdf. For me, image-tag shows the logo just fine when placed in a View (whatever.html.erb). "logo.jpg" is already located in both the asset pipeline and #{RailsRoot}/public/images. Finally, I am using wkhtmltopdf 0.9.9, wicked-pdf 0.11.0, and rails 4 on Ubuntu 14.04.
In a nutshell - what am I doing wrong that causes WickedPDF to fail to render the image?
First thing create a pdf template to render and use your wicked_pdf tags in that template..
for example-
app/views/layout/application.pdf.erb-
<!doctype html>
<html>
<head>
<meta charset='utf-8' />
</head>
<body onload='number_pages'>
<div id="content">
<%= yield %>
</div>
</body>
</html>
app/views/pdf/pdf_view.pdf.erb-
<div>
<%= wicked_pdf_image_tag 'logo.jpg' %>
</div>
use this template instead
def save
pdf = WickedPdf.new.pdf_from_string(
render_to_string(
template: 'example/pdf_view.pdf.erb',
layout: 'layouts/application.pdf.erb'))
send_data(pdf,
filename: 'file_name.pdf',
type: 'application/pdf',
disposition: 'attachment')
end
This might help you..
Use the wicked_pdf_image_tag helper in your view and reference the image with asset_url if your image is in public/images or use asset_pack_url if the image is in public/packs/media/images
<%= wicked_pdf_image_tag asset_url('/images/footer_logo.png') %>
or
<%= wicked_pdf_image_tag asset_pack_url('media/images/footer_logo.png') %>
I converted image url that 'http' from 'https'. Than worked.
Heroku-18
Rails 4.2
wicked_pdf (1.1.0)
wkhtmltopdf-binary (0.12.4)
In my case, I am using carrierwave, the solution was taken from this post
<img src="<%= root_url + "/" +file.service_url %>">
This worked on rails 5.
I've been having trouble switching from a default layout.erb file to an equivalent layout.haml file in Middleman. I want to use HAML for my layouts since I'm trying to become familiar with it, so I decided to replace the default layout with a HAML version. Unfortunately, when I replace layout.erb with layout.haml, I get this error:
NoMethodError at /
undefined method `force_encoding' for nil:NilClass
Ruby /Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in ensure in binary, line 289
Web GET localhost/
Traceback (innermost first)
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in ensure in binary
string.force_encoding(original_encoding)...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in binary
string.force_encoding(original_encoding)...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in extract_magic_comment
binary script do...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in extract_encoding
extract_magic_comment(script) || script.encoding...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in precompiled
template_encoding = extract_encoding(template)...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/erb.rb: in precompiled
source, offset = super...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/erb.rb: in precompiled
source, offset = super...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in compile_template_method
source, offset = precompiled(locals)...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in compiled_method
compile_template_method(locals_keys)...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in evaluate
method = compiled_method(locals.keys)...
/Library/Ruby/Gems/2.0.0/gems/tilt-1.4.1/lib/tilt/template.rb: in render
evaluate scope, locals || {}, &block...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/core_extensions/rendering.rb: in render_individual_file
content = template.render(context, locs, &block)...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/core_extensions/rendering.rb: in render_template
content = render_individual_file(layout_path, locs, opts, context) { content }...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/sitemap/resource.rb: in block in render
app.render_template(source_file, locs, opts, blocks)...
/Library/Ruby/Gems/2.0.0/gems/activesupport-4.1.4/lib/active_support/notifications.rb: in instrument
yield payload if block_given?...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/util.rb: in instrument
::ActiveSupport::Notifications.instrument(suffixed_name, payload, &block)...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/application.rb: in instrument
delegate :instrument, to: ::Middleman::Util...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/sitemap/resource.rb: in instrument
delegate :logger, :instrument, to: :app...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/sitemap/resource.rb: in render
instrument 'render.resource', path: relative_source, destination_path: destination_path do...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/core_extensions/request.rb: in process_request
output = resource.render do...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/core_extensions/request.rb: in block in call!
process_request(env, req, res)...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/core_extensions/request.rb: in catch
catch(:halt) do...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/core_extensions/request.rb: in call!
catch(:halt) do...
/Library/Ruby/Gems/2.0.0/gems/middleman-core-3.3.3/lib/middleman-core/core_extensions/request.rb: in call
dup.call!(env)...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/builder.rb: in call
to_app.call(env)...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/urlmap.rb: in block in call
return app.call(env)...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/urlmap.rb: in each
#mapping.each do |host, location, match, app|...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/urlmap.rb: in call
#mapping.each do |host, location, match, app|...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/showexceptions.rb: in call
#app.call(env)...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/head.rb: in call
status, headers, body = #app.call(env)...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/lint.rb: in _call
status, headers, #body = #app.call(env)...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/lint.rb: in call
dup._call(env)...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/builder.rb: in call
to_app.call(env)...
/Library/Ruby/Gems/2.0.0/gems/rack-1.5.2/lib/rack/handler/webrick.rb: in service
status, headers, body = #app.call(env)...
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/httpserver.rb: in service
si.service(req, res)...
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/httpserver.rb: in run
server.service(req, res)...
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/server.rb: in block in start_thread
block ? block.call(sock) : run(sock)
layout.erb looks like this:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<!-- Always force latest IE rendering engine or request Chrome Frame -->
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<!-- Use title if it's in the page YAML frontmatter -->
<title><%= current_page.data.title || "The Middleman" %></title>
<%= stylesheet_link_tag "normalize" %>
<!-- <%= stylesheet_link_tag "normalize", "all" %> -->
<%= javascript_include_tag "all" %>
</head>
<body class="<%= page_classes %>">
<%= partial "header" %>
<%= yield %>
<%= partial "footer" %>
</body>
</html>
layout.haml doesn't have quite the same content as layout.erb, but that doesn't seem to matter since it breaks no matter what:
!!!
%html
%head
%title
= current_page.data.title || "The Middleman"
= stylesheet_link_tag "normalize", "all"
= javascript_include_tag "all"
%body
= partial "header"
= yield
= partial "footer"
At first I thought the error was only ocurring because the HAML itself was broken, but even a very simple HAML file that defines only doctype, html, head, title and body tags breaks. I then suspected that only ERb files were being taken as layout files - which I confirmed by renaming layout.haml to layout.erb, which didn't cause an error but just displayed raw HAML code instead. Even keeping layout.erb and making a sublayout article_layout.haml causes a similar error when navigating to a blog article, while making an article_layout.erb works fine.
So, I suspect that Middleman just won't accept anything except ERb for layout files. I can't find a single thing about this in the documentation, though, and I've even seen examples that all have layout.haml files that work perfectly fine. Is mine just different? Is there a flag I need to set with middleman init in order to use HAML files for layouts? What's going on?
As #r.pazyaquian mentioned in the sub-comments, if you change your layout file type, make sure to restart the server.
I'm working with a site using client-side templates through knockout.js.
The backend api, and login, is written in rails.
What I want to do is have each client-side html template in a separate file, and then have those templates lifted into the page using the templates. Similar to how javascript files are lifted in.
So I have a directory in my app/assets called templates
Each template in the directory should be added to the page in a script tag with the type="text/html"
I've gotten so far as to product the actual templates content now I just want to put it in the html.erb file in the head property.
However it always lands in the Body as normal text, not as HTML.
I've defined the following method in my controller:
def html_templates
output = ''
templates = Dir.glob 'app/assets/templates/*'
templates.each { |template|
file = File.open(template, "rb")
output += '<script type="text/html" id="'+(File.basename template, '.html')+'">'
output += file.read
output += '</script>'
}
return output
end
I try to add it to the .erb layout file like so:
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<%= html_templates %>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
Yet the output is always put in the body, with all my html escaped.
Also, if anyone has better solutions to have to solve this. Please, recommend.
Thanks :) so basically you should use raw method whenever you don't want output to be escaped