I have looked around but I can't find a lead on what I need to do to make the following possible:
This question assumes I have all model controllers working properly and the named CSS attributes are defined in the default stylesheet.
I am wanting users to be able to select a few CSS attributes to personalize their own theme when they login. The basics attributes would be the "body" and "page-wrapper" colour. (foreground)
I am wanting them to be able to select these attributes (from a form?) in the user's edit page. (which is already created)
Any ideas as to how I could make this work or a good lead in the right direction?
Thanks for your help.
I think the best approach is via javascript, generating an style tag on the head with the desired styles. Jquery gives a simple way to do that, and you can store the styles on a column in your model.
Something like this:
class User
attr_accesible :styles
view.erb
<script>
// Assume the #styles attr has something like "body { background-color: #567;}"
$('head').append($('<style>').html('<%= #user.styles %>'))
</script>
#styles will be another column in your model, so you should add it with a migration
rails g migration addstylestousers styles:string
in your form.erb
<%= f.label :styles %>
<%= f.text_field :styles %>
I think it's simple enough for the user to put the css style here as long as you give him enough tips like "add body { background-color: red } in this field to make you background red!".
About serialization, consider this.
If you want to nest the styles, then the script will be
//Lets say that the user stored on #bgcolor and #fgcolor only css color codes, like '#222' or 'blue'
var bgc = '<%= #user.style.bgcolor %>'
var fgc = '<%= #user.style.fgcolor %>'
var style = 'body { background-color: ' + bgc + '; foreground-color: ' + fgc + ' }'
$('head').append($('<style>').html(style))
Remember that relationship should be User has_one :style on this case. However, nesting it's getting yourself into more problem, I don't think it's worth it at all.
Related
Note: This explanation is targeted for beginners.
I was facing the problem of not being able to change the image in a link_to when I hovered over the image. Nothing I did in CSS seemed to solve the problem. I present my solution to this problem below.
This is my link_to:
<%= link_to image_tag('1487789814_back.png'),
{controller: #controller_action_hash_from_params[:controller],
action: #controller_action_hash_from_params[:action]},
sql_text: #sql_text,
:id => "ralph-back-button-black-img", :class => "ralph-fieldset-back-button" %>
1487789814_back.png is an ordinary png in app/assets/images. It happens to be a black arrow pointing left. Similarly, app/assets/images/1487789814_back_red.png (used below) is a red arrow pointing left. I wanted the red arrow to appear when I hovered over a fieldset containing the black arrow.
The source of the problem:
The link_to above generates/generated the following HTML:
<img src="https://localhost:3000/assets/1487789814_back-731afaae70e04062b25988079e4ef8ab4e6b523f4ac11ff7d142a9ff01e63455.png" alt="1487789814 back">
Note:
The file https://localhost:3000/assets/1487789814_back-731afa...3455.png" will not exist for you. It's a filename automatically generated by Rails
Analysis:
The problem comes, in part, because (I believe) css cannot override HTML. That is, if you specify an attribute (e.g. width) in your HTML, you cannot override that in css. Similarly, (I believe) you cannot override the src="https: ..." in css. Any attempt (I believe) to use :hover will fail. To make this work, you'll need a bigger hammer: javascript or jquery.
My solution:
Please note: I am not claiming this solution is the best solution or even a good solution. I am claiming it works in my Rails 4 environment.
If you are using the asset pipeline in Rails 4 (Rails 3? Rails 5?), your "friendly" image names (in my case 1487789814_back.png and 1487789814_back_red.png) will be converted by the asset pipeline system into names with a cryptographic hash appended. In other words, to get access to the red arrow image you need to know what name Rails assigned to your image. It is beyond the cope of this little article to explain why Rails renames your image file; just know that it does. (Of course, your original file will still be there with its original name.)
So somehow we must "map" the friendly name (e.g. "1487789814_back.png") to the name in the asset pipeline.
I accomplished this by creating a div with "display:none" css.
erb:
<%# This div has display:none.
We do this in order to preload the images_path as well as create a "map"
between the friendly name and the asset pipeline name
%>
<div class='ralph_preload'>
<%= image_tag('1487789814_back.png', options={class:'ralph_preload_class', id:'1487789814_back'}) %>
<%= image_tag('1487789814_back_red.png', options={class:'ralph_preload_class', id:'1487789814_back_red'}) %>
</div>
The erb above generated the following HTML:
<div class="ralph_preload">
<img class="ralph_preload_class" id="1487789814_back" src="/assets/1487789814_back-731afaae70e04062b25988079e4ef8ab4e6b523f4ac11ff7d142a9ff01e63455.png" alt="1487789814 back">
<img class="ralph_preload_class" id="1487789814_back_red" src="/assets/1487789814_back_red-bbd0f2e34f3401cc46d2e4e1e853d472d8c01c9a75f96d78032738bd01b2133b.png" alt="1487789814 back red">
</div>
The associated css is:
.ralph_preload {
display: none;
}
I created some jQuery to change the black arrow to red when the user hovers:
<script type="text/javascript">
function get_precache_myStruct_array(outer_div_class){
var myStruct_array = [];
$('.'+outer_div_class).find(".ralph_preload_class").each(function(){
var myStruct = {
id: this.id,
src: this.src
};
// myStruct_array.push(myStruct);
myStruct_array[this.id] = myStruct;
});
return myStruct_array;
}
// See http://stackoverflow.com/questions/15352803/how-to-check-if-an-image-was-cached-in-js
function is_cached(img_url){
var imgEle = document.createElement("img");
imgEle.src = img_url;
return imgEle.complete || (imgEle.width+imgEle.height) > 0;
}
$(document).ready(function(){
var precache_myStruct_array = get_precache_myStruct_array("ralph_preload");
$.each(precache_myStruct_array,
function (index, value) {
if (!is_cached(value.src)) {
alert("Not cached!: " + value.src);
};
});
<% if true %>
$('#ralph-back-button-filedset').hover(function(){
var precache_myStruct_array = get_precache_myStruct_array("ralph_preload");
var imageID = '1487789814_back_red';
$('#ralph-back-button-black-img > img:nth-child(1)').attr("src", precache_myStruct_array[imageID].src);
}, function(){
var precache_myStruct_array = get_precache_myStruct_array("ralph_preload");
var imageID = '1487789814_back';
$('#ralph-back-button-black-img > img:nth-child(1)').attr("src", precache_myStruct_array[imageID].src);
});
<% end %>
});
</script>
You might notice a "<% if true %>" / <% end %> block in the jQuery. Since the jQuery is "inlined" into the .erb file, the jQuery goes through erb processing. By changing the true to false, it can make using browser debuggers easier to use.
Conclusion:
I did a search on the web to find the answer to my problem. I found none that is, as the lawyers say, on point.
I am, of course, enthusiastically open to corrections and comments.
If you put those images in your public folder, they will not get the extra hash added to the image name.
With that said, I ran a loop in my controller that got me all the "Rails" file names for my images and stored them somewhere I could access them easily.
I'm working on a rails form in which I have multiples options to ask for a customer. Of which one has multiple options to select from. I was able to have the list of options generated through a collection, however my problem is that I would like the list to stretch out the entire width of the container it is located in. No matter what I try, I'm not able to get anything within it to respond. What is happening is I continue to get the default styles that come with the inputs. I was wondering if anyone could take a look and help me with this situation.
= f.input :recognition, class: "recognitionStyling", collection: %w{article, blog_post, linkedin, magazine_ad, online_search, referral, twitter, other}, required: false
.recognitionStyling{
width: 100%;
}
Since you use Simple Form, you should pass your css class name into input_html options if you want set class to input:
= f.input :recognition, input_html: { class: 'recognitionStyling' }
If you want to set css class to label:
= f.input :recognition, label_html: { class: 'recognitionStyling' }
If you want to wrap both your input and label (set css class to default Simple Form wrapper):
= f.input :recognition, wrapper_html: { class: 'recognitionStyling' }
I have my css alias like:
module MyPage
def locator(key, *options)
hash = {
"FIRST_TABLE_CELL_HREF" => [ :css => '#my-table td:nth-child(1):first a']
}
end
I want to click on that alias:
#page.find("FIRST_TABLE_CELL_HREF").when_present.right_click
Problem: that's a Javascript style alias, so it doesn't work.
Question: how to write the same Ruby style css alias?
P.S. $('#my-table td:nth-child(1):first a') works well in browser console.
For #TitusFortner that's true when you want to select specific element. But I'm using some business level language (Gherkin in my case) and I want to write an universal instruction. It'd look like When I right click on the element "FIRST_TABLE_CELL_HREF". That instruction would be mapped to:
When(/^I right click(?: on|)(?: the|) "([^\"]*)"$/i) do |scope|
#page.find(scope).when_present.right_click
end
Where #page = #browser.visit(SomePage), where in turn #browser = BrowserBase.new start_browser(ENV['BROWSER'])
With Watir you often don't even need to use css
browser = Watir::Browser.new
First link in the table:
browser.table(id: 'my-table').link
Link in first data cell in table:
browser.table(id: 'my-table').td.link
If it has to be just css for some reason:
browser.link(css: '#my-table a')
Also if your table is within the context of an iframe, you have to explicitly declare it, because the driver can only see the top level browsing context unless specifically switched to. With Watir this would work:
browser.iframe(id: 'iframe_id').table(id: 'my-table').link
This would not work:
browser.link(css: '#iframe_id #my-table a')
I am using best_in_place gem which is awesome for inplace editing in rails apps.
But the problem with my implementation is the area that is defined as best in place wraps only around the text and so due to which there is some kind of wobbling[1] effect if I try to edit some desired field. So is there any way where in I can make the fixed text_area size so that it stays with the width that I want.
[1] By wobbling I mean when I click on the field i.e., when the field is focus it is of some width and when I tab-out it goes to default wrapper size.
The key is defining the inner class, rather than just the class. As in:
user/show.html.erb:
<%= best_in_place #user, :name, :inner_class => "css_class" %>
custom.css:
.css_class {
background:red;
}
Not sure if this helps, but I had kind of similar problem (same problem but with the text field), and this is how I've resolved it:
First add class to the best_in_place field:
<%= best_in_place #your_variable, :name, { :classes => "input_field" } %>
(I work with best_in_place 2.1.0, for older version you would need to depend on the id of the field, which seems to be unique)
Then apply styling to the input child of the class in your css:
.input_field input {
width: 400px;
}
and that should do it.
In my web app (c#/MVC3), I have a huge set of checkboxes in a table. Rather than a table of checkboxes, I'd like for it to look like a wall of toggle buttons. To the user I want it to look like a wall of buttons and when they click one it is 'checked' and the button changes color.
I wasn't sure if there was CSS that could make a checkbox do this (look like a button and change colors on check rather than show a check mark), or if I would have to use some combination of buttons and javascript/jquery and hidden checkboxes or what.
The jQuery UI Button widget can handle that:
http://jqueryui.com/button/#checkbox
Yes, it is definitely possible to do what you want with pure CSS.
I think you should check out the jsFiddle mentioned on this question.
Radio buttons are generated by the operating system and cannot be easily styled.
If you wany something different you need to generate it using CSS/images and JavaScript.
First of all, I'd actually avoid doing this for usability concerns but if you still want to then read on.
This is actually quite tricky to achieve but it is possible. My solution avoids the need to assign individual IDs to your check-boxes.
Essentially, you will need an image sprite for the "on" and "off" states which you will position with the CSS background-position property, using a toggle class. Then, the following jQuery will allow you to not only swap the image state, but also confirm the respective checkbox as checked or unchecked for use of the form. Do note, that the "actual" checkbox is hidden from view but the functionality remains.
<form>
<input type="checkbox" class="custom" />
</form>
<style type="text/css">
.checkbox {
clear:left;
float:left;
background:url('your_image');
background-position:top;
width:20px;
height:20px;
display:block;
}
.toggled {
background-position:bottom !important;
}
</style>
$(document).ready(function () {
var checkboxes = $('form .custom'),
custom = $('<span></span>').addClass('checkbox');
checkboxes.before(custom);
checkboxes.css('visibility', 'hidden');
$('.checkbox').click(function () {
$(this).toggleClass('toggled');
var isChecked = $(this).next(':checkbox');
var value = isChecked.prop('checked') ? 'true' : 'false';
if (value == 'false') {
isChecked.prop('checked', true);
} else {
isChecked.prop('checked', false);
}
});
});
You will, of course, have to edit the CSS to suit your exact needs. I hope this helps as this task was deceptively non-trivial.