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
Related
I have the following helper function in ruby :
def site_css_link_tag(merchant_canonical:, site_variant:, template_previewing:)
# TODO: will remove variant argument
is_js_generate = merchant_canonical.nil? && site_variant.nil? && template_previewing.nil?
url = is_js_generate ? '' : css_api_v2_shopfront_sites_url(
merchant: merchant_canonical,
variant: site_variant,
template_previewing: template_previewing
)
# return stylesheet_link_tag url, url, media: 'all', id: 'site-css', 'data-base-url': css_api_v2_shopfront_sites_url
cssStyles = File.read(File.join(Rails.root, 'public', Webpacker.manifest.lookup('shopfront_redux.css'))).html_safe
return cssStyles
end
It returns all the styles correctly , I.E. i do see the output in the browser like so:
but how do i add this to a style tag ?
I have seen the ruby documentation here. It say for javascript you can have something like :
javascript:
alert('ok')
I tried doing the same with the css like so:
style:
site_css_link_tag(merchant_canonical: #merchant&.canonical_name, site_variant: #variant, template_previewing: #template_previewing)
But this variation does't seem to work ? So how do i output the css once again ?
Try css:
css:
site_css_link_tag(merchant_canonical: #merchant&.canonical_name, site_variant: #variant, template_previewing: #template_previewing)
I just started using vue-i18n and tried to use the v-on-directive (shorthand: #) in my language specific text.
What i tried to do:
// locale definition
let locale = {
en: {
withEventListener: 'Some HTML with <a #click="onClickHandler">event handling</a>'
}
}
and the vue template:
<!-- vue template be like -->
<p v-html="$t('withEventListener')" />
This doesn't throw an error but unfortunately it does not get evaluated by vue-js either. This would result to Plain-HTML like:
<p>
Some HTML with <a #click="onClickHandler">event handling</a>
</p>
So my question is if there is a way to make Vue 'evaluate' the text and thus 'translate' the directives within the text.
You can use Vue.compile to do something like this if you are including the standalone build script. I'm not familiar with vue-i18n, but this might put you on the right path.
Note that I had withEventListener to wrap it in a div because of the rules around templates.
let locale = {
en: {
withEventListener: '<div>Some HTML with <a #click="onClickHandler">event handling</a></div>'
}
}
const res = Vue.compile(Vue.t("withEventListener"));
Vue.component("internationalized", {
methods:{
onClickHandler(){
alert("clicked")
}
},
render: res.render,
staticRenderFns: res.staticRenderFns
})
new Vue({
el:"#app"
})
With the template
<div id="app">
<internationalized></internationalized>
</div>
Working example.
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 :-)
So I have my first MVC2 site that I'm working on and naturally I'd like to throw some AJAX in there. The problem is, is that I don't know how to get the URL for the action when passing in a URL parameter. Let me explain. The examples I've seen so far show the developer passing in strings like '/MyController/MyAction'. That's great, except if your controllers are not in the root directory of your website (as is the case in my situation). I could always use relative URLs like 'MyAction' except if the URL contains parameters that doesn't work either. Consider http://example.com/myroot/MyController/MyAction vs http://example.com/myroot/MyController/MyAction/PageNumber/SomeOtherValue. Now the relative URL will be incorrect.
In the ASPX code, this is easy. I just write in <%= Url.Action("MyAction") %>. But how do I do this in my javascript file?
This is part of the long-standing issue that including server-sided code in JavaScript files is not really possible :(. (Without serious hacks, that is.)
The best solution is to include the action URL inside your HTML file somewhere, then get that value from JavaScript. My suggestion would be something like this:
<!-- in your view file -->
<form id="MyForm" action="<%: Url.Action("MyAction") %>"> ... </form>
<!-- or -->
<a id="MyLink" href="<%: Url.Action("MyAction") %>"> ... </a>
combined with
// In your .js file
$("#MyForm").submit(function ()
{
$.post($(this).attr("action"), data, function (result) { /* ... */ });
return false;
});
// or
$("#MyLink").click(function ()
{
$.getJSON($(this).attr("href"), data, function (result) { /* ... */ });
return false;
});
This feels semantically clear to me, and in some cases even creates degradable fallback behavior for when JavaScript is turned off.
You can't do this in your JavaScript file directly, however you can pass these dynamic values into your script by way of a script initializer. Consider the following example:
External Js file
ShoppingCart = function() {
this.settings = {
AddProductToCartUrl: '',
RemoveFromCartUrl: '',
EmptyCartUrl: '',
UpdateCartUrl: ''
};
};
ShoppingCart.prototype.init = function(settings) {
this.settings = jQuery.extend(this.settings, settings || {});
};
HTML/View
<script type="text/javascript">
var cart = new ShoppingCart();
cart.init({ AddProductToCartUrl: '<%=Url.Action("MyAction")%>' });
alert(cart.settings.AddProductToCartUrl);
</script>
Simple: tell your javascript what the correct URL is.
Tactically, you can get there alot of ways, but they basically break down into two techniques:
Have a server-side generated javascript "configuration" so you can do something like var url = siteConfiguration.SITEROOT + 'products/pink-bunny-slippers' Note this file can be a normal MVC view, the only trick is you have to tell the controller to send a text/javascript header rather than text/html.
Basically, dependency inject it into your script. IE function wireUpAjaxLinksToService(linkIdentifier, serviceEndpoint) where you call using something like wireUpAjaxLinks('a.ajax', '<%= Url.Action("MyService", "Services") %>')
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.