I'm having trouble arriving at an approach to this problem. tl;dr I want to be able to set the css class of an li to the name of the current_user that posted the chat. Then based on that class, I'll apply different styling.
This is for a chat window and I want all the current users messages to display on one side and I want all other messages to display on the other side with a different color, etc.
I have a file.js.coffee that basically reads in some user input and apends it to an ordered list and adds some elements and classes along the way
projectRef.on "child_added", (snapshot) ->
message = snapshot.val()
$("<li class='self'>").append($("<div class='message'>").append($("<p>").text(message.text))).prepend($("<b/>").text(message.name + ": ")).appendTo $("#messagesDiv")
$("#messagesDiv")[0].scrollTop = $("#messagesDiv")[0].scrollHeight
$("#messageInput").keypress (e) ->
if e.keyCode is 13
text = $("#messageInput").val()
projectRef.push
name: userName
text: text
$("#messageInput").val ""
The above would yield something like this in the browser
<li class="self">
<b>User : </b>
<div class="message">
<p>My chatt message from file.js.coffee!!</p>
</div>
</li>
That 'self' class in the li is what I have been trying to dynamically set based on the current_user. So I have 2 issues - 1. I'm trying to figure out who posted the li and 2. I'm trying to dynamically set the class of that li based on the user that chatted/posted it.
My thinking was something along the lines of in the file.js.coffee use JQuery to grab that li and add the <%= current_user.name %> as a class then I could have a file.js.erb where I would do something like
<% unless $('li').hasClass('<%= current_user.name %>'); %>
<%= $('li').toggleClass('others') %>
<% end %>
This way it checks if the class of the target li is from the current user and if it is keep the css class as self if not toggle it to others. Then I could style the classes appropriately (left, right, background-color:blue;, etc).
Is there a more correct way to approach this problem given what I am trying to accomplish? I think so..
It seems like you are saying you're trying to assign a class as the current user's name.
I'm wondering if going that far is necessary.
Assigning the list element with a class named "current_user" might be enough, then have separate CSS to control anything with class named "current_user".
Here's an example fiddle.
CSS
li {
list-style:none;
clear:both;
float:right;
text-align:right;
background-color:#A7A2A0;
border:1px solid #EEE;
width:200px;
margin:10px;
padding:5px;
}
li.current_user {
float:left;
text-align:left;
background-color:#24887F;
}
HTML
<li class="current_user">
<b>Current User:</b>
<div class="message">
<p>My message!</p>
</div>
</li>
<li>
<b>All Other Users:</b>
<div class="message">
<p>Other person's smessage.</p>
</div>
</li>
UPDATE:
Looking at the firebase example I altered it to add a class "current_user" if the username matched the the name of the user that wrote the message. Below is the part of the code that I altered in the "displayChatMessage" function, I also added CSS to the head section for the "current_user" class.
Here's a link to the working example, view it in to different web browsers using different usernames at the same time to see.
function displayChatMessage(name, text) {
if(name == $('#nameInput').val()){
$('<div/>').text(text).prepend($('<em/>').text(name+': ')).appendTo($('#messagesDiv')).addClass('current_user');
$('#messagesDiv')[0].scrollTop = $('#messagesDiv')[0].scrollHeight;
}
else{
$('<div/>').text(text).prepend($('<em/>').text(name+': ')).appendTo($('#messagesDiv'));
$('#messagesDiv')[0].scrollTop = $('#messagesDiv')[0].scrollHeight;
}
};
This is the CSS I added to the head.
<style type="text/css">
.current_user {
background-color:#24887F;
}
</style>
There are many users using the app concurrently. But for every user, there is only one current_user in session. Don't mix it up.
Since the message is to be processed by server, you can easily add a new attribute of message.klass in server side by judging the message comes from current_user. If it is, the class may be current, else blank or others.
Then, in JS
$('li').addClass('<%= message.klass %>')
Related
I spent time learning Rails and now I'm working on a demo project.The first thing I want the user to do, is to select whether or not they need immediate care on a care request _form. If the user selects "false" then the user will be asked to select a time and date from the next two hidden lines of code, passing in my start_time and start_date. If the user selects "true", I want to use Time.now to get the current time and current date for my start_time and start_date fields when the user clicks the submit button on the request _form. My question is What is the proper way to keep the last two fields hidden until a user selects "false"? requests_form.html.erb
<div class="row">
<div class="form-group">
<%= f.check_box :immediate_care,{:checked => "checked"} %> Patient needs immediate care.
</div
</div>
<div class="row">
<div class="form-group">
<label>Choose your start date.</label>
<%= f.text_field :start_day, placeholder: "MM/DD/YY", class: "form control" %>
</div>
</div>
<div class="row">
<div class="form-group">
<label>Choose your start time.</label>
<%= f.text_field :start_time, placeholder: "08:00 AM", class: " form-control" %>
</div>
</div>
Here is a drastically simplified solution. The basic idea is that you wrap the optionally displayed input fields inside a single div. You defined a couple CSS classes that will show and hide that div respectively. You bind a javascript function to the click event on that select that will add and remove the CSS classes to the optional div depending upon the select:option value.
The HTML:
<select id='my_select'>Do you want Immediate Care?
<option value='yes'>Yes</option>
<option value='no'>No</option>
</select>
<div class='reveal' id='date_fields'>
... in here you put the fields you want to hide and show ...
</div>
The Javascript:
$document.ready(function() {
$('#my_select').bind('click', function() {
selected_option = $('#my_select option:selected');
if $(selected_option).val() == 'yes' {
$('#date_fields').addClass('reveal');
$('#date_fields').removeClass('hide');
} else {
$('#date_fields').addClass('hide');
$('#date_fields').removeClass('reveal');
}
});
});
And finally, the CSS:
.reveal {
display: block;
}
.hide {
display: none;
}
I candidly admit that in places my syntax might be off. As a Rails developer I've opted to use Coffeescript and SASS so my Javascript and SASS syntax skills have atrophied a bit over the last 5 years. Please feel free to point out issues and/or edit fixes in.
A few caveats to this. Since divs display:block by default, you can use a single CSS class that changes that to display:none and have the click handler simply add and remove that one class. I made my example more explicit so it's easier to follow the logic.
Also, I may have bound the click incorrectly. Again, this example is just to show the general approach to the problem that I would take.
Add class for optional fields wrappers:
<div class="row optional">
Add this script:
<script>
$('#patient_immediate_care').change(function() {
if($(this).is(":checked")) {
$('.optional').hide();
}
else {
$('.optional').show();
}
}
);
$(function() {
if($('#name_immediate_care').is(":checked")) {
$('.optional').hide();
}
else {
$('.optional').show();
}
});
</script>
And css:
<style>
.optional {
display: none;
}
</style>
Check ids of yor form elements. It depends on form_for. patient is for example.
I'm struggling a bit with this : let's say I have a class in the body <body class="video page"> and in my page I have a pagination which add a number like this <body class="video-2 page"> at each page. I would like to target the class video whether or not it has a number in order to apply some jquery if the condition is filled.
How do I do that?
You can use this attribute selector to select elements that have a class attribute starting with video-:
[class^="video-"]
But for this to work, you’d have to make sure that the video- class is the first one in the element’s class attribute (see http://jsfiddle.net/Czyep/).
It might be better to have the video class and the pagination class be separate, e.g.:
<body class="video page-2 page">
I would split the classes like class="video two page" so that you can still address both classes separately. Nevertheless you can do something like
$('body[class*=video]')
$("body").not(".video");
Should select all bodies wich end with a number. You could also do:
if($("body").is("[class$='video-'")) {}
have you tried something like this this?
$('.video,.video-'+pageNumber).dosomething()
You can use the attribute starts with selector:
$("body[class^='video']");
Assuming I have understood your question correctly I would suggest that you use concatenation in your selector.
I assume that you are aware that you have specified two classes on your body tag namely video and page or video-2 and page. And I therefore assume that page is significant in your selection and should be included in your selector.
Therefore I would use this syntax whilst not as neat as some syntax it is very clear what is going on. Obviously you would need to incorporate this into what ever logic is driving your page selection.
var suffix = "";
$(".video" + suffix + ".page").dosomething(); // select <body class="video page">
suffix = "-2";
$(".video" + suffix + ".page").dosomething(); // select <body class="video-2 page">
Note that there should be no space between the classes in the selector because they have been declared in the same tag in the html.
Had you specified something like
<body class="video"> // body wrapper
<div class="page"> // page wrapper
</div>
</body>
Then a space would be required as you are then looking to match on div page within body with class video or video-2 as appropriate.
suffix = "-2";
$(".video" + suffix + " .page").dosomething(); // select <body class="video-2"><div class="page">
I have a chat window made using HTML, CSS & JS. I want to position the message from bottom to top.
Example:
first message div at the bottom, 2nd message div on top of first an so on. Is it possible?
I can't imagine a pure CSS solution. But Using jQuery, if you already have this library for your project, you could write something this:
$(':button').click(function() {
var message = $('input[type=text]').val();
$('#chat').prepend('<div class="line">'+message);
});
Demo: http://jsfiddle.net/Vbd67/1/
**I changed the append to prepend according to the comment
I know that this is not an answer to your question, rather this is a better option that you should consider implementing in the chat window.
Newest comment should be at the bottom, that is how most basic chat windows work.
Next thing, you can do this all using css:
because such a design requires either use of table rows or list elements
Obviously you have to use javascript for using ajax, so that you can asynchronously fetch user records like messages and profile pic etc
CSS:
<style type="text/css">
table#chat_window {
}
tr#message_row {
}
td#profile_pic {
}
td#message {
}
</style>
HTML STRUCTURE:
<table id="chat_window">
<tr id="message_row">
<td id="profile_pic"></td>
<td id="message"></td>
</tr>
</table>
OR USING LISTS:
<ul id="chat_window">
<li id="message_row">
<div id="profile_pic"></div>
<div id="message"></div>
</li>
</ul>
Now you have to just using javascript:ajax to fetch values and add a child:
If you are using table based chat-window, then you have to fetch the table id using javascript and add row element <tr> per value/message that you fetch.
If you are using list based chat-window, then you have to fetch the list id using javascript and add list element <li> per value/message that you fetch.
I am sorry if there are any typos I have less time.
You can do this using jQuery like;
var first = $('div > div:first-child');
first.appendTo(first.parent());
To deal with several elements, you can do this:
$('div > div').each(function() {
$(this).prependTo(this.parentNode);
});
Here is a working Live Demo.
You should use a combination of display:table-cell and vertical-align:bottom.
I use Sotiris's fiddle and fixed its CSS.
The HTML is
<div style="display:table; height:200px;">
<div style="display:table-row">
<div id="chat" style="width:400px; border:1px solid black;display:table-cell; vertical-align:bottom">
</div>
</div>
</div>
<input type="text"><input type="button" value="post">
And this is the JavaScript code
$(':button').click(function() {
var message = $('input[type=text]').val();
$('#chat').append( $('<div/>').text(message) );
});
Please let me know if there is a problem.
This is the fiddle
I kept searching for a better solution because table layout is always suspicious to me, but I found css-tricks article about it and they do the same as I do.. so I guess this solution is the right one.
ADDING - keep scroll to bottom code
Since new messages are coming at the bottom, we need to keep scroll to bottom.
I updated the fiddle link
I'm using a bit of javascript to fade in a couple of message bars at the top of my page - a bit like stackoverflow does :)
I have:
<div id='message' style="display: none;">
<span>Wow, that was quick! - below is a preview of your page.</span>
X
</div>
<div id='message' style="display: none;">
<span>Try posting something interesting</span>
X
</div>
CSS:
#message {height:30px;width:100%;z-index:105;text-align:center;color:white;padding:10px 0px 10px 0px;background-color:#8E1609;}
#message span {text-align: center;width: 95%;float:left;}
.close-notify {white-space: nowrap;float:right;margin-right:10px;color:#fff;text-decoration:none;border:2px #fff solid;padding-left:3px;padding-right:3px}
.close-notify a {color: #fff;}
and Javascript:
$(document).ready(function() {
$("#message").fadeIn("slow");
$("#message a.close-notify").click(function() {
$("#message").fadeOut("slow");
return false;
});
});
But unfortunately only the first message displays. How come? Surely the second one should show as well?
thanks
id attributes should be unique among all elements in the page. Change the HTML, CSS and JavaScript to use class="message" instead of id="message" and it will work fine.
Technically what happens here is that jQuery sees the #message selector and tries to find the element using document.getElementById (which is fastest). This function returns only one element, in this case the first one. So the second never has a chance to be processed.
You also have a bug: As the code stands now, hitting the "close" link will make all messages disappear. You need to tweak the click handler a bit to make it behave as expected.
See all of this in action here.
An ID should only be used once on the page. It is a unique identifier.
You'll want to use a class instead if you have multiple items.
Html
<div class="message">Some Message</div>
<div class="message">Some Other Message</div>
jQuery
$('.message').fadeIn('slow');
Here's a demo: http://jsfiddle.net/GBjxH/
Both of your elements have the same ID #message - an ID should be unique, so this should be a class instead.
You can't use an ID for two elements, try using a class!
<div class='message' style="display: none;">
$('.message').fadeIn();
It's because they both have the same id. The fadeIn is only being called for the first one. If you want to do it for both (or all) of them, apply a class and do something like
$(".classname").each(...
You can't have two identical ID's
You shouldn't have elements with the same 'id'.
ID's are unique! You cannot have 2 Elements with the same ID. Use Classes
You shouldn't have multiple items with the same id, use a class instead.
Is there a specific reason that most everyone implements edit-in-place as a shown 'display' div and a hidden 'edit' div that are toggled on and off when somebody clicks on the associated 'edit' button like so?
<div id="title">
<div class="display">
<h1>
My Title
</h1>
</div>
<div class="edit">
<input type="text" value="My Title" />
<span class="save_edit_button"></span>
Cancel
</div>
</div>
Everywhere I look, I see edit-in-place basically handled like this. This approach certainly makes sense when you are rendering all views on the server side and delivering them to the client. However, with pure AJAX apps and frameworks like backbone.js, it seems that we could make our code much more DRY by rendering edit-in-place form elements on the fly as necessary, possibly even making a factory method that determines which form element to render. e.g.
an H1 element with class "title" is replaced by <input type="text" />
a span with class "year_founded" is replaced by <input type="number" min="1900" max="2050" />
a span with class "price" is replaced by an input with the appropriate mask to only allow prices to be input.
Is this practice of rendering all edit-in-place form elements a historical legacy leftover from when pages were rendered on the server-side?
Given the flexibility and power we have with client-side MVC frameworks like Backbone.js, is there a reason for not creating and inserting the form elements on the fly when necessary using a factory method? Something like this:
HTML
<div id="description">
Lorem ipsum dolar set amit...
</div>
<span class="edit_button"></span>
Backbone.js View
events: {
"click .edit_button": "renderEditInPlaceForm",
},
renderEditInPlaceForm: function:(e) {
var el = $(e.currentTarget).previous();
var id = el.attr('id');
var value = el.text();
var tagName = el.tagName();
var view = new editInPlaceForm({
id: id,
type: tagName,
value: value
});
$("#id").html(view.render().el)
},
Where editInPlaceForm is a factory that returns the appropriate edit-in-place form element type based on tagName. This factory view also controls all its own logic for saving an edit, canceling an edit, making requests to the server and rerendering the appropriate original element that was replaced with the .html() function?
It seems to me that if we use this approach then we could also render the <span class="edit_button"></span> buttons on the fly based on a user's editing rights like so:
<h1 id="title">
<%= document.get("title") %>
</h1>
<% if (user.allowedToEdit( document, title )) { %>
<span class="edit_glyph"></span>
<% } %>
where the allowedToEdit function on the user model accepts a model and attribute as its arguments.
It's an interesting idea. The devil is in the detail.
While your simple example is easily rendered as an editable form on the fly, things quickly get trickier when dealing with other data types.
For example - suppose my edit form requires the user to choose a value from a select list. On the display form I can simply display the user's choice, but for the edit form I am going to need those other available choices. Where do I hide them on the display? Similar issues exist for checkboxes, radio lists...
So, perhaps we should consider rendering the edit form, and then deriving our display-view from that?
After 5 Backbone apps I came to same thoughts.
When things are complicated you have forms to show relations between user data,
but in simple cases you just need input, select, checkbox over h1, div or span
Now I am searching for jQuery plugin to make simple in place editing without ajax.
jQuery but not Backbone becuase I don't want to be tight coupled with Backbone for such small thing.
Likely to wright my own jQuery + Synapse plugin http://bruth.github.com/synapse/docs/.
Synapse for binding with model and jQuery for input placing