In my Meteor project, I have two buttons. One button is an upvote button, which adds a point to the score of an entry, while the other is a downvote button, which does the opposite. My site doesn't require login.
How can I restrict it so that any given device can only click either the upvote or downvote button initially, and then if that device decides to change it's vote, it should be able to click only the other button, and so on?
You can use HTML 5 LocalStorage. But it will only work on latest browsers. If you want suppoert for old browsers as well then you might be interested in this question as well. If your user base doesn't use very old browsers then you can do it with LocalStorage like this,
In template's created callback,
Template.yourTemplate.created = function () {
var template = this;
var userVote = null;
if(typeof(Storage) !== "undefined") {
userVote = localStorage.getItem("userVote");
}
template.userVote = new ReactiveVar(userVote); //or you can use Session.setDefault("userVote", userVote)
}
When user clicks on the up or down button
Template.yourTemplate.events({
'click #upButton': function (ev, template) {
localStorage.setItem("userVote", "up");
template.userVote.set("up"); // or Session.set("userVote", "up");
},
'click #downButton': function (ev, template) {
localStorage.setItem("userVote", "down");
template.userVote.set("down"); // or Session.set("userVote", "down");
}
});
Then to disable buttons, you can do something like this in your helpers,
Template.yourTemplate.helpers({
'isUpButtonDisabled': function () {
var template = Template.instance();
var userVote = template.userVote.get(); // or Session.get("userVote");
return userVote === "up";
},
'isDownButtonDisabled': function (ev, template) {
var template = Template.instance();
var userVote = template.userVote.get(); // or Session.get("userVote");
return userVote === "down";
}
});
Update: This answer uses localStorage so that the application can keep track of the user's vote even when user visits the same site at a later date, which was what OP was trying to do, since user can vote without a login.
EDIT: Based on your comment to have different votes for different templates/topics. Assuming you have current topic's id in template's current data. You can do something like this,
In template's created callback,
Template.yourTemplate.created = function () {
var template = this;
template.userVote = new ReactiveVar(null); //or you can use Session.setDefault("userVote", null)
template.autorun(function () {
var data = Template.currentData();
var topicId = data.topicId;
var userVote = null;
if(typeof(Storage) !== "undefined") {
userVote = localStorage.getItem("userVote" + topicId);
}
template.userVote.set(userVote); //or you can use Session.set("userVote", userVote);
});
}
When user clicks on the up or down button
Template.yourTemplate.events({
'click #upButton': function (ev, template) {
var topicId = this.topicId;
localStorage.setItem("userVote" + topicId, "up");
template.userVote.set("up"); // or Session.set("userVote", "up");
},
'click #downButton': function (ev, template) {
var topicId = this.topicId;
localStorage.setItem("userVote" + topicId, "down");
template.userVote.set("down"); // or Session.set("userVote", "down");
}
});
Then to disable buttons, you can do something like this in your helpers,
Template.yourTemplate.helpers({
'isUpButtonDisabled': function () {
var template = Template.instance();
var userVote = template.userVote.get(); // or Session.get("userVote");
return userVote === "up";
},
'isDownButtonDisabled': function (ev, template) {
var template = Template.instance();
var userVote = template.userVote.get(); // or Session.get("userVote");
return userVote === "down";
}
});
It sounds like a regular old radio button should do the trick.
I made some fancier stuff as well, see this CodePen.
Update
Added #4castle's rescind vote function. Nice touch.
Update 2
Per OP's request, the radio buttons are now the arrows.
CodePen 2
html,
body {
box-sizing: border-box;
background: #111;
color: #DDD;
font: 400 16px/1.4'Verdana';
height: 100vh;
width: 100vw;
}
*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
border: 0 none hlsa(0%, 0, 0, 0);
outline: 0 none hlsa(0%, 0, 0, 0);
}
fieldset {
margin: 0 1em 1em 1em;
padding: 8px;
border-radius: 9px;
border: 3px double #FF8;
width: 100%;
max-width: 19em;
}
legend {
font: small-caps 700 1.5rem/2"Palatino Linotype";
color: #FD1;
}
/* RadZ */
#radz input.chkrad {
display: none;
}
#radz input.chkrad + label {
color: #EEE;
background: transparent;
font-size: 16px;
}
#radz input.chkrad:checked + label {
color: #0ff;
background: transparent;
font-size: 16px;
}
#radz input.chkrad + label span {
display: inline-block;
width: 18px;
height: 18px;
margin: -1px 15px 0 0;
vertical-align: baseline;
cursor: pointer;
}
#radz input + label span {
background: transparent;
line-height: 100%;
}
input.A + label span:before {
content: '△';
color: #0ff;
font-style: normal;
font-weight: 700;
font-size: 24px;
}
input.A:checked + label span:before {
padding: -5px 15px 5px;
font-size: 16px;
}
input.A:checked + label span:before {
content: '▲';
color: #0ff;
font-style: normal;
font-weight: 700;
font-size: 24px;
}
input.B + label span:before {
content: '▽';
color: #0ff;
font-style: normal;
font-weight: 700;
font-size: 24px;
}
input.B:checked + label span {
padding: -5px 15px 5px;
font-size: 16px;
}
input.B:checked + label span:before {
content: '▼';
color: #0ff;
font-style: normal;
font-weight: 700;
font-size: 24px;
}
input.fade + label span,
input.fade:checked + label span {
-webkit-transition: background 0.7s linear;
-moz-transition: background 0.7s linear;
transition: background 0.7s linear;
}
<fieldset id="radz" name="radz">
<legend>Vote</legend>
<input type='radio' name='rad' id="rad1" class="chkrad A fade" value='1' />
<label for="rad1"><span></span>Up</label>
<br/>
<input type='radio' name='rad' id="rad2" class="chkrad B fade" value='2' />
<label for="rad2"><span></span>Down</label>
<br/>
</fieldset>
// Rescind vote function provided by 4castle
// http://stackoverflow.com/users/5743988/4castle
var selectedRad;
var voteRads = document.querySelectorAll('input[name="vote"]');
for (var i = 0; i < voteRads.length; i++) {
voteRads[i].onclick = function() {
if (selectedRad == this) {
this.checked = false;
selectedRad = null;
} else {
selectedRad = this;
}
};
}
.rad1 + label:after {
content: '△';
}
.rad1:checked + label:after {
content: '▲';
}
.rad2 + label:after {
content: '▽';
}
.rad2:checked + label:after {
content: '▼';
}
<input id="up" type="radio" class="rad1" name="vote">
<label for="up"></label>
<br/>
<label>Vote</label>
<br/>
<input id="down" type="radio" class="rad2" name="vote">
<label for="down"></label>
Related
I have to lists and am using a jquery function to move items from one list (id="columns")to the other (id="columns1") when I click on the items in the first list (id="columns").
That part of it works fine, but when I add a new item in the first list (id="columns"), the previously moved items show up in the first list (id="columns").
Is there a way to prevent the moved items to show up in the first list? Is there a way to do it with vanilla js or do I need to use jquery?
This is all part of an to do list app I am creating where you could add tasks, remove them, click on the task to consider it a finished task, etc.
// Create a "close" button and append it to each list item
var myNodelist = document.getElementsByTagName("LI");
var i;
for (i = 0; i < myNodelist.length; i++) {
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
myNodelist[i].appendChild(span);
}
// Click on a close button to hide the current list item
function closeEvent() {
var close = document.getElementsByClassName("close");
for (var i = 0; i < close.length; i++) {
close[i].onclick = function () {
var div = this.parentElement;
div.style.display = "none";
renderGraph();
}
}
}
// Add a "checked" symbol when clicking on a list item
var list = document.querySelector('ul');
list.addEventListener('click', function (ev) {
if (ev.target.tagName !== 'LI') return;
ev.target.classList.toggle('checked');
renderGraph();
}, false);
// Create a new list item when clicking on the "Add" button
function newElement() {
var li = document.createElement("li");
li.className = "column";
li.draggable = "true";
// order according to time
li.setAttribute("data-time", document.getElementById("myInput1").value);
// order according to time
var inputValue = document.getElementById("myInput").value;
var inputValue1 = document.getElementById("myInput1").value;
var tine = document.getElementById("myInput1");
tine.dateTime = "6:00"
// inputValue2.datetime = "6:00";
var tt = document.createTextNode(inputValue1 + " - ");
li.appendChild(tt);
var t = document.createTextNode(inputValue);
li.appendChild(t);
if (inputValue === '') {
alert("You must write a task!");
} else {
document.getElementById("columns").appendChild(li);
// order according to time start
setTimeout(function () {
var sortItems = document.querySelectorAll("[data-time]");
var elemArray = Array.from(sortItems);
elemArray.sort(function (a, b) {
if (a.getAttribute('data-time') < b.getAttribute('data-time')) { return -1 } else { return 1 }
});
//
document.getElementById("columns").innerHTML = "";
elemArray.forEach(appendFunction);
function appendFunction(item, index) {
document.getElementById("columns").innerHTML += item.outerHTML;
}
afterUpdate();
});
// order according to time end
}
document.getElementById("myInput").value = "";
document.getElementById("myInput1").value = "";
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
li.appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function () {
var div = this.parentElement;
div.style.display = "none";
}
}
}
// Add tasks by pressing enter
// Get the input field
var input = document.getElementById("myInput");
// Execute a function when the user releases a key on the keyboard
input.addEventListener("keyup", function (event) {
// Number 13 is the "Enter" key on the keyboard
if (event.keyCode === 13) {
// Cancel the default action, if needed
event.preventDefault();
// Trigger the button element with a click
document.getElementById("myBtn").click();
}
});
// //
// //
var btn = document.querySelector('.add');
var remove = document.querySelector('.column');
function dragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
};
function dragEnter(e) {
this.classList.add('over');
}
function dragLeave(e) {
e.stopPropagation();
this.classList.remove('over');
}
function dragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
return false;
}
function dragDrop(e) {
if (dragSrcEl != this) {
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
closeEvent();
}
return false;
}
function dragEnd(e) {
var listItems = document.querySelectorAll('.column');
[].forEach.call(listItems, function (item) {
item.classList.remove('over');
});
this.style.opacity = '1';
}
function addEventsDragAndDrop(el) {
el.addEventListener('dragstart', dragStart, false);
el.addEventListener('dragenter', dragEnter, false);
el.addEventListener('dragover', dragOver, false);
el.addEventListener('dragleave', dragLeave, false);
el.addEventListener('drop', dragDrop, false);
el.addEventListener('dragend', dragEnd, false);
}
function addDragAndDrop() {
var listItems = document.querySelectorAll('.column');
listItems.forEach(addEventsDragAndDrop);
}
afterUpdate();
function afterUpdate() {
closeEvent();
addDragAndDrop();
renderGraph();
}
function addNewItem() {
var newItem = document.querySelector('.input').value;
if (newItem != '') {
document.querySelector('.input').value = '';
var li = document.createElement('li');
var attr = document.createAttribute('column');
var ul = document.querySelector('ul');
li.className = 'column';
attr.value = 'true';
li.setAttributeNode(attr);
li.appendChild(document.createTextNode(newItem));
ul.appendChild(li);
addEventsDragAndDrop(li);
}
}
#myInput1 {
width: 180px;
height: 36px;
margin-right: 10px;
/* margin-left: -40px; */
/* padding: 10px; */
/* color: red; */
/* box-sizing: border-box; */
/* background-color: blue; */
/* display: inline-block; */
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
/* Required to make elements draggable in old WebKit */
-khtml-user-drag: element;
-webkit-user-drag: element;
}
/* Include the padding and border in an element's total width and height */
* {
box-sizing: border-box;
font-family: 'Josefin Sans', sans-serif;
}
p {
font-weight: 300;
}
h1 {
font-weight: 300;
}
#x-text {
color: #f97350;
font-size: 1.5rem;
}
::placeholder{
color: #777d71;
}
#myInput1:before {
content:'Time:';
margin-right:.6em;
color: #777d71;
}
/* Remove margins and padding from the list */
ul {
margin: 0;
padding: 0;
list-style: none;
}
/* Style the list items */
ul li {
cursor: pointer;
position: relative;
padding: 12px 8px 12px 40px;
background: #f7f6e7;
font-size: 18px;
transition: 0.2s;
color: rgb(94, 91, 91);
/* make the list items unselectable */
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* Set all odd list items to a different color (zebra-stripes) */
ul li:nth-child(odd) {
background: #dfddc5;
}
/* Darker background-color on hover */
ul li:hover {
background: rgb(207, 205, 205);
}
/* When clicked on, add a background color and strike out text */
ul li.checked {
background: #888;
color: #fff;
text-decoration: line-through;
}
/* Add a "checked" mark when clicked on */
ul li.checked::before {
content: '';
position: absolute;
border-color: #fff;
border-style: solid;
border-width: 0 2px 2px 0;
top: 10px;
left: 16px;
transform: rotate(45deg);
height: 15px;
width: 7px;
}
/* Style the close button */
.close {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
color: #f97350;
/* font-size: 1.5rem; */
}
.close:hover {
background-color: #f97350;
color: white;
}
/* Style the header */
.header {
background-color: #777d71;
padding: 30px 40px;
color: white;
text-align: center;
}
/* Clear floats after the header */
.header:after {
content: "";
display: table;
clear: both;
}
/* Style the input */
input {
margin: 0;
border: none;
border-radius: 0;
width: 75%;
padding: 10px;
float: left;
font-size: 16px;
}
/* Style the "Add" button */
/* .addBtn {
padding: 10px;
width: 25%;
background: #d9d9d9;
color: #555;
float: left;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
border-radius: 0;
} */
/* .addBtn:hover {
background-color: #bbb;
} */
#finished-tasks {
/* box-sizing: border-box; */
padding: 20px;
display: grid;
align-content: center;
justify-content: center;
background-color:#bbd38b ;
color: white;
margin-bottom: -20px;
margin-top: 40px;
}
#finished-tasks-p {
/* box-sizing: border-box; */
padding: 20px;
display: grid;
align-content: center;
justify-content: center;
background-color:#bbd38b ;
color: white;
margin-bottom: 0;
margin-top: 0;
}
/* #myChart{
margin-top: 50px;
width: 50vw;
height: 100px;
padding-left: 200px;
padding-right: 200px;
} */
/* canvas{
width:1000px !important;
height:auto !important;
margin: auto;
} */
#media only screen and (max-width: 855px){
input {
margin: 10px;
}
#myInput {
display: grid;
width:70vw;
/* align-content: center; */
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="myDIV" class="header">
<h1>My Daily Tasks</h1>
<p>Add a time and task then press enter. When finished task click on task bar</p>
<p>To delete task click on <span id="x-text">x</span> in the corner of task bar</p>
<input type="time" id="myInput1" value="06:00">
<input name="text" type="text" id="myInput" placeholder="My task...">
<span onclick="newElement()" class="addBtn" id="myBtn"></span>
</div>
<ul id="columns">
<!-- <li draggable="true" class="column">test</li>
<li draggable="true" class="column">test1</li> -->
<!-- <li class="column" draggable="true">w</li>
<li class="column" draggable="true">ff</li>
<li class="column" draggable="true">uuu</li> -->
</ul>
<ul id="columns2">
<h1 id="finished-tasks">finished Tasks</h1>
<p id="finished-tasks-p">Finished tasks would show up here once you have clicked on the task</p>
</ul>
<!-- adding a graph -->
<canvas id="myChart" width="400" height="400"></canvas>
<script src="/graph.js"></script>
<script src="/app.js"></script>
<!--
<div id="element"></div>
<script>
document.getElementById('element').innerHTML = 'Hi';
</script>-->
<script>
$("#columns").on('click', 'li', function () {
$(this).appendTo('#columns2');
});
$("#listC").on('click', 'li', function () {
$(this).appendTo('#listB');
});
</script>
Change your setTimeout call to this:
setTimeout(function () {
var sortItems = Array.from(document.querySelectorAll("[data-time]"))
.filter((item) => !item.classList.contains('checked'))
.sort(function (a, b) {
if (a.getAttribute('data-time') < b.getAttribute('data-time')) { return -1 } else { return 1 }
});
document.getElementById("columns").innerHTML = "";
sortItems.forEach(appendFunction);
function appendFunction(item, index) {
document.getElementById("columns").innerHTML += item.outerHTML;
}
afterUpdate();
});
The key passage is here:
.filter((item) => !item.classList.contains('checked'))
Before, you were selecting all of the items, even the ones that were already checked. This filters those out.
Here's a working JSFiddle you can experiment with. I had to add an event listener to the addBtn to get it to work on there, but your original script is fine when running from my local machine.
We use custom selectbox elements for our page (for reasons), but in one specific place and only with IE (in my case version 10 and 11), there is a problem.
When you open the box and close it, sometimes the browser leaves visual artifacts of that element. If there is a button below the element (in the opened state), then those artifacts are still on top of that button UNTIL you hover over the button, then those artifacts disappear at that place.
I think everyone experienced this behaviour at some point in his life with windows or something else. Sorry if my description isn't perfect.
Here are some screenshots (The red boxes are censored text, sorry):
Open state:
Closed state with artifacts:
Hope my description is accurate, I desperately need a fix for this.
I can't reproduce it on my system, but our QA guy can reproduce it consistently. It also changes depending on the size of the browser. On some sizes it doesn't seem to happen at all. It must be some weird rendering glitch of IE.
I don't think it has anything to do with our custom selectbox element, because it happens only in this specific place and in our old design we experienced it in a different place with a completely different element. At that time I thought it's because the DOM is too complicated for IE, but this page has almost no elements.
EDIT: I Just found out that if I minimize the window and maximize it again, the artifacts disappear, which should confirm that this is a rendering glitch, right?
EDIT 2: Here is the code and css of our custom selectbox
HTML:
<div class="input_selectbox">
<label>Title</label>
<div class="input_selectbox__head" data-placeholder="">
<label>
<input type="hidden" name="id" value="5-10909">
Dummy 1
</label>
</div>
<div class="input_selectbox__body">
<label data-value="" class="">
No Option
</label>
<label id="5-10909" data-value="5-10909" class="input_selectbox__option--selected" data-default="true">
Dummy 1
</label>
<label id="5-12568" data-value="5-12568" class="">
Dummy 2
</label>
<label id="5-20001" data-value="5-20001" class="">
Dummy 3
</label>
<label id="5-20002" data-value="5-20002" class="">
Dummy 4
</label>
</div>
</div>
LESS:
.input_combobox, .input_selectbox {
display: block;
font-family: RobotoCondensed-Regular;
font-size: 14px;
width: 100%;
overflow: hidden;
&:focus {
outline: none;
}
label {
cursor: pointer;
}
}
.input_selectbox {
font-family: Roboto-Regular;
}
.input_selectbox__head {
border: 1px solid #colorBorderGrey;
transition: background-color 0.2s, border 0.3s;
overflow-x: hidden;
text-overflow: ellipsis;
display: flex;
background-color: #colorLightestGrey;
padding: 10px;
justify-content: space-between;
&:hover {
cursor: pointer;
border-color: #colorDarkGrey;
&:after {
color: #colorBlue;
}
}
label {
display: flex;
user-select: none;
pointer-events: none;
i {
margin-right: 10px;
}
}
&:after {
content: "\f078";
font-style: normal;
font-variant: normal;
text-rendering: auto;
font-family: "Font Awesome 5 Pro";
font-weight: 900;
pointer-events: none;
transition: color 0.3s, opacity 0.3s, background-color 0.2s;
display: block;
padding-left: 10px;
font-size: 16px;
}
}
.input_combobox--active, .input_selectbox--active {
.input_combobox__head, .input_selectbox__head {
background-color: #colorLightGrey;
&:hover {
border: 1px solid #colorBorderGrey;
&:after {
color: #colorDarkGrey;
}
}
&:after {
background-color: #colorLightGrey;
}
span {
background-color: #colorGreyHover;
}
}
}
.input_combobox__body, .input_selectbox__body {
display: none;
position: fixed;
box-shadow: rgba(0,0,0, 0.05) 0px 2px 5px 0px;
background-color: #colorWhite;
border: 1px solid #colorBorderGrey;
border-top: none;
max-height: 400px;
overflow-y: auto;
width: 100%;
z-index: 499;
label {
font-family: RobotoCondensed-Regular;
font-size: 16px;
display: block;
padding: 10px 20px;
transition: background-color 0.5s, color 0.3s;
border-bottom: 1px solid #colorBorderGrey;
&:hover {
background-color: #colorLightGrey;
}
&:last-child {
border-bottom: none;
}
i {
margin-right: 10px;
}
input[type=checkbox] {
display: none;
}
}
}
.input_combobox__body--top, .input_selectbox__body--top {
box-shadow: rgba(0, 0, 0, 0.1) 0px -2px 5px 0px;
}
.input_combobox__option--inactive, .input_selectbox__option--inactive {
opacity: 0.3;
}
Javascript:
function selectbox()
{
// click
$(document).on("click", ".input_selectbox__head", function ()
{
$(this).trigger("selectbox:toggle");
});
// toggle
$(document).on("selectbox:toggle", ".input_selectbox__head", function ()
{
if ($(this).parent().hasClass("input_selectbox--active"))
{
$(this).trigger("selectbox:close");
}
else
{
$(this).trigger("selectbox:open");
}
});
// open
$(document).on("selectbox:open", ".input_selectbox__head", function ()
{
var selectbox = $(this).closest(".input_selectbox");
if (!selectbox.hasClass("readonly") && !selectbox.hasClass("input--disabled"))
{
$(".input_selectbox--active .input_selectbox__head").trigger("selectbox:close");
// Positionierung
var header = selectbox.find(".input_selectbox__head");
var headerHeight = header.outerHeight();
var selectboxBody = selectbox.find(".input_selectbox__body");
var headerPositionX = header.offset().left;
var headerPositionY = header.offset().top - $(window).scrollTop();
var bodyPositionY = headerPositionY + headerHeight;
selectboxBody.removeClass("input_selectbox__body--top");
selectboxBody.css({
"top": bodyPositionY,
"left": headerPositionX,
"width": selectbox.width(),
"bottom": ""
});
selectbox.addClass("input_selectbox--active");
selectboxBody.show();
// check if offscreen
var isOut = isOutOfViewport(selectboxBody.get(0));
if (isOut.bottom)
{
selectboxBody.addClass("input_selectbox__body--top");
selectboxBody.css({
top: "",
bottom: ($(window).innerHeight() - headerPositionY - 1)
});
}
// close combobox on parent scroll
var scrollParent = getScrollParent(header[0]);
$(scrollParent).one("scroll", function ()
{
header.trigger("selectbox:close");
});
$(document).one("scroll", function ()
{
header.trigger("selectbox:close");
});
$(window).one("resize", function ()
{
header.trigger("selectbox:close");
});
}
});
// close
$(document).on("selectbox:close", ".input_selectbox__head", function ()
{
var selectbox = $(this).closest(".input_selectbox");
selectbox.removeClass("input_selectbox--active");
var selectboxBody = selectbox.find(".input_selectbox__body");
selectboxBody.hide();
});
// change option
$(document).on("click", ".input_selectbox__body > label", function ()
{
var label = $(this);
var value = label.attr("data-value");
var headerLabel = $(this).closest(".input_selectbox__body").siblings(".input_selectbox__head").children("label");
var name = headerLabel.find("input[type=hidden]").attr("name");
label.addClass("input_selectbox__option--selected").siblings().removeClass("input_selectbox__option--selected");
headerLabel.html(label.html());
headerLabel.append('<input type="hidden" name="' + name + '" value="' + value + '" />');
headerLabel.closest(".input_selectbox__head").trigger("selectbox:close");
$(this).closest(".input_selectbox").trigger("selectbox:change").trigger("change");
});
// close selectbox on outside click
$(document).ready(function ()
{
$(document).on("click touchstart", function (event)
{
if ($(event.target).closest('.input_selectbox--active').length == 0)
{
$(".input_selectbox--active .input_selectbox__head").trigger("selectbox:close");
}
});
});
// form reset
$(document).on("reset", "form", function ()
{
var selectboxes = $(this).find(".input_selectbox");
selectboxes.each(function ()
{
$(this).find(".input_selectbox__body").find("label[data-default=true]").click();
});
});
}
I have these elements created inside a "querySelector('ul'). It's working property.
I want the "blue-Save" button to have the same function as the "yellow-Save".
But the Blue-save button was created in the HTML file, and the Yellow-Save button was created in JavaScript to listen to an event from the "querySelector('ul').
Is there anyway I can just link the Blue-Save to react as if I was clicking in the Yellow-Save?
(I'm sorry if I didn't explain it property or If it seems too confused, this is my first application, It doesn't seems too organized but I'm focused in making things work before dive in 'well developed apps').
Thank You Everyone!
var todoList = {
todos: [],
addTodo: function (todoText) {
this.todos.push({
todoText: todoText,
/*the name of the property (even if it is the same name as the parameter) never change. Only the value, which follows in this case is following the parameter*/
completed: false
});
},
changeTodo: function (position, todoText) {
this.todos[position].todoText = todoText;
},
deleteTodo: function (position) {
this.todos.splice(position, 1);
},
toggleCompleted: function (position) {
var todo = this.todos[position];
todo.completed = !todo.completed;
/*Here we flip the boolean to his oposite value. if todo.completed is equal false, so changes it to true, and so on. */
},
toggleAll: function () {
// recording the number of todos and completed todos
var totalTodos = this.todos.length;
var completedTodos = 0;
// get the number of completed todos.
this.todos.forEach(function (todo) {
if (todo.completed === true) {
completedTodos++;
}
});
this.todos.forEach(function (todo) {
// Case 1: If everything is true, make everything.
if (completedTodos === totalTodos) {
todo.completed = false;
// Case 2: Otherwise, make everything true.
} else {
todo.completed = true;
}
});
}
};
var handlers = {
addTodo: function () {
var addTodoTextInput = document.getElementById('add-todo-text-input');
todoList.addTodo(addTodoTextInput.value);
addTodoTextInput.value = '';
view.displayTodos();
},
changeTodo: function (position) {
var changeTodoTextInput = document.getElementById('change-todo-text-input');
todoList.changeTodo(position, changeTodoTextInput.value);
changeTodoTextInput.value = '';
view.displayTodos();
},
deleteTodo: function (position) {
todoList.deleteTodo(position);
view.displayTodos();
},
toggleCompleted: function (position) {
todoList.toggleCompleted(position);
view.displayTodos();
},
toggleAllButton: function () {
todoList.toggleAll();
view.displayTodos();
}
};
var view = {
displayTodos: function () {
var todosUl = document.querySelector('ul');
todosUl.innerHTML = '';
todoList.todos.forEach(function (todo, position) {
var todoLi = document.createElement('li');
var todoTextWithCompletion = '';
if (todo.completed === true) {
todoTextWithCompletion = todo.todoText;
todoLi.classList.add('item-completed');
} else {
todoTextWithCompletion = todo.todoText;
}
todoLi.id = position;
todoLi.textContent = todoTextWithCompletion;
todoLi.appendChild(this.createEditButton());
todoLi.appendChild(this.createToggleButton());
todoLi.appendChild(this.createDeleteButton());
todoLi.appendChild(this.createSaveButton());
todosUl.appendChild(todoLi);
}, this);
},
createDeleteButton: function () {
var deleteButton = document.createElement('button');
deleteButton.textContent = '\u2715';
deleteButton.className = 'delete-button';
return deleteButton;
},
createToggleButton: function () {
var toggleButton = document.createElement('button');
toggleButton.textContent = '\u2713';
toggleButton.className = 'toggle-button';
return toggleButton;
},
createSaveButton: function () {
var saveButton = document.createElement('button');
saveButton.textContent = 'Save';
saveButton.className = 'save-button';
return saveButton;
},
createEditButton: function () {
var editButton = document.createElement('button');
editButton.textContent = '\u270E';
editButton.className = 'edit-button';
return editButton;
},
setUpEventListeners: function () {
var todosUl = document.querySelector('ul');
todosUl.addEventListener('click', function (event) {
// Get the element that was clicked on.
var elementClicked = event.target;
// Check if elementClicked is a delete button.
if (elementClicked.className === 'delete-button') {
handlers.deleteTodo(parseInt(elementClicked.parentNode.id));
} else if (elementClicked.className === 'toggle-button') {
handlers.toggleCompleted(parseInt(elementClicked.parentNode.id));
} else if (elementClicked.className === 'save-button') {
handlers.changeTodo(parseInt(elementClicked.parentNode.id));
} else if (elementClicked.className === 'edit-button') {
}
});
}
};
view.setUpEventListeners();
body {
font-family: Helvetica, sans-serif;
font-size: 25px;
background: rgb(236, 236, 236);
}
h1 {
color: rgb(255, 255, 255);
text-align: center;
font-family: Helvetica, sans-serif;
font-size: 50px;
text-transform: uppercase;
background: rgb(48, 48, 48);
position: relative;
}
.container {
margin: auto;
width: 50%;
}
ul {
list-style: none;
padding:0px;
margin: 10px;
}
.add-button {
background-color: rgb(68, 165, 230); /* Blue */
border: none;
color: white;
margin:auto;
padding: 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
border-radius: 5px;
width:20%;
}
.add-button:hover {
background-color :rgb(53, 127, 177); /* Green */
color: white;
}
.save-change-button {
background-color: rgb(68, 165, 230); /* Blue */
border: none;
color: white;
margin:auto;
padding: 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
border-radius: 5px;
width:20%;
}
.save-change-button:hover {
background-color :rgb(53, 127, 177); /* Green */
color: white;
}
.toggle-all-button {
background-color: rgb(38, 156, 38); /* Green */
border: none;
color: white;
margin: 10px 0;
padding: 15px 32px;
text-align: center;
text-decoration: none;
font-size: 16px;
border-radius: 5px;
width: 100%;
}
.toggle-all-button:hover {
background-color : rgb(36, 114, 36); /* Green */
color: white;
}
.edit-button {
background-color: rgb(219, 208, 50); /* Green */
border: none;
color: white;
padding: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
width: 25px;
height: 25px;
margin: 0 0 0 10px;
}
.edit-button:hover {
background-color: rgb(185, 175, 26); /* Green */
color: white;
}
.toggle-button {
background-color: rgb(38, 156, 38); /* Green */
border: none;
color: white;
padding: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
width: 25px;
height: 25px;
margin: 0 0 0 10px;
}
.toggle-button:hover {
background-color: rgb(36, 114, 36); /* Green */
color: white;
}
.delete-button {
background-color: rgb(168, 44, 44); /* Green */
border: none;
color: white;
margin: 0 0 0 10px;
padding: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
width: 25px;
height: 25px;
}
.delete-button:hover {
background-color :rgb(128, 31, 31); /* Green */
color: white;
}
.save-button {
background-color: rgb(219, 208, 50); /* Green */
border: none;
color: white;
padding: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
border-radius: 5px;
width: 55px;
height: 25px;
margin: 0 10px;
}
.save-button:hover {
background-color :rgb(185, 175, 26); /* Green */
color: white;
}
.add-input {
margin: 10px 0;
padding: 6px 0;
text-align: center;
font-family: Arial, Helvetica, sans-serif;
font-size: 18px;
width: 78%;
}
.edit-input {
margin: 10px 0;
padding: 6px 0;
text-align: center;
font-family: Arial, Helvetica, sans-serif;
font-size: 18px;
width: 78%;
}
.item-completed {
text-decoration: line-through;
}
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
color: rgba(209, 209, 209, 0.555);
font-family: 'Times New Roman', Times, serif;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Todo List</title>
<link href="index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="container">
<h1>Todo List</h1>
<div>
<input id="add-todo-text-input" class="add-input" placeholder="Add a New Todo to Your List" type="text">
<button class="add-button" onclick="handlers.addTodo()">Add</button>
</div>
<ul>
</ul>
<div id="edit-todo"">
<input id="change-todo-text-input" class="edit-input" placeholder="Add the Changes Your Want to Make" type="text">
<button class="save-change-button">Save</button>
</div>
<div id="toggle-all"">
<button class="toggle-all-button" onclick="handlers.toggleAllButton()">Toggle All</button>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
You can add a common class to both blue and yellow buttons, and attach a click event by the class name like below
$(".custom_save_button").on("click", function() {
//your code
});
Since you are creating that button, sharing the same class won't just work as expected, instead use delegated events which allow you to attach events on new elements added to the DOM
Add a common class for both and then add an event listener for that class using event delegation.
For this example Let's suppose you chose the class name: stack_class
//I added this function for you to be able to know if an element has a class
function hasClass( target, className ) {
return new RegExp('(\\s|^)' + className + '(\\s|$)').test(target.className);
}
//you could change body to the closest parent's selector both buttons share
document.querySelector('body').addEventListener('click', function(event) {
var clickedElement = event.target;
if(hasClass(clickedElement, "stack_class")) {
//create your functionality for both buttons here
}
});
If you assign a common class to both buttons, then you can add the same event listener to all buttons that have that class. Here is a simple example:
var saveButton = document.createElement('button');
saveButton.textContent = 'Save';
saveButton.className = 'save-button yellow-button';
body = document.querySelector('body');
body.appendChild(saveButton);
buttons = document.getElementsByClassName('save-button');
for (var i = 0; i < buttons.length; i += 1) {
buttons[i].addEventListener('click', function (event) {
alert('Hello!');
});
}
.yellow-button {
background: #ffff00;
}
.blue-button {
background: #0000ff;
}
<button class="save-button blue-button">Save</button>
When I toggle between jQuery filters that show elements with a certain class, sometimes the selected filter shows all elements and not just the ones with the respective class.
You can see this in the below fiddle. Switch between the select options and sometimes they'll show all results.
Fiddle.
function activateButtons(_data){
$('.jobs-teams select').on("change", function(e) {
e.preventDefault();
for(i = 0; i < _data.length; i++) {
var teamRaw = _data[i].title;
var team = cleanString(teamRaw);
var jobs = $(".jobs-list");
if ($(this).find(":selected").hasClass(team)) {
if ($(this).hasClass("active")) {
$(this).removeClass("active");
jobs.find(".job").fadeIn("fast");
}
else {
$(".jobs-teams").find("a").removeClass("active");
$(this).addClass("active");
jobs.find("."+team).fadeIn("fast");
jobs.find(".job").not("."+team).fadeOut("fast");
}
}
}
})
}
Issues with the code that just need to be updated are the following.
//$(this) return the select tag. you should target options
if ($(this).hasClass("active")) {
$(this).removeClass("active");
jobs.find(".job").fadeIn("fast");
}
else {
//$(".jobs-teams").find("a") returns undefined remember that you changed the anchors to select options
$(".jobs-teams").find("a").removeClass("active");
$(this).addClass("active");
jobs.find("."+team).fadeIn("fast");
jobs.find(".job").not("."+team).fadeOut("fast");
}
CODE SNIPPET:
// Replace "leverdemo" with your own company name
url = 'https://api.lever.co/v0/postings/leverdemo?group=team&mode=json'
//Functions for checking if the variable is unspecified
function cleanString(string) {
if (string) {
var cleanString = string.replace(/\s+/ig, "");
return cleanString;
}
else {
return "Uncategorized";
}
}
function nullCheck(string) {
if (!string) {
var result = 'Uncategorized'
return result;
}
else {
return string;
}
}
function createJobs(_data) {
for(i = 0; i < _data.length; i++) {
var team = nullCheck(_data[i].title)
var teamCleanString = cleanString(team);
$('#jobs-container .jobs-teams select').append(
'<option value="" class=' + teamCleanString + '>' + team + '</option>'
);
}
for(i = 0; i < _data.length; i++) {
for (j = 0; j < _data[i].postings.length; j ++) {
var posting = _data[i].postings[j]
var title = posting.text
var description = posting.description
//Making each job description shorter than 250 characters
var shortDescription = $.trim(description).substring(0, 250)
.replace('\n', ' ') + "...";
var location = nullCheck(posting.categories.location);
var locationCleanString = cleanString(location);
var commitment = nullCheck(posting.categories.commitment);
var commitmentCleanString = cleanString(commitment);
var team = nullCheck(posting.categories.team);
var teamCleanString = cleanString(team);
var link = posting.hostedUrl;
$('#jobs-container .jobs-list').append(
'<div class="job '+teamCleanString+' '+locationCleanString+' '+commitmentCleanString+'">' +
'<a class="job-title" href="'+link+'"">'+title+'</a>' +
'<p class="tags"><span>'+team+'</span><span>'+location+'</span><span>'+commitment+'</span></p>' +
'<p class="description">'+shortDescription+'</p>' +
'<a class="btn" href="'+link+'">Learn more</a>' +
'</div>'
);
}
}
}
function activateButtons(_data){
$('.jobs-teams select').on("change", function(e) {
e.preventDefault();
for(i = 0; i < _data.length; i++) {
var teamRaw = _data[i].title;
var team = cleanString(teamRaw);
var jobs = $(".jobs-list");
var $this = $(this).find(":selected");
if ($this.hasClass(team)) {
if ($this.hasClass("active")) {
$this.removeClass("active");
jobs.find(".job").fadeIn("fast");
}
else {
$(".jobs-teams select").find("option").removeClass("active");
$this.addClass("active");
jobs.find("."+team).fadeIn("fast");
jobs.find(".job").not("."+team).fadeOut("fast");
}
}
}
}).change();
}
//Fetching job postings from Lever's postings API
$.ajax({
dataType: "json",
url: url,
success: function(data){
createJobs(data);
activateButtons(data);
}
});
body {
font-family: 'Lato', sans-serif;
overflow-y: scroll;
}
p {
margin: 0 0 1em 0;
line-height: 1.4em;
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
section {
position: relative;
padding: 30px;
}
.container {
max-width: 960px;
margin: 0 auto;
}
.job {
display: inline-block;
vertical-align: top;
width: 50%;
padding: 40px 30px;
}
h1 {
font-size: 48px;
color: #454545;
padding: 0 30px;
}
.job-title {
font-size: 24px;
text-decoration: none;
color: #454545;
}
.job-title:hover {
color: #00A0DF;
}
.tags span {
color: #999;
font-size: 12px;
color: grayMediumDark;
}
.tags span:after {
content: ', ';
}
.tags span:last-of-type:after {
content: '';
}
.description {
color: #999;
}
.btn {
display: inline-block;
padding: 7px 15px;
text-decoration: none;
font-weight: normal;
color: #999;
border: 2px solid #ebebeb;
-webkit-border-radius: 4px;
border-radius: 4px;
background: #f9f9f9;
}
.btn:hover {
background: #ebebeb;
color: #555;
}
.btn.active {
background: #454545;
border-color: #454545;
color: #fff;
}
.jobs-teams {
margin-bottom: 40px;
padding: 0 30px
}
.jobs-teams .btn {
margin: 0 8px 8px 0;
}
.jobs-teams .btn:first-of-type {
margin-left: 0;
}
.jobs-teams .btn:last-of-type {
margin-right: 0;
}
<section>
<div class="container" id="jobs-container">
<h1>Open jobs</h1>
<div class="jobs-teams">
<select>
</select>
</div>
<div class="jobs-list">
</div>
</div>
</section>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
Consider doing it with fewer lines:
function activateButtons(_data) {
$('.jobs-teams select').on("change", function(e) {
e.preventDefault();
var selected_class = $('.jobs-teams select').find(':selected').attr('class');
$('.jobs-list').find('div.job')
.not('.' + selected_class).fadeOut('fast').end() //remove the ones that do not match
.filter('.' + selected_class).not(':visible').fadeIn('fast'); // bring in the ones that do match (and are not already visible)
})
.change(); //have the form pre-load with the default selected value
}
Oh--I also added a line to have the jobs honor the default selection (.change(); //have the form pre-load with the default selected value).
Working fiddle.
I am using pubnub in Javascript (version 3.10.2, which I believe is the latest version as of now). I am making a little game, and alongside the game is a chat div, where I append an li containing my message to a ul. I also have a occupancy counter. I call a function in pubnub.subscribe (presence: displayOccupancy) to display m.occupancy. (sorry if all of this was useless info, first question) The problem is that there is a UUID which I named "test3" which will not timeout from channel "chat" and when I made a button to force that UUID to unsubscribe, it would rejoin automatically after a few seconds. After changing UUIDs and trying this again, they would timeout normally according to my heartbeat and if I made the UUID unsubscribe, it would generate a leave event and that was it. Why does the UUID not leave or timeout from the channel?
EDIT: It's not only the "test3" UUID which lingers. Every time I reopen and test my code from Dreamweaver, the most recent test UUID which I have assigned the previous time I have worked on it "replaces" the UUID which was there before. ("previously" as in from the previous day, not every previous test)
// JavaScript Document
var uuid = PUBNUB.uuid();
var pubnub = PUBNUB.init({
publish_key: 'pub-c-bbf633c9-8ddb-43f7-bf4c-c03215ccd8d8',
subscribe_key: 'sub-c-a1b830fa-d9f5-11e5-a22c-02ee2ddab7fe',
uuid: uuid,
heartbeat: 10
});
var noOfWordsInRow = 0;
//arrays
var consanantArray = ["b","c","d","f","g","h","j","k","l","m","n","p","r","s","t","v","w","y"];
var vowelArray = ["a","e","i","o","u"];
var submittedWordsArray = [];
//containers
var lettersDiv = $("div#letterDisplay");
var wordAreaDiv = $("div#wordArea");
var submitDiv = $("div#submitDiv");
var startDiv = $("div#start");
var checkDiv = $("div#checkDiv");
var consanantUl = $("ul#consanantUl");
var vowelUl = $("ul#vowelUl");
var chatUl = $("#chatList");
var confirmWord = $("p#word");
var confirmBtn = $("#confirmBtn");
var error = $("#error");
var noOfPlayers = $("p#noOfPlayers");
//buttons
var startGame = $("button#enterGame");
//input
var chatInput = $("#chatInput");
//other
/**
var consanantOne = $("#firstConsanant");
var consanantTwo = $("#secConsanant");
var consanantThree = $("#thirdConsanant");
var consanantFour = $("#fourthConsanant");
var vowelOne = $("#firstVowel");
var vowelTwo = $("#firstVowel");
var vowelThree = $("#firstVowel");
**/
//pubnub portion of game
$("#testLeave").click(function(){
"use strict";
pubnub.unsubscribe({
channel: "chat"
});
});
//game and chat stuff below
$(window).load(function(){
"use strict";
generateLetters();
});
startGame.click(function(){
"use strict";
//channel
startDiv.css("display", "none");
});
function handleMessage(message){
"use strict";
chatUl.append("<li>"+message+"</li>");
}
function getNoOfUsers(m){
"use strict";
console.log(m);
if(m.action === "join"){
}
else if(m.action === "timeout" || m.action === "leave"){
pub("chat","Player left");
}
noOfPlayers.html(m.occupancy);
}
function playerJoined(){
"use strict";
pub("chat","Player joined");
}
function pub(channel, message){
"use strict";
pubnub.publish({
channel: channel,
message: message
});
}
chatInput.keydown(function(key){
"use strict";
if(key.which === 13){
pub("chat",$("#chatInput").val());
chatInput.val('');
}
});
function generateLetters(){
"use strict";
//vowels
generateRandomLetters(vowelArray, vowelUl, 3);
//consanants
generateRandomLetters(consanantArray, consanantUl, 4);
}
function generateRandomLetters(array, ul, noOfElementsNeeded){ //noOfElementsNeeded = 3 or 4
"use strict";
var usedLetters = [];
var successCount = 0;
while(successCount < noOfElementsNeeded){
var letter = array[Math.floor(Math.random()*array.length)];
var successful = usedLetters.indexOf(letter) === -1; //boolean, checks if the generated letter has been generated before
if(successful){
ul.append("<li><button>"+letter+"</button></li>");
usedLetters.push(letter);
successCount++;
}
}
}
function duplicateLetter(letter){
"use strict";
if((confirmWord.text()).indexOf(letter) > -1){
return true;
}
else {
return false;
}
}
function wordLengthAboveTwo(){
"use strict";
if((confirmWord.text()).length < 3){
return false;
} else {
return true;
}
}
function repeatWords(){
"use strict";
if(submittedWordsArray.indexOf(confirmWord.text()) === -1){
return false;
} else {
return true;
}
}
$(document).on('click', 'ul li button', function(){
"use strict";
var letter = $(this).text();
if(duplicateLetter(letter)){
error.text("You cannot use the same letter twice in a word.");
}
else {
confirmWord.append(letter);
}
});
confirmBtn.click(function(){
"use strict";
if(wordLengthAboveTwo()){
if(!repeatWords()){
if(noOfWordsInRow === 5){
$("#tableOfSubmittedWords").append("<tr><td><p>"+confirmWord.text()+"</p></td></tr>");
noOfWordsInRow++;
noOfWordsInRow = 1;
} else {
$("#tableOfSubmittedWords tr:last").append("<td><p>"+confirmWord.text()+"</p></td>");
noOfWordsInRow++;
}
submittedWordsArray.push(confirmWord.text());
confirmWord.text('');
error.text('');
} else {
error.text("You cannot submit two of the same word.");
}
} else {
error.text("Your word has to be above two letters in length.");
}
});
$(document).on('click', 'p#word', function(){
"use strict";
confirmWord.text('');
});
pubnub.subscribe({
channel: "chat",
presence: getNoOfUsers,
message: handleMessage,
connect: playerJoined
});
#charset "utf-8";
/* CSS Document */
#container {
height: 800px;
position:fixed;
}
div#start {
z-index: 18;
height: 850px;
position: absolute;
background-color: #00FF8C;
width: 100%;
}
#letterDisplay {
position: relative;
background-color: #01ACFF;
height: 200px; /*200px*/
margin: 0 auto;
}
#wordArea {
overflow: scroll;
height: 400px;
width: 100%;
text-align: center;
}
#submitDiv {
background-color: #01ACFF;
height: 250px;
margin: 0 auto;
}
#chatDiv {
position: fixed;
height: 200px;
z-index: 2;
}
ul#chatList li, ul#listOfUsers li{
display: list-item !important;
text-align: left;
}
table {
width: 100%;
height: 100%;
table-layout: fixed;
}
table tr {
width: 100%;
}
table tr td {
size: auto;
}
table tr td p{
font: 25px/1 "Comic Sans MS", Verdana, sans-serif;
text-transform: uppercase;
}
#confirmBtn {
height: 75px;
width: 200px;
}
#checkDiv {
padding-top: 25px;
text-align: center;
size: auto;
}
p#word {
font: 30px/1 "Comic Sans MS", Verdana, sans-serif;
text-transform: uppercase;
}
p#word:hover {
color: #E74C3C;
cursor: pointer;
}
p#error {
color: #E74C3C;
transition: all 0.1s;
-moz-transition: all 0.1s;
-webkit-transition: all 0.1s;
}
div ul li p {
font: 25px/1 "Comic Sans MS", Verdana, sans-serif;
text-transform: uppercase;
}
button {
font: 36px/1 "Comic Sans MS", Verdana, sans-serif;
color: #FFF;
width: 75px;
height: 75px;
text-transform: uppercase;
border-radius: 4px;
background-color: #F2CF66;
text-shadow: 0px -2px #2980B9;
transition: all 0.1s;
-moz-transition: all 0.1s;
-webkit-transition: all 0.1s;
}
button#enterGame {
width: auto;
}
button:hover {
background-color: #E74C3C;
cursor: pointer;
}
button:active {
-webkit-transform: translate(0px,5px);
-moz-transform: translate(0px,5px);
transform: translate(0px,5px);
border-bottom: 1px solid;
}
ul {
list-style-type: none;
text-align: center;
}
ul#consanantUl {
padding-top: 25px;
}
ul#vowelUl {
vertical-align: bottom;
}
ul li{
display: inline;
padding-right: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Word Game</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div id="container">
<button id="testLeave">clik 2 leev</button>
<div id="start">
Channel Name? <input type="text" id="channelInput">
<button id="enterGame">Join</button>
<p id="startMenuError"></p>
</div>
<div id="presenceDiv">
<p id="noOfPlayers"></p>
</div>
<div id="chatDiv">
<ul id="chatList"></ul>
<input type="text" id="chatInput">
</div>
<div id="letterDisplay">
<ul id="consanantUl"></ul>
<ul id="vowelUl"></ul>
</div>
<div id="wordArea">
<table id="tableOfSubmittedWords">
<tr><td> </td><td> </td><td> </td><td> </td><td> </td></tr>
<tr></tr>
</table>
</div>
<div id="submitDiv">
<div id="checkDiv">
<p id="word"></p>
<button id="confirmBtn">submit</button>
<p id="error"></p>
</div>
</div>
</div>
<!--Jquery-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.color-animation/1/mainfile"></script>
<!--Pubnub-->
<script src="https://cdn.pubnub.com/pubnub-3.10.2.js"></script>
<!--My Code-->
<script src="script.js"></script>
</body>
</html>