*this question has been updated.
I have a set of boxes which, when clicked open a div called #expander. In my code, after #expander is opened, and if another box is clicked, I check if the new box clicked is the same as the last box clicked. If it is the same, I close #expander, else I briefly close it and then open it again.
This is demonstrated with the this jsfiddle
Here is the same code, in stackoverflow:
$(document).on('click', '.box', function(e) {
if (!$('#expander').hasClass('active')) {
$('#expander').addClass('active');
$('.basic-info').css('border-left', '1px solid black');
activeBox = $(this).attr('id');
$('#main').text(activeBox);
console.log('activeBox = ' + activeBox);
return;
}
if ($('#expander').hasClass('active')) {
$('#expander').removeClass('active');
$('.basic-info').css('border-left', '0px solid black');
if ($(this).attr('id') !== activeBox) {
setTimeout(function() {
$('#expander').addClass('active');
}, 256);
}
activeBox = $(this).attr('id');
$('#main').text(activeBox);
console.log('activeBox = ' + activeBox);
return;
}
});
#expander{
height: 100%;
width: 0%;
float: left;
visibility: hidden;
overflow: hidden;
background-color: grey;
transition: .75s ease-out;
}
#expander.active{
height: 100%;
width: 50%;
z-index: 1;
visibility: visible;
}
#closer{
padding: 4px;
margin: 0px;
background-color: #707070;
color: white;
font-size: 1.5em;
text-align: center;
cursor: pointer;
}
#closer:hover{
background-color: #606060;
font-size: 2em;
padding: 0px;
}
.box{
width: 32px;
height: 32px;
padding: 5px 0px;
margin: 0px 4px;
display: inline-block;
background-color: grey;
overflow: hidden;
font-size: 1em;
font-weight: bold;
text-align: center;
border: 1px solid transparent;
border-radius: 2px;
cursor: pointer;
}
.basic-info{
padding: 8px 16px;
color: white;
background-color: #47a;
border-top: 1px solid black;
border-right: 1px solid black;
border-bottom: 1px solid black;
transition: .5s ease-out;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="expander">
<div id="closer" title="Close"><span>×</span></div>
<div id="main"></div>
</div>
<div class="basic-info">
<div id="box1" class="box">1</div>
<div id="box2" class="box">2</div>
<div id="box3" class="box">3</div>
</div>
The above code works (although it does not look exactly how it looks in my final layout) BUT what it does not do run this: $('.basic-info').css('border-left', '1px solid black'); after the first time a box is clicked (when it opens the #expander
I realize the reason this is not working is that the JS code first adds the classes and styles, but then the next if statement removes the classes and styles. Also, I have to paste the following code two times:
$('#main').text(activeBox);
console.log('activeBox = ' + activeBox);
return;
Does anyone know a better way to layout my if statements so that code does not conflict? Also, is there a way to not need to use return;s?
P.S. does anyone have a link to a good if statement tricks tutorial so that I can learn these things for the future?
Thank you.
UPDATE:
I have updated the code based on the current answers and have changed the JS to this:
$(document).on('click', '.box', function(e) {
if ($('#expander').hasClass('active')) {
$('#expander').removeClass('active');
if ($(this).attr('id') !== activeBox) {
setTimeout(function() {
$('#expander').addClass('active');
}, 256);
activeBox = $(this).attr('id');
console.log('activeBox = ' + activeBox);
return;
}
$('.basic-info').css('border-left', '0px solid white');
return;
}
$('#expander').addClass('active');
$('.basic-info').css('border-left', '1px solid white');
activeBox = $(this).attr('id');
console.log('activeBox = ' + activeBox);
}
(it does the same thing, just laid out differently). All I am trying to figure out now is just how I can write this without any of the return;s and also so I do not have to write activeBox = $(this).attr('id'); console.log('activeBox = ' + activeBox); twice (unless these things are impossible/unavoidable)
thank you.
for the clean up part and get rid of repeated data, you can convert your js code to this
Updated
jsFiddle
// target the #expander
var Expander = $('#expander'),
activeBox = '';
$(document).on('click', '.box', function(e) {
//toggleClass means if #expander hasClass, remove it, if it
//doesn't have the class, add it.
Expander.toggleClass('active');
// same for .basic info, we use toggle class, instead of
// CSS hardcoded, thus we can toggle
$('.basic-info').toggleClass('black-border-left');
if ($(this).attr('id') !== activeBox) {
Expander.removeClass('active');
// to get rid of the delay for when one .box div is clicked for the first time
// when activeBox = ''.
if(activeBox !== ''){
setTimeout(function() {
Expander.addClass('active');
}, 500);
}else{
Expander.addClass('active');
}
activeBox = $(this).attr('id');
}
$('#main').text(activeBox);
console.log('activeBox = ' + activeBox);
});
$(document).on('click', '.box', function(e) {
if (!$('#expander').hasClass('active')) {
$('#expander').addClass('active');
$('.basic-info').css('border-left', '1px solid black');
activeBox = $(this).attr('id');
$('#main').text(activeBox);
console.log('activeBox = ' + activeBox);
} else if ($('#expander').hasClass('active')) {
$('#expander').removeClass('active');
$('.basic-info').css('border-left', '0px solid black');
if ($(this).attr('id') !== activeBox) {
setTimeout(function() {
$('#expander').addClass('active');
}, 256);
}
activeBox = $(this).attr('id');
$('#main').text(activeBox);
console.log('activeBox = ' + activeBox);
}
});
Related
I am in the process of building a quiz sort of game using JQuery. My game works how I wish it to currently, but only for the first question.
var progress = 0;
var score = 0;
var running = true;
var questions = [
{question: 'Which character is played by Robert Downey Junior?', answers: ['Thor', 'Iron Man', 'Captain America', 'Star Lord'], correct: 'Iron Man'},
{question: 'What colour is the star on Captain Americas shield?', answers: ['Red', 'Silver/Grey', 'Blue', 'Yellow/Gold'], correct: 'Silver/Grey'}
];
var $quiz = $('.quiz');
var $question = $('#quiz-question');
var $answers = $('#answers');
var $next = $('#next');
var $results = $('#results');
var showQuestion = q => {
if (progress < questions.length) {
$question.html(q.question);
$answers.html(' ');
q.answers.forEach(function(ans) {
$answers.append("<div class='answer'>" + ans + "</div>");
})
} else {
$results.html("<h2>Your Results:</h2><p>You scored " + score + "/" + questions.length + "</p>");
$quiz.hide();
$results.show();
}
};
showQuestion(questions[progress]);
$(document).ready(function(){
$next.hide();
$results.hide();
$('.answer').on('click', function(){
if($(this).html() === questions[progress].correct && running) {
progress++;
running = false;
score++;
$(this).css('color', 'green');
$(this).css('border', '3px solid green');
$(this).css('font-weight', 'bold');
$next.show();
} else if ($(this).html() !== questions[progress] && running) {
$(this).css('color', 'red');
$(this).css('border', '3px solid red');
$(this).css('font-weight', 'bold');
progress++;
running = false;
$next.show();
}
})
$next.on('click', function() {
running = true;
showQuestion(questions[progress]);
})
})
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
background-color: #c7ecee;
font-family: 'Karla', sans-serif;
}
main {
min-height: 500px;
width: 100%;
display: flex;
align-items: flex-end;
}
main .quiz {
width: 40%;
margin: 0 auto;
text-align: center;
}
main .quiz #quiz-question {
font-size: 2rem;
width: 100%;
border: 2px solid #4d4d4d;
color: #fff;
background-color: #4d4d4d;
padding: 1rem;
}
main .quiz #answers {
font-size: 1.5rem;
border: 1px solid #4d4d4d;
}
main .quiz #answers .answer {
width: 100%;
padding: 1rem;
background-color: #fff;
border: 1px solid #4d4d4d;
cursor: pointer;
}
main .quiz #answers .answer:hover {
}
div#ui {
text-align: center;
width: 100%;
padding: .75rem;
}
div#ui button {
font-size: 1.75rem;
padding: .75rem;
background-color: #4d4d4d;
border: 1px solid #4d4d4d;
color: #fff;
cursor: pointer;
}
<main>
<div class='quiz'>
<div id='quiz-question'>
</div>
<div id='answers'>
</div>
</div>
<div id='results'>
</div>
</main>
<div id='ui'>
<button id='next'>Next</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Basically, a question and its answers are displayed, when an answer is clicked it stops running the game, so that no other answers can be clicked (or an answer can't be clicked more than once to boost score). When the question is answered, a button appears at the bottom to go to the next question. If there are no more questions, it shows you the results display.
This works exactly how I wish - for one question. When I add any further questions, it displays the question exactly as it should, but the on click effects are no longer applied. I assume this is to do with the elements not existing when the $(document).ready() function is called. Could anyone shed any light on how I could solve this problem?
Edited to include code snippet. Uncomment the second quest
On line 37, change:
$('.answer').on('click', function(){
to
$('body').on('click', '.answer', function(){
The thing is, when you write:
$(document).ready(function(){
$next.hide();
$results.hide();
$('.answer').on('click', function(){
You target all elements (at current moment) that have the class .answer. Since this is only the first question (in the beginning) it won't work at the questions after the first one.
If you instead write:
$(document).ready(function(){
$next.hide();
$results.hide();
$('body').on('click', '.answer', function(){
You tell jQuery to add the click-event to any current and new elements that will be added with the class .answer (within the body-element). It better to keep this specific, for example with an id for the quiz.
Se the whole example:
var progress = 0;
var score = 0;
var running = true;
var questions = [
{question: 'Which character is played by Robert Downey Junior?', answers: ['Thor', 'Iron Man', 'Captain America', 'Star Lord'], correct: 'Iron Man'},
{question: 'What colour is the star on Captain Americas shield?', answers: ['Red', 'Silver/Grey', 'Blue', 'Yellow/Gold'], correct: 'Silver/Grey'}
];
var $quiz = $('.quiz');
var $question = $('#quiz-question');
var $answers = $('#answers');
var $next = $('#next');
var $results = $('#results');
var showQuestion = q => {
if (progress < questions.length) {
$question.html(q.question);
$answers.html(' ');
q.answers.forEach(function(ans) {
$answers.append("<div class='answer'>" + ans + "</div>");
})
} else {
$results.html("<h2>Your Results:</h2><p>You scored " + score + "/" + questions.length + "</p>");
$quiz.hide();
$results.show();
}
};
showQuestion(questions[progress]);
$(document).ready(function(){
$next.hide();
$results.hide();
$('body').on('click', '.answer', function(){
if($(this).html() === questions[progress].correct && running) {
progress++;
running = false;
score++;
$(this).css('color', 'green');
$(this).css('border', '3px solid green');
$(this).css('font-weight', 'bold');
$next.show();
} else if ($(this).html() !== questions[progress] && running) {
$(this).css('color', 'red');
$(this).css('border', '3px solid red');
$(this).css('font-weight', 'bold');
progress++;
running = false;
$next.show();
}
})
$next.on('click', function() {
running = true;
showQuestion(questions[progress]);
})
})
<body>
<main>
<div class='quiz'>
<div id='quiz-question'>
</div>
<div id='answers'>
</div>
</div>
<div id='results'>
</div>
</main>
<div id='ui'>
<button id='next'>Next</button>
</div>
<script src='https://code.jquery.com/jquery-3.2.1.min.js' integrity='sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=' crossorigin='anonymous'></script>
<script src='includes/js/main.js'></script>
</body>
Here is a minimal edit to get your code working:
var progress = 0;
var score = 0;
var running = true;
var questions = [
{question: 'Which character is played by Robert Downey Junior?', answers: ['Thor', 'Iron Man', 'Captain America', 'Star Lord'], correct: 'Iron Man'},
{question: 'What colour is the star on Captain Americas shield?', answers: ['Red', 'Silver/Grey', 'Blue', 'Yellow/Gold'], correct: 'Silver/Grey'}
];
var $quiz = $('.quiz');
var $question = $('#quiz-question');
var $answers = $('#answers');
var $next = $('#next');
var $results = $('#results');
var showQuestion = q => {
if (progress < questions.length) {
$question.html(q.question);
$answers.html(' ');
q.answers.forEach(function(ans) {
$answers.append("<div class='answer'>" + ans + "</div>");
})
$('.answer').on('click', function(){
if($(this).html() === questions[progress].correct && running) {
progress++;
running = false;
score++;
$(this).css('color', 'green');
$(this).css('border', '3px solid green');
$(this).css('font-weight', 'bold');
$next.show();
} else if ($(this).html() !== questions[progress] && running) {
$(this).css('color', 'red');
$(this).css('border', '3px solid red');
$(this).css('font-weight', 'bold');
progress++;
running = false;
$next.show();
}
})
} else {
$results.html("<h2>Your Results:</h2><p>You scored " + score + "/" + questions.length + "</p>");
$quiz.hide();
$results.show();
}
};
showQuestion(questions[progress]);
$(document).ready(function(){
$next.hide();
$results.hide();
$next.on('click', function() {
running = true;
showQuestion(questions[progress]);
})
})
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
background-color: #c7ecee;
font-family: 'Karla', sans-serif;
}
main {
min-height: 500px;
width: 100%;
display: flex;
align-items: flex-end;
}
main .quiz {
width: 40%;
margin: 0 auto;
text-align: center;
}
main .quiz #quiz-question {
font-size: 2rem;
width: 100%;
border: 2px solid #4d4d4d;
color: #fff;
background-color: #4d4d4d;
padding: 1rem;
}
main .quiz #answers {
font-size: 1.5rem;
border: 1px solid #4d4d4d;
}
main .quiz #answers .answer {
width: 100%;
padding: 1rem;
background-color: #fff;
border: 1px solid #4d4d4d;
cursor: pointer;
}
main .quiz #answers .answer:hover {
}
div#ui {
text-align: center;
width: 100%;
padding: .75rem;
}
div#ui button {
font-size: 1.75rem;
padding: .75rem;
background-color: #4d4d4d;
border: 1px solid #4d4d4d;
color: #fff;
cursor: pointer;
}
<main>
<div class='quiz'>
<div id='quiz-question'>
</div>
<div id='answers'>
</div>
</div>
<div id='results'>
</div>
</main>
<div id='ui'>
<button id='next'>Next</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Basically, you were attaching an event listener to .answer elements once, then replacing those elements, which means when a user clicks the new ones, nothing happens. Here, we add the listeners every time a question is created.
Keep in mind, there are ways you can refactor this code. I would look into event delegation if you want to avoid creating listeners for every .answer element.
I've decided to try and make a Notes program as a learning experience. The point was to problem-solve on my own, but I'm pretty clueless as to why this won't work.
When I Shift + Double Click a note to rename it the note changes from a <div> to <input>, but the CSS stays the same. When I press enter (which submits the input) the changes back to <div>, and the CSS is there, but it is very small and doesn't take the shape of the text. Any idea why? Thanks!
Code:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<button class="newList" onclick="newNote()">Create a new note</button>
<br></br>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script>
function clickNote(){
if(event.shiftKey){
$( "div" ).click(function() {
$( this ).replaceWith( "<tr><td><form'><input class='rename' placeholder='Type here' onkeydown='enter(event)' id='newListName' autofocus>" + "</input></form></td></tr>" );
});
} else {
location.href='list.html';
}
}
function enter(event){
var enter = event.which;
if (enter == 13){
var input = document.getElementById("newListName");
$( "input" ).keyup(function() {
$( this ).replaceWith( "<tr><td><div class='list' id='list' onclick='clickNote()'>" + input.value + "</div></td></tr>" );
});
}
}
function newNote(){
var newNt = document.createElement("DIV");
var text = "Rename with Shift + Double Click"
newNt.textContent = text;
newNt.setAttribute('class', 'list');
newNt.setAttribute('id', 'list');
newNt.setAttribute("onclick", "clickNote()");
document.body.appendChild(newNt);
}
</script>
</body>
</html>
CSS:
:root {
--main-color: #FFE033;
--secondary-color: #FEC82A;
}
.newList {
height: inherit;
width: 10%;
padding: .4%;
position: relative;
border-bottom: 4px solid var(--secondary-color);
background: var(--main-color);
}
.list {
height: inherit;
width: 10%;
padding: .4%;
position: relative;
border-bottom: 4px solid var(--secondary-color);
background: var(--main-color);
}
.rename {
height: 2.5em;
width: 116%;
padding: .4%;
position: relative;
border-bottom: 4px solid var(--secondary-color);
background: var(--main-color);
}
#list {
cursor: pointer;
}
Am not sure why you are doing this, but you are adding td tr around the div which make it insde a table and create this issue as the width is defined with 10%. Remove it and it should work fine. You need also to correct the input tag.
function clickNote() {
if (event.shiftKey) {
$("div").click(function() {
$(this).replaceWith("<input class='rename' placeholder='Type here' onkeydown='enter(event)' id='newListName' autofocus>");
});
} else {
location.href = 'list.html';
}
}
function enter(event) {
var enter = event.which;
if (enter == 13) {
var input = document.getElementById("newListName");
$("input").keyup(function() {
$(this).replaceWith("<div class='list' id='list' onclick='clickNote()'>" + input.value + "</div>");
});
}
}
function newNote() {
var newNt = document.createElement("DIV");
var text = "Rename with Shift + Double Click"
newNt.textContent = text;
newNt.setAttribute('class', 'list');
newNt.setAttribute('id', 'list');
newNt.setAttribute("onclick", "clickNote()");
document.body.appendChild(newNt);
}
:root {
--main-color: #FFE033;
--secondary-color: #FEC82A;
}
.newList {
height: inherit;
width: 10%;
padding: .4%;
position: relative;
border-bottom: 4px solid var(--secondary-color);
background: var(--main-color);
}
.list {
height: inherit;
width: 10%;
padding: .4%;
position: relative;
border-bottom: 4px solid var(--secondary-color);
background: var(--main-color);
}
.rename {
height: 2.5em;
width: 100%;
padding: .4%;
position: relative;
border-bottom: 4px solid var(--secondary-color);
background: var(--main-color);
}
#list {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="newList" onclick="newNote()">Create a new note</button>
I'm trying to animate a button with two states: saved and unsave. When it goes from save -> unsave, it should slowly expand and add the next text. It should do the reverse when going from unsave to save. I have the following fiddle:
https://jsfiddle.net/4x0svuLd/2/
My problem right now is that even though I have designated a width transition, it seems to ignoring it. My issue is this button could have arbitrary text, thats just boolean in nature, so I can't know the exact width beforehand. I just need to it animate to the proper text width, whatever that text is.
HTML:
<div class="button" >
<text class="text"> Save </text>
</div>
CSS:
.button {
background-color: transparent;
border: 1px solid;
border-color: black;
border-radius: 6px;
color: black;
cursor: pointer;
display: inline-block;
font-size: 14px;
margin-top: 8px;
outline-style: none;
padding: 6px 10px;
text-align: center;
transition: width 2s cubic-bezier(0.23, 1, 0.32, 1);
width: auto;
}
.button-depressed {
color: white;
background-color: #ADD8E6;
border-color: transparent;
}
JS:
var isSaved = false
function doSaveAnimation() {
var button = document.getElementsByClassName("button")[0];
button.classList.add("button-depressed");
setTimeout(function() {
button.innerHTML = "Unsave";
}, 80);
}
function doUnsaveAnimation() {
var button = document.getElementsByClassName("button")[0];
button.classList.remove("button-depressed");
setTimeout(function() {
button.innerHTML = "Save";
}, 80);
}
function animate(){
if (isSaved) {
doUnsaveAnimation();
} else {
doSaveAnimation();
}
isSaved = !isSaved;
}
document.getElementsByClassName("button")[0].addEventListener("click", animate);
You could calculate the width of the text that you are setting to the button, and set calculated width to the button accordingly;
Once right away, and then each click.
you could also set the transition to everything, not just the width of the button - for smoother animation.
In this post you have several examples of how to determine width of text, i have adapted one of those to the solution below:
var isSaved = false;
var button = document.getElementsByClassName("button")[0];
button.style.width = getWidthOfText("Save", "14","sans-serif") +20+ "px";
function getWidthOfText(txt, fontsize) {
var c = document.createElement('canvas');
var ctx = c.getContext('2d');
ctx.font = fontsize + 'px' ;
var length = ctx.measureText(txt).width;
return length;
}
function doSaveAnimation() {
button.classList.add("button-depressed");
setTimeout(function() {
button.innerHTML = "Unsave";
console.log(button.offsetWidth);
}, 120);
button.style.width = getWidthOfText("Unsave", "14") +20+ "px";
}
function doUnsaveAnimation() {
button.classList.remove("button-depressed");
setTimeout(function() {
button.innerHTML = "Save";
console.log(button.offsetWidth);
}, 120);
button.style.width = getWidthOfText("Save", "14") +20+ "px";
}
function animate() {
if (isSaved) {
doUnsaveAnimation();
} else {
doSaveAnimation();
}
isSaved = !isSaved;
}
document.getElementsByClassName("button")[0].addEventListener("click", animate);
.button {
background-color: transparent;
border: 1px solid;
border-color: black;
border-radius: 6px;
color: black;
cursor: pointer;
display: inline-block;
font-size: 14px;
margin-top: 8px;
outline-style: none;
padding: 6px 10px;
text-align: center;
transition: 1s cubic-bezier(0.23, 1, 0.32, 1);
text-align:center;
}
.button-depressed {
color: white;
background-color: #ADD8E6;
border-color: transparent;
transition: 1s cubic-bezier(0.23, 1, 0.32, 1);
}
<div class="button">
<text class="text">Save</text>
</div>
One way to do this without javascript is to use max-width instead of width.
https://jsfiddle.net/LjchoLqt/
.button {
transition: max-width 2s cubic-bezier(0.23, 1, 0.32, 1);
width: auto;
max-width: 2em;
}
.button-depressed {
max-width:4em;
}
You'll need to pay around with the values to make sure it doesn't cut off. This isnt an ideal solution though, especially if you don't control the content (eg it's populated by a CMS)
I have this popup window and I want to make it draggable. I searched everywhere for a solution but I couldn't find one that worked for me. I was wondering if someone can help me out? Here's my code:
<script>
$(document).ready(function() {
//
$('a.poplight[href^=#]').click(function() {
var popID = $(this).attr('rel'); //Get Popup Name
var popURL = $(this).attr('href'); //Get Popup href to define size
var query = popURL.split('?');
var dim = query[1].split('&');
var popWidth = dim[0].split('=')[1]; //Gets the first query string value
$('#' + popID).fadeIn().css({
'width': Number(popWidth)
}).prepend('');
var popMargTop = ($('#' + popID).height() + 80) / 2;
var popMargLeft = ($('#' + popID).width() + 80) / 2;
//Apply Margin to Popup
$('#' + popID).css({
'margin-top': -popMargTop,
'margin-left': -popMargLeft
});
$('body').append('<div id="fade"></div>');
$('#fade').css({
'filter': 'alpha(opacity=80)'
}).fadeIn(); //Fade in the fade layer - .css({'filter' : 'alpha(opacity=80)'})
return false;
});
$('a.close, #fade').live('click', function() {
$('#fade , .popup_block').fadeOut(function() {
$('#fade, a.close').remove(); //fade them both out
});
return false;
});
});
</script>
CSS:
#fade {
display: none;
background: transparent;
position: fixed; left: 0; top: 0;
width: 100%; height: 100%;
opacity: .80;
z-index: 9999;
}
.popup_block{
color: #000;
display: none;
padding: 3px;
background: #c0c0c0;
border-top: 2px solid #fff;
border-left: 2px solid #fff;
border-right: 2px solid #000;
border-bottom: 2px solid #000;
float: left;
font-family: arial;
font-size: 12px;
position: fixed;
top: 55%; left: 50%;
z-index: 99999;
}
img.btn_close {
float: right;
margin: -20 -20px 0 0;
}
*html #fade {
position: absolute;
}
*html .popup_block {
position: absolute;
}
If you ever have the need to see it here's the link. Start --> Message
As the jQuery UI library is already loaded, the following code will make your popup block draggable:
<script>
$(document).ready(function() {
$('.popup_block').draggable();
// ...
// your code
}
</script>
See the documentation of the jQuery UI draggable widget for more information about available options: http://api.jqueryui.com/draggable/
jQuery UI also offers demonstrations of several use cases: https://jqueryui.com/draggable/
First of all I am not very good in designing but with some help I am able to acheive this code
My main issue is that when a user opens a div it becomes the target div, so if I have five divs open at the same time it doesn't matter which I type in because the text gets appended to the last opened div. I can also open an unlimited amount of the same div, which should not happen.
The small issue I have is that I'm unable to close the div and minimize it(much like fb when we click on the chat box it gets minimized).
Fiddle
HTML
<div id="contact">
<header>Users</header>
<main>
<ul>
<li id="Prashant">Prashant</li>
<li id="Katrina">Katrina</li>
<li id="Priyanka">Priyanka</li>
<li id="Kareena">Kareena</li>
<li id="Anushka">Anushka</li>
</ul>
</main>
</div>
<div id="chat"></div>
CSS
* {
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
}
body{margin:0;padding:0;}
#contact {
height: auto;
background: #ececec;
position:absolute;
right:0;
bottom:0;
width:100px;
}
#contact header {
padding: 10px;
background: #333;
color: #FFF;
}
#contact main {
padding: 10px
}
#chat {
position: fixed;
bottom: 0;
left: 0;
right: 100px;
height: auto;
}
#chat .user {
border: 1px solid #333;
background: #fff;
width: 200px;
height: 100%;
float: left;
margin-right: 5px;
}
.user header {
position: relative;
background: #4b67a8;
border: 1px solid #2e4588;
}
.user header .status {
position: absolute;
top: 36%;
left: 10px;
width: 8px;
height: 8px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
background: green;
}
.user header .header-text {
color: #fff;
font-weight: bold;
padding: 8px;
margin: 0 0 0 15px;
font-size: 12px;
text-shadow: 0 -1px rgba(0, 0, 0, .25);
}
.user header .close {
position: absolute;
right: 5px;
top: 7px;
color: #fff;
}
.message-area {
background: #fff;
height: 120px;
padding: 5px;
color: #333;
overflow: scroll;
}
.user .input-area {
border-top: 1px solid #333;
padding: 3px;
}
.user .input-area input {
padding: 5px;
width: 100%;
font-size: 12px;
border: none;
outline: none;
}
Javascript
var username = 'user201';
$(document).ready(function() {
$('a').click(function(e) {
e.preventDefault();
var targetUser = ($(this).html());
$(document).data('chat.targetUser', targetUser);
var user = '<div class="user open" id="' + targetUser + '"><header><div class="status"></div><div class="header-text">' + targetUser + '</div><div class="close">×</div></header><div class="message-area"></div><div class="input-area"><input type="text" id="input" /></div></div>';
$('#chat').append(user);
});
$('#chat').on('keydown', '#input', function(event) {
if (event.keyCode == 13) {
var targetUser = $(document).data('chat.targetUser');
var txt = $(this).val();
$('#' + targetUser + ' .message-area').append(username + ': ' + txt + '<br/>');
$(this).val('');
}
});
});
I edited div.close and added a div.mini like
<div class="mini" title="MINIMIZE">-</div>
<div class="close" title="CLOSE">×</div>
Css for .mini
.user header .mini {
position: absolute;
right: 25px;
top: 7px;
color: #fff;
cursor:pointer;
}
JS code for them to work
$(document).on("click", "div.close", function(){
$(this).parent().parent().remove();
});
$(document).on("click", "div.mini", function(){
var elem = $(this).parent().parent().children().not("header");
elem.slideToggle();
});
Also added this js code to prevent add the div if it's already opened and make it append to last section of chat
if ($("div#" + targetUser).length > 0) {
$("div#" + targetUser).appendTo("#chat");
return false;
}
FIDDLE
EDIT
Edited div.mini click function for -/+ Minimize/Maximize
$(document).on("click", "div.mini", function(){
var elem = $(this).parent().parent().children().not("header");
elem.slideToggle();
$(this).text($(this).text() == "-" ? "+" : "-");
$(this).attr("title", $(this).attr("title") == "MINIMIZE" ? "MAXIMIZE" : "MINIMIZE");
});
UPDATED FIDDLE
The text you enter will appear in the last opened div because your var targetUser is changed every time you click on one of the users. The best way to solve this I think is to find the parent of the input field and search for the previous .message-area.
Like this:
$('#chat').on('keydown', '#input', function(event) {
if (event.keyCode == 13) {
var txt = $(this).val();
$(this).parent().prev(".message-area").append(username + ': ' + txt + '<br/>');
$(this).val('');
}
});
Working JSFiddle
Here is the fix for your code:
http://jsfiddle.net/afzaal_ahmad_zeeshan/36pcu/14/
I have updated the code in your fiddle, and I have added a fix so that the divs don't open up twice.
I just added a class to the link of the user, to show that this user is now active. Here is the code
if($(this).attr('class') != 'active') {
var targetUser = ($(this).html());
$(document).data('chat.targetUser', targetUser);
var user = '<div class="user open" id="' + targetUser + '"><header><div class="status"></div><div class="header-text">' + targetUser + '</div><div class="close">×</div></header><div class="message-area"></div><div class="input-area"><input type="text" id="input" /></div></div>';
$('#chat').append(user);
}
$(this).attr('class', 'active');
Then the div thing was handled using this code:
if (event.keyCode == 13) {
var txt = $(this).val();
$(this).parent().prev(".message-area").append(username + ': ' + txt + '<br/>');
$(this).val('');
}
This was the fix for your code, now it works.
According to your statement "...Also I am able to open an unlimited amount of the same divs, which should not happen**..." this can be prevented if you know what are the boxes opened
please check the Fiddle
var id = '#Box' + targetUser;
var existent = $('#chat').find(id)[0];
// This will ensure that you can only open one box at each time
if(existent != null){
alert('There is already one chat to user "' + targetUser + '" open');
}
else
{
your code...
}
Also the fix proposed by speetje33 helps you prevent to write always in the last box.
I've added some comments to the code for your better understanding.