Is there a way to get my Stack Exchange stats? - javascript

I’m working on a re-creation of the flare image that Stack Exchange offers, and the re-creation is more responsive in that I can hover over a site icon and show my stats for a given Stack Exchange domain. I currently have to manually update my data which I plan to do twice a month or so, unless there’s a way to load that data directly from Stack Exchange via a web service or similar.
A few things to keep in mind:
I will be hosting this in an ASP.NET web application so C# APIs would be fine.
Web services would be perfect too since I can call them from JavaScript.
I would need links to documentation for any service provided.
Below is my current manual re-creation in case you’re curious or don’t know what the SE flair is, though it does need to be cleaned up and made to be more efficient.
var siteNames = [ 'Stack Exchange',
'Puzzling',
'Stack Overflow',
'Software Engineering',
'Mathematics',
'Physical Fitness' ]
var reps = [ '6.2k', '4.3k', '954', '410', '224', '220' ];
var golds = [ '1', '0', '0', '1', '0', '0' ];
var silvers = [ '14', '7', '4', '2', '1', '0' ];
var bronzes = [ '98', '50', '20', '10', '8', '10' ];
function getSiteStats(siteID) {
document.getElementById("site-name").innerText = siteNames[siteID];
document.getElementById("rep").innerText = reps[siteID];
document.getElementById("gold").innerText = golds[siteID];
document.getElementById("silver").innerText = silvers[siteID];
document.getElementById("bronze").innerText = bronzes[siteID];
}
function resetSiteStats() {
getSiteStats(0);
}
html, body {
margin: 0;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: #6aa4ed;
background-image: linear-gradient(45deg, #6aa4ed, #141d33);
background-image: -webkit-linear-gradient(45deg, #6aa4ed, #141d33);
}
h1, h5 {
color: #fff;
font-family: Arial, Helvetica, sans-serif;
font-weight: 100;
text-align: center;
margin: 0;
}
h1 {
font-size: 10vh;
}
h5 {
margin-bottom: 10px;
}
.flair {
padding: 15px;
background-color: #fff;
border-radius: 5px;
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.25);
display: flex;
}
.flair img {
width: 40px;
height: 40px;
margin: 5px;
cursor: pointer;
}
.flair .profile {
width: 175px;
height: 175px;
margin: 0;
margin-right: 15px;
box-shadow: 2px 2px 4px rgba(12,13,14,0.5);
cursor: default;
}
.flair a {
color: #37f;
text-decoration: none;
margin: 5px;
}
.flair a:hover {
color: #15a;
}
.flair ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.flair ul > li {
display: inline-block;
margin: 5px;
}
.flair p {
margin: 0;
margin-left: 5px;
}
.badge div {
display: inline-block;
height: 7px;
width: 7px;
border-radius: 50%;
transform: translateY(-3px) translateX(3px);
}
.gold {
background-color: #fc0;
}
.silver {
background-color: #ccc;
}
.bronze {
background-color: #da6;
}
<h1>Stack Exchange Flair</h1>
<h5>Not Mobile Friendly (Yet)</h5>
<h5>Hover Over Site Icons</h5>
<div class="flair">
<img class="profile" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/2940219/blue.jpg" />
<div class="account">
PerpetualJ
<p id="site-name">Stack Exchange</p>
<ul>
<li><strong id="rep">6.2k</strong></li>
<li>
<div class="badge">
<div class="gold"></div>
<span id="gold">1</span>
</div>
</li>
<li>
<div class="badge">
<div class="silver"></div>
<span id="silver">14</span>
</div>
</li>
<li>
<div class="badge">
<div class="bronze"></div>
<span id="bronze">98</span>
</div>
</li>
</ul>
<ul>
<li onmouseover="getSiteStats(1);" onmouseout="resetSiteStats();"><img src="https://cdn.sstatic.net/Sites/puzzling/img/icon-48.png"/></li>
<li onmouseover="getSiteStats(2);" onmouseout="resetSiteStats();"><img src="https://cdn.sstatic.net/Sites/stackoverflow/img/apple-touch-icon.png"/></li>
<li onmouseover="getSiteStats(3);" onmouseout="resetSiteStats();"><img src="https://cdn.sstatic.net/Sites/softwareengineering/img/icon-48.png"/></li>
<li onmouseover="getSiteStats(4);" onmouseout="resetSiteStats();"><img src="https://cdn.sstatic.net/Sites/math/img/apple-touch-icon.png"/></li>
<li onmouseover="getSiteStats(5);" onmouseout="resetSiteStats();"><img src="https://cdn.sstatic.net/Sites/fitness/img/icon-48.png?v=f5a02f85db94"/></li>
</ul>
<p>How fast do you have to slap a chicken to cook it?</p>
</div>
</div>
Is there some way for me to call an API, web service, or similar that will allow me to pull my current stats for a given Stack Exchange site?
Also, I would prefer to not do any type of web scraping or similar. I’d prefer it come from a legitimate Stack Exchange service.
NOTE: If this belongs on meta please let me know so it can be migrated.
On-Topic: This question is considered as on-topic per the help center:
We feel the best Stack Overflow questions have a bit of source code in them, but if your question generally covers…
software tools commonly used by programmers; and is
a practical, answerable problem that is unique to software development
…then you’re in the right place to ask your question!
Given the above quote, API's are tools commonly used by programmers, and by asking if Stack Exchange has one, this question is a practical and answerable problem. However, I do believe this may have been better suited for Meta, but I am unable to migrate it.

I found out recently that Stack Exchange does offer an API for these types of things. I heavily recommend reading over their documentation for the API prior to usage. In order to accomplish the task I've asked about here, I needed to utilize the following API calls:
/users/{ids}
/users/{ids}/associated
I utilized both of these calls together to recreate the Stack Exchange flair, and just-in-case you do not know what the flair is:
To get started I wrote a simple set of methods to process my requests to the API:
function getWebServiceResponse(requestUrl, callback) {
let request = new XMLHttpRequest();
request.open('GET', requestUrl, true);
request.onload = function() {
if (request.status < 200 || request.status >= 400)
callback("An unexpected error occurred.");
else
callback(JSON.parse(this.response));
};
request.send();
}
function getSEWebServiceResponse(request, callback) {
let apiRoot = 'https://api.stackexchange.com/2.2/';
let key = 'key=s29XM)Eqn2x3YxhjLgFwBQ((';
if (request.indexOf('?') >= 0)
key = '&' + key;
else
key = '?' + key;
getWebServiceResponse(apiRoot + request + key, function(response) { callback(response); });
}
Here, the key is needed to help prevent throttling of too many subsequent requests:
Every application is subject to an IP based concurrent request throttle. If a single IP is making more than 30 requests a second, new requests will be dropped.
From here the implementation is pretty straight-forward and was a great learning process!
/users/{ids}
Gets the users identified in ids in {ids}.
Typically this method will be called to fetch user profiles when you have obtained user ids from some other source, such as /questions.
{ids} can contain up to 100 semicolon delimited ids.
function getAssociatedAccountDetails(userID, siteName, fullSiteName, callback) {
let url = 'users/' + userID +'?order=desc&sort=reputation&site=' + siteName;
getSEWebServiceResponse(url, function(response) {
if (!response.items)
return;
let account = response.items[0];
userCard.reputation += account.reputation;
userCard.badges.gold += account.badge_counts.gold;
userCard.badges.silver += account.badge_counts.silver;
userCard.badges.bronze += account.badge_counts.bronze;
if (userCard.siteUrls.length < 7) {
var siteProfileCombo = account.link + '|<IMG>|' + fullSiteName;
siteProfileCombo = siteProfileCombo.replace('<IMG>', getSiteIcon(siteName));
userCard.siteUrls.push(siteProfileCombo);
}
if (userCard.username.length < 1)
userCard.username = account.display_name;
if (userCard.profileImageUrl.length < 1)
userCard.profileImageUrl = account.profile_image;
callback();
});
}
/users/{ids}/associated
Returns all of a user's associated accounts, given their account_ids in {ids}.
{ids} can contain up to 100 semicolon delimited ids.
function getAssociatedAccounts(accountID, callback) {
let url = 'users/' + accountID + '/associated';
getSEWebServiceResponse(url, function(response) {
if (!response.items)
return;
var accounts = sortAccountsByReputation(response.items);
var accountsProcessed = 0;
for (let i = 0; i < accounts.length; i++) {
let siteName = accounts[i].site_url.replace('https://', '');
siteName = siteName.replace('.stackexchange', '');
siteName = siteName.replace('.com', '');
getAssociatedAccountDetails(accounts[i].user_id, siteName, accounts[i].site_name, function() {
if (++accountsProcessed >= accounts.length)
callback();
});
}
});
}
The Full Implementation
/* Definitions */
var CardType = { Wheel: "wheel", Card: "card", Box: "box" }
var userCard = {
username: '',
profileImageUrl: '',
reputation: 0,
badges: {
gold: 0,
silver: 0,
bronze: 0
},
siteUrls: []
}
/* Initial Calls */
var accountID = '13342919';
generateCard('user-flair-wheel', accountID, CardType.Wheel);
/* Required Events */
function showSitename(tooltipID, siteName) {
var tooltip = document.getElementById(tooltipID);
tooltip.innerHTML = siteName.replace('Stack Exchange', '');
tooltip.classList.add('active');
}
function hideSitename(tooltipID) {
document.getElementById(tooltipID).classList.remove('active');
}
/* UI Generation Functions */
function generateCard(containerid, accountid, cardType) {
getAssociatedAccounts(accountID, function() {
var className = cardType.toString().toLowerCase();
var container = document.getElementById(containerid);
container.classList.add("flair");
container.classList.add(className);
// Build the card.
addProfile(container);
addScores(container, className);
addSites(container, className);
container.innerHTML += '<div id="' + containerid +
'-tooltip" class="se-tooltip"></div>';
});
}
function addProfile(container) {
container.innerHTML += '<img class="user-image" src="' +
userCard.profileImageUrl + '"/>';
container.innerHTML += '<h1 class="username display-4">' +
userCard.username + '</h1>';
}
function addScores(container, cardType) {
var badges = '<ul class="badges">';
badges += '<li><i class="fas fa-trophy"></i> <span id="reputation-' +
cardType + '">' + userCard.reputation + '</span></li>';
badges += '<li><span id="gold-badges-' + cardType + '">' +
userCard.badges.gold + '</span></li>';
badges += '<li><span id="silver-badges-' + cardType + '">' +
userCard.badges.silver + '</span></li>';
badges += '<li><span id="bronze-badges-' + cardType + '">' +
userCard.badges.bronze + '</span></li>';
badges += '</ul>';
container.innerHTML += badges;
}
function addSites(container, cardType) {
var sites = '<ul id="sites-' + cardType + '" class="sites">';
for (var i = 0; i < userCard.siteUrls.length; i++) {
var site = '<li>';
var siteLinkSplit = userCard.siteUrls[i].split('|');
site += '<a href="' + siteLinkSplit[0] + '">';
var tooltipID = container.id +'-tooltip';
var linkElement = '<a href="' + siteLinkSplit[0] + '"';
linkElement += ' onmouseover="showSitename(\'' + tooltipID + '\',\'' + siteLinkSplit[2] + '\')"';
linkElement += ' onmouseout="hideSitename(\'' + tooltipID + '\');"';
site += linkElement + '>';
site += '<img src="' + (siteLinkSplit[1] == '<IMG>' ? '#' : siteLinkSplit[1]) + '"/></a></li>';
sites += site;
}
sites += '</ul>';
container.innerHTML += sites;
}
/* Stack Exchange API Based Functions */
function getAssociatedAccounts(accountID, callback) {
let url = 'users/' + accountID + '/associated';
getSEWebServiceResponse(url, function(response) {
if (!response.items)
return;
var accounts = sortAccountsByReputation(response.items);
var accountsProcessed = 0;
for (let i = 0; i < accounts.length; i++) {
let siteName = accounts[i].site_url.replace('https://', '');
siteName = siteName.replace('.stackexchange', '');
siteName = siteName.replace('.com', '');
getAssociatedAccountDetails(accounts[i].user_id, siteName, accounts[i].site_name, function() {
if (++accountsProcessed >= accounts.length)
callback();
});
}
});
}
function getAssociatedAccountDetails(userID, siteName, fullSiteName, callback) {
let url = 'users/' + userID +'?order=desc&sort=reputation&site=' + siteName;
getSEWebServiceResponse(url, function(response) {
if (!response.items)
return;
let account = response.items[0];
userCard.reputation += account.reputation;
userCard.badges.gold += account.badge_counts.gold;
userCard.badges.silver += account.badge_counts.silver;
userCard.badges.bronze += account.badge_counts.bronze;
if (userCard.siteUrls.length < 7) {
var siteProfileCombo = account.link + '|<IMG>|' + fullSiteName;
siteProfileCombo = siteProfileCombo.replace('<IMG>', getSiteIcon(siteName));
userCard.siteUrls.push(siteProfileCombo);
}
if (userCard.username.length < 1)
userCard.username = account.display_name;
if (userCard.profileImageUrl.length < 1)
userCard.profileImageUrl = account.profile_image;
callback();
});
}
/* Helper Functions */
function getSEWebServiceResponse(request, callback) {
let apiRoot = 'https://api.stackexchange.com/2.2/';
let key = 'key=s29XM)Eqn2x3YxhjLgFwBQ((';
if (request.indexOf('?') >= 0)
key = '&' + key;
else
key = '?' + key;
getWebServiceResponse(apiRoot + request + key, function(response) { callback(response); });
}
function getWebServiceResponse(requestUrl, callback) {
let request = new XMLHttpRequest();
request.open('GET', requestUrl, true);
request.onload = function() {
if (request.status < 200 || request.status >= 400)
callback("An unexpected error occurred.");
else
callback(JSON.parse(this.response));
};
request.send();
}
function sortAccountsByReputation(accounts) {
return accounts.sort(function(a, b) { return b.reputation - a.reputation; });
}
function getSiteIcon(siteName) {
if (siteName == "meta")
return 'https://meta.stackexchange.com/content/Sites/stackexchangemeta/img/icon-48.png';
return 'https://cdn.sstatic.net/Sites/' + siteName + '/img/apple-touch-icon.png';
}
/* Flair Styles */
.flair {
position: relative;
margin: 15px;
}
.flair > .se-tooltip {
position: absolute;
left: 50%;
transform: translate(-50%);
width: 250px;
bottom: 50px;
opacity: 0;
background-color: #fff;
color: #555;
text-shadow: none;
border-radius: 25px;
padding: 5px 10px;
box-shadow: 2px 2px 3px #0005;
}
.flair > .se-tooltip.active {
bottom: 10px;
opacity: 1;
}
/* Flair Wheel Styles */
.flair.wheel {
width: 200px;
height: 250px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
text-shadow: 1px 1px 2px #0005;
}
.flair.wheel .user-image {
width: 100px;
height: 100px;
border-radius: 50%;
box-shadow: 2px 2px 3px #0005;
}
.flair.wheel .username {
font-size: 30px;
margin: 0;
}
.flair.wheel .badges > li > span { position: relative; }
.flair.wheel .badges > li:first-of-type > i { color: #5c9; }
.flair.wheel .badges > li:not(:first-of-type) > span::before {
content: '';
position: absolute;
top: 50%;
left: -15px;
transform: translateY(-40%);
width: 10px;
height: 10px;
border-radius: 50%;
}
.flair.wheel .badges > li:nth-child(2) > span::before { background-color: #fb3; }
.flair.wheel .badges > li:nth-child(3) > span::before { background-color: #aaa; }
.flair.wheel .badges > li:nth-child(4) > span::before { background-color: #c95; }
.flair.wheel .sites {
position: absolute;
top: 10px;
left: 0;
width: 100%;
height: 55%;
}
.flair.wheel .sites > li { position: absolute; }
.flair.wheel .sites > li > a > img {
width: 35px;
height: 35px;
background-color: #fffa;
border-radius: 50%;
padding: 2px;
box-shadow: 2px 2px 3px #0005;
cursor: pointer;
transition: 0.3s cubic-bezier(0.5, -2.5, 1.0, 1.2) all;
z-index: 1;
}
.flair.wheel .sites > li > a:hover > img {
width: 40px;
height: 40px;
background-color: #fff;
}
.flair.wheel .sites > li:nth-child(1) {
top: -15px;
left: 50%;
transform: translate(-50%);
}
.flair.wheel .sites > li:nth-child(2) {
top: 0px;
left: 15%;
transform: translate(-20%);
}
.flair.wheel .sites > li:nth-child(3) {
top: 0px;
left: 70%;
transform: translate(-20%);
}
.flair.wheel .sites > li:nth-child(4) {
top: 45%;
left: 80%;
transform: translate(-20%, -50%);
}
.flair.wheel .sites > li:nth-child(5) {
top: 45%;
left: -5px;
transform: translateY(-50%);
}
.flair.wheel .sites > li:nth-child(6) {
top: 79%;
left: 3px;
transform: translateY(-50%);
}
.flair.wheel .sites > li:nth-child(7) {
top: 79%;
right: 3px;
transform: translateY(-50%);
}
/* To Organize in a Row instead of Column */
.user-flair-container {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
/* Global Styles */
ul {
padding: 0;
listy-style-type: none;
}
ul > li {
display: inline-block;
padding: 0 10px;
}
/* Template Overrides */
html, body {
margin: 0;
height: 100%;
background-color: #333 !important;
background-image: linear-gradient(45deg, #333, #555) !important;
background-image: -webkit-linear-gradient(45deg, #333, #555) !important;
}
.primary-content {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.primary-content > .lead { font-size: 25px; }
<link href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/2940219/PerpetualJ.css" rel="stylesheet"/>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" rel="stylesheet"/>
<div id="primary-content" class="primary-content">
<div class="user-flair-container">
<div id="user-flair-wheel"></div>
</div>
</div>
Best of luck to all of you in your future endeavors!

Related

How to search movies via actor's name? (TMDB)

I'm creating a web site dedicated to find films as convenient as possible, using TMDB service. Currently, I'm trying to make a search, using just an actor's name. I've learned a lot about TMDB and all its features. Eventually, I've created code that should have found movies starring with entered actor, yet it doesn't. Moreover, when I type any actor's name, I just see an option of film, which is 'Undefined' (sometimes there are two films). I'll attach my code and I'd be more than grateful for any suggestions or explanations of people, who already had their own experience with TMDB. Thanks for time spent for reading this article. Have a good day!
HTML:
<div class="actor-form" id="actorForm">
<input type="text" class="actor-form-input" placeholder="Desired Actor:" name="name" id='actorNameInput'
autocomplete="off">
<label for="actorNameInput" class="actor-form-label">
<span class="actor-form-span">Desired Actor</span>
</label>
</div>
<main id="main"></main>
CSS:
.actor-form {
position: absolute;
padding: 10px 0 0 0;
width: 40%;
left: 50%;
top: 35%;
transform: translate(500%, -50%);
transition: all 2s;
cursor: default;
}
.actor-form-input {
font-family: 'Marvel', sans-serif;
width: 100%;
border: 0;
border-bottom: 2px solid #202020;
outline: 0;
font-size: 26px;
color: #202020;
padding: 7px 0;
background: transparent;
transition: border-color 0.4s;
}
.actor-form-input::placeholder {
color: transparent;
}
.actor-form-input:placeholder-shown+.actor-form-label {
font-size: 26px;
cursor: text;
top: 20px;
}
.actor-form-label {
position: absolute;
top: -20px;
display: block;
transition: 0.2s;
color: #202020;
font-size: 24px;
font-family: 'Marvel', sans-serif;
}
.actor-form-input:focus+.actor-form-label {
position: absolute;
top: -20px;
display: block;
transition: 0.2s;
color: #21ebff;
font-size: 24px;
}
.actor-form-input:focus {
border-bottom: 2px solid #21ebff;
}
.actor-form-span {
-webkit-user-select: none;
user-select: none;
}
JS:
// Show Movies
const API_KEY = 'api_key= [here is my apikey]';
const BASE_URL = 'https://api.themoviedb.org/3';
const API_URL = BASE_URL + '/discover/movie?sort_by=popularity.desc&' + API_KEY;
const IMG_URL = 'https://image.tmdb.org/t/p/w500';
const searchURL = BASE_URL + '/search/movie?' + API_KEY;
const searchPersonURL = BASE_URL + '/search/person?' + API_KEY;
getMovies(API_URL);
function getMovies(url) {
lastUrl = url;
fetch(url).then(res => res.json()).then(data => {
if (data.results.length !== 0) {
showMovies(data.results);
currentPage = data.page;
nextPage = currentPage + 1;
prevPage = currentPage - 1;
totalPages = data.total_pages;
current.innerText = currentPage;
if (currentPage <= 1) {
prev.classList.add('disabled');
next.classList.remove('disabled')
} else if (currentPage >= totalPages) {
prev.classList.remove('disabled');
next.classList.add('disabled')
} else {
prev.classList.remove('disabled');
next.classList.remove('disabled')
}
tagsEl.scrollIntoView({ behavior: 'smooth' })
} else {
main.innerHTML = `<h1 class="no-results">No Results Found</h1>`
}
})
}
function showMovies(data) {
main.innerHTML = '';
data.forEach(movie => {
const { title, poster_path, vote_average, overview, id } = movie;
const movieEl = document.createElement('div');
movieEl.classList.add('movie');
movieEl.innerHTML = `
<img src="${poster_path ? IMG_URL + poster_path : "http://via.placeholder.com/1080x1580"}" alt="${title}">
<div class="movie-info">
<h3>${title}</h3>
</div>
<div class="overview">
<h3>Overview</h3>
${overview}
<br/>
<button class="know-more" id="${id}">Know More</button
</div>
`
main.appendChild(movieEl);
document.getElementById(id).addEventListener('click', () => {
console.log(id)
openNav(movie)
})
})
}
// Actor Form
const actorFormLabel = document.querySelector('.actor-form-label');
const actorNameInput = document.getElementById('actorNameInput');
actorNameInput.addEventListener('input', function (e) {
let val = e.target.value.trim();
if (val.length) {
getMovies(searchPersonURL + '&query=' + encodeURI(val));
console.log(encodeURI(val));
}
});

Html into wordpress theme

I need to make a fixed bottom footer to my WordPress web, with some buttons including js with a popover. I've Pillar Theme and I only need to make this change. I need to put it into my footer.php. But when I try, nothing works. I do not know if this is the best way to do that. Here is the code that I do for the footer:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<!-- Styles just for demo -->
<style>
#font-face {
font-family: 'social-icons';
font-weight: normal;
font-style: normal;
src: url('font/social.eot?44259375');
src: url('font/social.eot?44259375#iefix') format('embedded-opentype'), url('font/social.woff?44259375') format('woff'), url('font/social.ttf?44259375') format('truetype'), url('font/social.svg?44259375#social') format('svg');
}
/* Share button
***********************************************/
.need-share-button {
position: relative;
display: inline-block;
}
.need-share-button_dropdown {
position: absolute;
z-index: 10;
visibility: hidden;
overflow: hidden;
width: 240px;
-webkit-transition: .3s;
transition: .3s;
-webkit-transform: scale(.1);
-ms-transform: scale(.1);
transform: scale(.1);
text-align: center;
opacity: 0;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.need-share-button-opened .need-share-button_dropdown {
visibility: visible;
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
opacity: 1;
}
.need-share-button_link {
display: inline-block;
width: 40px;
height: 40px;
line-height: 40px;
cursor: pointer;
text-align: center;
}
.need-share-button_link:after {
font: normal normal normal 16px/1 'social-icons';
text-align: center;
text-transform: none;
speak: none;
}
.need-share-button_link:hover {
-webkit-transition: .3s;
transition: .3s;
opacity: .7;
}
/* Dropdown position
***********************************************/
.need-share-button_dropdown-top-center {
bottom: 100%;
left: 50%;
margin-bottom: 10px;
}
/* Default theme
***********************************************/
.need-share-button-default .need-share-button_button {
display: inline-block;
margin-bottom: 0;
padding: 20px;
font-size: 14px;
line-height: 1.42857143;
font-weight: 400;
color: white;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-align: center;
vertical-align: middle;
white-space: nowrap;
background-image: url("share.png") no-repeat;
}
.need-share-button-default .need-share-button_button span {
background-image: url("share.png") no-repeat;
}
.need-share-button-default .need-share-button_button:hover {
color: #737373;
}
/* Network buttons
***********************************************/
.need-share-button_mailto {
color: #efbe00;
}
.need-share-button_mailto:after {
content: '\e80a';
}
.need-share-button_mailto.need-share-button_link-box {
color: #fff;
background: #efbe00;
}
.need-share-button_twitter {
color: #00acec;
}
.need-share-button_twitter:after {
content: '\e813';
}
.need-share-button_twitter.need-share-button_link-box {
color: #fff;
background: #00acec;
}
.need-share-button_facebook {
color: #3b5998;
}
.need-share-button_facebook:after {
content: '\e80e';
}
.need-share-button_facebook.need-share-button_link-box {
color: #fff;
background: #3b5998;
}
.wrapper {
text-align: center;
}
footer {
background-color: black;
position: fixed;
bottom: 0;
width: 100%;
left: 0;
height: 60px;
}
footer .col-sm {
text-align: center;
}
a {
color: white;
text-decoration: none;
}
footer .col-sm > span {
padding: 7px 0 0px;
display: inline-block;
}
footer .col-sm > span > a:hover {
color: #737373;
text-decoration: none;
}
#homefooter a{
background-image: url("home.png");
background-repeat: no-repeat;
padding-bottom: 35px;
}
#donarfooter a {
background-image: url("donar.png");
background-repeat: no-repeat;
padding-bottom: 35px;
}
footer a span {
visibility: hidden;
}
/* ------------------------------------ MEDIA QUERIES -------------------------------------------*/
#media (max-width: 900px){
footer .col-sm {
width: 25%;
}
footer span {
padding: 0 !important;
}
}
/* ------------------------------------ MEDIA QUERIES -------------------------------------------*/
/* ------------------------------------ SEARCH STYLES -------------------------------------------*/
* {
box-sizing: border-box;
}
.openBtn {
background: #f1f1f1;
border: none;
padding: 10px 15px;
font-size: 20px;
cursor: pointer;
}
.openBtn:hover {
background: #bbb;
}
.overlay {
height: 100%;
width: 100%;
display: none;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0, 0.9);
}
.overlay-content {
position: relative;
top: 46%;
width: 80%;
text-align: center;
margin-top: 30px;
margin: auto;
}
.overlay .closebtn {
position: absolute;
top: 20px;
right: 45px;
font-size: 60px;
cursor: pointer;
color: white;
}
.overlay .closebtn:hover {
color: #ccc;
}
.overlay input[type=text] {
padding: 15px;
font-size: 17px;
border: none;
float: left;
width: 80%;
background: white;
}
.overlay input[type=text]:hover {
background: #f1f1f1;
}
.overlay button {
float: left;
width: 20%;
padding: 15px;
background: #ddd;
font-size: 17px;
border: none;
cursor: pointer;
}
.overlay button:hover {
background: #bbb;
}
/* ------------------------------------ SEARCH STYLES -------------------------------------------*/
</style>
</head>
<body>
<section>
<div id="myOverlay" class="overlay">
<span class="closebtn" onclick="closeSearch()" title="Close Overlay">×</span>
<div class="overlay-content">
<form action="/action_page.php">
<input type="text" placeholder="Search.." name="search">
<button type="submit"><i class="fa fa-search"></i></button>
</form>
</div>
</div>
</section>
<footer class="fixed-bottom">
<div class="container-fluid" style="height: 100%">
<div class="row" style="height: 100%">
<div class="col-sm" id="homefooter">
<span>
<span>HOME</span>
</span>
</div>
<div class="col-sm" style="height: 100%; border-left: solid 0.5px white; border-right: solid 0.5px white">
<div class="wrapper">
<img src="share.png">
<div id="share-button-2" class="need-share-button-default" data-share-position="topCenter" data-share-icon-style="box" data-share-networks="Mailto,Twitter,Facebook"></div>
</div>
</div>
<div class="col-sm" id="donarfooter">
<span>
<span>CONTRIBUIR</span>
</span>
</div>
<div class="col-sm" id="donarfooter">
<span>
<button class="openBtn" onclick="openSearch()">BUSCAR</button>
</span>
</div>
</div>
</div>
</footer>
<script>
/***********************************************
needShareButton
- Version 1.0.0
- Copyright 2015 Dzmitry Vasileuski
- Licensed under MIT (http://opensource.org/licenses/MIT)
***********************************************/
(function() {
// share dropdown class
window.needShareDropdown = function(elem, options) {
// create element reference
var root = this;
root.elem = elem;
root.elem.className += root.elem.className.length ? ' need-share-button' : 'need-share-button';
/* Helpers
***********************************************/
// get title from html
root.getTitle = function() {
var content;
// check querySelector existance for old browsers
if (document.querySelector) {
if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
return content.getAttribute('content');
} else if (content = document.querySelector('title')) {
return content.innerText;
} else
return '';
} else {
if (content = document.title)
return content.innerText;
else
return '';
}
};
// get image from html
root.getImage = function() {
var content;
// check querySelector existance for old browsers
if (document.querySelector) {
if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
return content.getAttribute('content');
} else
return '';
} else
return '';
};
// get description from html
root.getDescription = function() {
var content;
// check querySelector existance for old browsers
if (document.querySelector) {
if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
return content.getAttribute('content');
} else
return '';
} else {
if (content = document.getElementsByTagName('meta').namedItem('description'))
return content.getAttribute('content');
else
return '';
}
};
// share urls for all networks
root.share = {
'mailto' : function() {
var url = 'mailto:?subject=' + encodeURIComponent(root.options.title) + '&body=Thought you might enjoy reading this: ' + encodeURIComponent(root.options.url) + ' - ' + encodeURIComponent(root.options.description);
window.location.href = url;
},
'twitter' : function() {
var url = root.options.protocol + 'twitter.com/home?status=';
url += encodeURIComponent(root.options.title) + encodeURIComponent(root.options.url);
root.popup(url);
},
'facebook' : function() {
var url = root.options.protocol + 'www.facebook.com/sharer/share.php?';
url += 'u=' + encodeURIComponent(root.options.url);
url += '&title=' + encodeURIComponent(root.options.title);
root.popup(url);
},
}
// open share link in a popup
root.popup = function(url) {
// set left and top position
var popupWidth = 500,
popupHeight = 400,
// fix dual screen mode
dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : screen.left,
dualScreenTop = window.screenTop != undefined ? window.screenTop : screen.top,
width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width,
height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height,
// calculate top and left position
left = ((width / 2) - (popupWidth / 2)) + dualScreenLeft,
top = ((height / 2) - (popupHeight / 2)) + dualScreenTop,
// show popup
shareWindow = window.open(url,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=' + popupWidth + ', height=' + popupHeight + ', top=' + top + ', left=' + left);
// Puts focus on the newWindow
if (window.focus) {
shareWindow.focus();
}
}
/* Set options
***********************************************/
// create default options
root.options = {
shareButtonClass: false, // child selector of custom share button
iconStyle: 'default', // default or box
boxForm: 'horizontal', // horizontal or vertical
position: 'bottomCenter', // top / middle / bottom + Left / Center / Right
buttonText: 'COMPARTIR',
protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
url: window.location.href,
title: root.getTitle(),
image: root.getImage(),
description: root.getDescription(),
networks: 'Mailto,Twitter,Facebook'
}
// integrate data attribute options
for (var option in root.elem.dataset) {
// replace only 'share-' prefixed data-attributes
if (option.match(/share/)) {
var new_option = option.replace(/share/, '');
if (!new_option.length) {
continue;
}
new_option = new_option.charAt(0).toLowerCase() + new_option.slice(1);
root.options[new_option] = root.elem.dataset[option];
}
}
// convert networks string into array
root.options.networks = root.options.networks.toLowerCase().split(',');
/* Create layout
***********************************************/
// create dropdown button if not exists
if (root.options.shareButtonClass) {
for (var i = 0; i < root.elem.children.length; i++) {
if (root.elem.children[i].className.match(root.options.shareButtonClass))
root.button = root.elem.children[i];
}
}
if (!root.button) {
root.button = document.createElement('span');
root.button.innerText = root.options.buttonText;
root.elem.appendChild(root.button);
}
root.button.className += ' need-share-button_button';
// show and hide dropdown
root.button.addEventListener('click', function(event) {
event.preventDefault();
if (!root.elem.className.match(/need-share-button-opened/)) {
root.elem.className += ' need-share-button-opened';
} else {
root.elem.className = root.elem.className.replace(/\s*need-share-button-opened/g,'');
}
});
// create dropdown
root.dropdown = document.createElement('span');
root.dropdown.className = 'need-share-button_dropdown';
root.elem.appendChild(root.dropdown);
// set dropdown position
setTimeout(function() {
switch (root.options.position) {
case 'topCenter':
root.dropdown.className += ' need-share-button_dropdown-top-center';
root.dropdown.style.marginLeft = - root.dropdown.offsetWidth / 2 + 'px';
break
}
},1);
// fill fropdown with buttons
var iconClass = root.options.iconStyle == 'default' ? 'need-share-button_link need-share-button_' : 'need-share-button_link-' + root.options.iconStyle + ' need-share-button_link need-share-button_';
for (var network in root.options.networks) {
var link = document.createElement('span');
network = root.options.networks[network];
link.className = iconClass + network;
link.dataset.network = network;
root.dropdown.appendChild(link);
// add share function to event listener
link.addEventListener('click', function() {
root.share[this.dataset.network]();
});
}
}
})();
</script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script>
new needShareDropdown(document.getElementById('share-button-2'));
</script>
<script>
function openSearch() {
document.getElementById("myOverlay").style.display = "block";
}
function closeSearch() {
document.getElementById("myOverlay").style.display = "none";
}
</script>
</body>
</html>
You can try Sticky footer with jQuery. Add this code in your js file.
var $ = jQuery.noConflict();
jQuery(document).ready(function($){
/* sticky footer function */
StickyFooter()
});
/* Script on resize */
jQuery(window).resize(function($) {
/* sticky footer function */
StickyFooter();
});
/* Script on load
----------------------------------*/
jQuery(window).load(function($) {
/* sticky footer function */
StickyFooter();
});
/* Sticky Footer Function */
function StickyFooter(){
var Stickyfooter = jQuery( 'footer' ).outerHeight()
jQuery('#wrapper').css('margin-bottom',-Stickyfooter) /* Here #wrapper is your main <div> of <body> */
jQuery('#wrapper').css('padding-bottom',Stickyfooter)
}

js object value change on click in localStorage

I have object, in that object there is this array:
[
{
"title": "Title1",
"status": false
},
{
"title": "Title2",
"status": false
}
]
and when I press the a tag, I want to change element's status from false to true and move it from "Tasks" section to "Done" section. Like this.
But in changeStatus function I'm getting error:
Uncaught TypeError: Cannot set property 'status' of undefined
at changeStatus (script.js:116)
at HTMLAnchorElement.onclick (?new-task=Task1:1)
How could I change my element's status on the click?
var tasks = {};
var element = {};
var tasksList;
var index;
Date.shortMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
function short_months(dt) {
return Date.shortMonths[dt.getMonth()];
}
function taskList() {
var today = new Date();
var full_date = short_months(today) + " " + today.getDate() + " " + today.getYear();
element["title"] = document.getElementById('new-task').value;
element["status"] = false;
element["date"] = full_date;
var oldItems = JSON.parse(localStorage.getItem('tasksAll')) || [];
oldItems.push(element);
localStorage.setItem('tasksAll', JSON.stringify(oldItems));
updateData();
}
function updateData() {
var retrievedData = localStorage.getItem("tasksAll");
tasksList = JSON.parse(retrievedData);
var htmlNotDone = "";
var htmlDone = "";
var falseCount = 0;
for (index = 0; index < tasksList.length; index++) {
if (tasksList[index].status === false) {
falseCount++;
htmlNotDone += '<div class="task-element">';
htmlNotDone += '<div class="task-left-element"><p>' + tasksList[index].date + '</p><h4>' + tasksList[index].title + tasksList[index].status + '</h4></div>';
htmlNotDone += '<div class="task-right-element">';
htmlNotDone += '<span class="checkmark"><div class="checkmark_stem"></div><div class="checkmark_kick"></div></span>';
htmlNotDone += '</div>';
htmlNotDone += '</div>';
} else {
htmlDone = htmlDone + tasksList[index].title;
}
}
if (htmlNotDone === "") {
document.getElementById("task-list").innerHTML = "Nothing";
} else {
document.getElementById("task-list").innerHTML = htmlNotDone;
}
if (htmlDone === "") {
document.getElementById("done-task-count").innerHTML = "Nothing";
} else {
document.getElementById("done-task-count").innerHTML = htmlDone;
}
}
function changeStatus(index) {
tasksList[index].status = true;
}
updateData();
#font-face {
font-family: font-Heavy;
src: url(fonts/Aileron-Heavy.otf);
}
#font-face {
font-family: font-Bold;
src: url(fonts/Aileron-Bold.otf);
}
#font-face {
font-family: font-Light;
src: url(fonts/Aileron-Light.otf);
}
#font-face {
font-family: font-Regular;
src: url(fonts/Aileron-Regular.otf);
}
body {
background-color: #e5e5e5;
}
.container {
position: fixed;
left: 40%;
top: 10%;
transform: translate(-40%, -10%);
width: 80%;
background-color: #f7f9fa;
}
.container .content {
margin-left: 25%;
margin-right: 25%;
}
.container .content h1 {
font-family: font-Heavy;
color: #2f80ed;
}
.content form input[type=text] {
font-family: font-Regular;
padding-left: 15px;
min-height: 60px;
width: 100%;
border: 1px solid #e0e0e0;
border-radius: 3px;
box-shadow: inset 0px 0px 10px #e0e0e0;
}
::placeholder {
color: #929292;
}
.content .undone-task h3,
.content .done-task h3 {
font-family: font-Bold;
color: #828282;
}
.content .task-element {
border: 1px solid #e5e6e7;
border-radius: 3px;
box-shadow: 0px 10px 18px #e5e6e7;
margin-bottom: 20px;
min-height: 60px;
}
.task-element p {
font-family: font-Light;
color: #c5c5c5;
margin-bottom: 0;
font-size: 12px;
}
.task-element h4 {
font-family: font-Light;
color: #828282;
margin-top: 0px;
margin-bottom: 15px;
}
.task-element .task-left-element {
float: left;
margin-left: 15px;
}
.task-element .task-rigth-element {
margin-right: 10px;
float: right;
}
.checkmark {
float: right;
margin-right: 10px;
margin-top: 3%;
display: inline-block;
width: 22px;
height: 22px;
-ms-transform: rotate(45deg);
/* IE 9 */
-webkit-transform: rotate(45deg);
/* Chrome, Safari, Opera */
transform: rotate(45deg);
}
.checkmark_stem {
position: absolute;
width: 3px;
height: 9px;
background-color: #ccc;
left: 11px;
top: 6px;
}
.checkmark_kick {
position: absolute;
width: 3px;
height: 3px;
background-color: #ccc;
left: 8px;
top: 12px;
}
.checkmark:hover .checkmark_stem,
.checkmark:hover .checkmark_kick {
background-color: #6fcf97;
}
<div class="container">
<div class="content">
<h1>To-do</h1>
<form name="taskForm" onsubmit="taskList();return false">
<input type="text" name="new-task" id="new-task" placeholder="Task title">
<input type="submit" style="visibility: hidden;" />
</form>
<div class="undone-task">
<h3>Tasks</h3><span id="task-count"></span>
<div id="task-list"></div>
</div>
<div class="done-task">
<h3>Done</h3><span id="done-task-count"></span>
<div id="done-task-list"></div>
</div>
</div>
</div>
Well first of all...
You shouldn't generate HTML with JavaScript but instead use DOM queries to add/edit DOM children, for this purpose, you should learn how to use a library, like jQuery or vue.js.
Second of all, you shouldn't use onclick html attributes, but eventlisteners instead, this is usually handled by the library or framework..
Third, you're using index as a string, not as the variable, so of course it will try to use the global variable index which will be executed, way after the index loop is. So you should learn about lexical scope and variable management.
In order to solve your problem, replace onclick="changeStatus(index);" with onclick="changeStatus('+index+');" and it should work..

how to make a div return to starting point when the div slides to end

I'm trying to make am image scroll that uses control button and also slides automatically, my problem now is I need to know how to return the div to starting point when the div hit end on left side or on right side, what I could get so far is to know when the div hit an end but don't know how to return it to starting point in case of automatic sliding.
var n = 3; //total number of slides to be display at once
var totalDeal = 9; //total deals to be display
var sliderTotalWidth = 100; //in percentage append % later
var z = (100 / totalDeal) + '%'; //ddslides width
var x = totalDeal / n;
var counter = 1;
$(".dialyDealSlider").css('width', x + '00%');
//$(".ddslides").css('width', ddslidesWidth);
fillDailyDeal(totalDeal, z);
function fillDailyDeal(totalDeal, z) {
var imgUrl = '{$img}';
var ext = '.jpg';
var width = "width:" + z
for (var i = 1; i <= totalDeal; i++) {
var myDiv = $(
"<div class='ddslides' style='" + width + "' >" +
'<div class="dddesc">' +
'<div class="ddtitle">' +
'The is the title of the item it\'s a long title' +
'</div>' +
"<div class='ddprice'>$"+i+"00</div>" +
'<button class="ddview" title="View Item">view item</button>' +
'</div>' +
'<div class="ddimg">' +
'</div>' +
'<div class="vDivider"></div>' +
'<div class="ddSaleBadge">sold 44%</div>' +
'</div>');
$("#dialyDealSlider").append(myDiv);
}
}
$("#prev, #next").click(function() {
if (this.id == "next") {
counter++;
} else {
counter--;
}
//console.log(counter);
if (counter == x) {
alert('rigth end');
//$("#dialyDealSlider").css('left', '0px');
}
if (counter == 1) {
alert('left end');
}
var ddslidesWidth = $(".ddslides").width();
var dir = this.id == "next" ? '-=' : '+=';
var width = ddslidesWidth * n;
//alert(leftpos);
$("#dialyDealSlider").animate({
left: dir + width
}, 800);
});
my code is here JSFIDDLE: https://jsfiddle.net/sammyzeal/LqpL1n2g/
As we can see in the above fiddle, when we slide the div and the price is between $700 and $900 we hit an end then there's an alert, on this point if a user keeps on clicking this next button how do I scroll to the starting point which is between price $100 and $300, I hope my question is cleared and thanks in advance for any help
I just saw that you updated the code as i said , good work. So i wont hesitate to help now, you should make a separate slideNow() function that slides next or previous and you should increment/decrement the counter after checking the current or previous slides, if it is the last slide create a function separate to goToStart() to move to the first slide and if it is th first slide just return from there and do nothing, you can use the following script and test it with various combinations like, first going to the last slide by clicking and then on the last slide click next and see if it goes to the first on and then try clicking left from the first slide and verify if it goes left or stays still.
See a demo below
var n = 3; //total number of slides to be display at once
var totalDeal = 9; //total deals to be display
var sliderTotalWidth = 100; //in percentage append % later
var z = (100 / totalDeal) + '%'; //ddslides width
var x = totalDeal / n;
var counter = 1;
$(".dialyDealSlider").css('width', x + '00%');
//$(".ddslides").css('width', ddslidesWidth);
fillDailyDeal(totalDeal, z);
function fillDailyDeal(totalDeal, z) {
var imgUrl = '{$img}';
var ext = '.jpg';
var width = "width:" + z
for (var i = 1; i <= totalDeal; i++) {
var myDiv = $(
"<div class='ddslides' style='" + width + "' >" +
'<div class="dddesc">' +
'<div class="ddtitle">' +
'The is the title of the item it\'s a long title' +
'</div>' +
"<div class='ddprice'>$" + i + "00</div>" +
'<button class="ddview" title="View Item">view item</button>' +
'</div>' +
'<div class="ddimg">' +
'</div>' +
'<div class="vDivider"></div>' +
'<div class="ddSaleBadge">sold 44%</div>' +
'</div>');
$("#dialyDealSlider").append(myDiv);
}
}
$("#prev, #next").click(function() {
var target = this.id;
//console.log(counter);
if (counter == x && target == "next") {
counter = 1;
goToStart();
return;
}
if (counter == 1 && target == "prev") {
return;
}
if (target == "next") {
counter++;
} else {
counter--;
}
//slide the slides
slideNow(target, n);
});
function goToStart() {
$("#dialyDealSlider").animate({
left: 0
}, 800);
}
function slideNow(target, n) {
var ddslidesWidth = $(".ddslides").width();
var dir = target == "next" ? '-=' : '+=';
var width = ddslidesWidth * n;
//alert(leftpos);
$("#dialyDealSlider").animate({
left: dir + width
}, 800);
}
.dailyDeal {
height: 150px;
width: 100%;
margin-top: 15px;
padding: 0 !important;
}
.dialyDealBox {
float: left;
height: 150px;
padding: 0 !important;
overflow: hidden;
}
.dialyDealSlider {
width: 100%;
height: 150px;
position: absolute;
border: 1px solid #ddd;
}
.ddslides {
height: 150px;
width: 2%;
float: left;
background-color: #fff;
position: relative;
padding: 10px 0;
}
#media only screen and (max-width: 768px) {
.ddslides {
width: 16.66%;
}
}
#media (max-width:320px) {
.ddslides {
width: 33.33%;
}
}
.ddimg {
float: left;
margin: auto;
height: 100%;
width: 32%;
margin-right: 4px;
}
.ddimg>a>img {
height: 100%;
width: 100%;
}
.dddesc {
float: left;
margin: auto;
height: 100%;
width: 65%;
padding: 0 10px 0 15px;
}
.ddSaleBadge {
position: absolute;
top: 5px;
right: 5px;
width: 37px;
height: 38px;
padding: 5px 2px 4px 3px;
overflow: hidden;
background: url("/trobay/img/icon/label.png") no-repeat 50% 50%;
line-height: 14px;
text-align: center;
color: #fff;
}
.ddtitle {
margin-bottom: 10px;
}
.ddtitle>a {
font-size: 14px;
color: #666666;
text-decoration: none;
}
.ddtitle>a:hover {
color: #e4393c;
text-decoration: none;
}
.ddprice {
color: #e4393c;
font-size: 16px;
margin-bottom: 10px;
}
.ddview {
color: #fff;
background-color: #e4393c;
font-size: 14px;
border: 0;
outline: 0;
padding: 4px;
font-weight: bold;
}
.ddslider-prev {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 5px;
color: #666666;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
left: 0;
z-index: 10;
background-color: rgba(221, 221, 221, 1);
display: block;
}
.ddslider-next {
cursor: pointer;
position: absolute;
right: 0;
top: 50%;
width: auto;
margin-top: -22px;
padding: 5px;
color: #666666;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
z-index: 10;
background-color: rgba(221, 221, 221, 1);
display: block;
}
.vDivider {
height: 130px;
border-right: 1px dotted #666;
position: absolute;
top: 10px;
;
right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div class="dailyDeal col-md-12">
<div class="dialyDealBox col-xs-10" id="dialyDealBox">
<div class="dialyDealSlider" id="dialyDealSlider">
</div>
<div class="ddslider-prev" id="prev">❮</div>
<div class="ddslider-next" id="next">❯</div>
</div>
</div>
</div>

Underline slide transition in buttons

I tried to search for tutorials on this effect. The effect that I wanted is an active underline (or border-bottom) under a link. When I click on a link, the underline will slide over to the next link and so on... One example is this question.
I know that what I have in html are buttons, not nav menu. So the coding would be different. I'm thinking that I might need to convert the buttons to nav menu if it doesn't work out.
Anyway, the problem is that I did try to use the example mentioned above to make the underline move to a clinked link. But it's not working...
Here's my code which is on codepen.
$(document).ready(function() {
$(".con-button").click(function(){
if(this.id == "c-all") {
$(".con-button").removeClass("active");
$("#c-all").addClass("active");
$('.offline').hide();
$('.offline').fadeIn("slow").show();
$('.online').hide();
$('.online').fadeIn("slow").show();
$('.none').fadeIn("slow").show();
} else if (this.id == "c-online") {
$(".con-button").removeClass("active");
$("#c-online").addClass("active");
$('.offline').hide();
$('.online').hide();
$('.online').fadeIn("slow").show();
$('.none').hide();
} else if (this.id == "c-offline") {
$(".con-button").removeClass("active");
$("#c-offline").addClass("active");
$('.offline').hide();
$('.offline').fadeIn("slow").show();
$('.online').hide();
$('.none').hide();
}
})
getSteams();
});
var channels = ["BasicallyIDoWrk", "FreeCodeCamp", "Golgothus", "maatukka", "Vinesauce", "brunofin", "comster404", "OgamingSC2"];
var cb = "?client_id=egn4k1eja0yterrcuu411n5e329rd3&callback=?";
function getSteams() {
channels.forEach(function(indchannel) {
//for (var channel in channels) {
//var indchannel = channel;
var streamURL = "https://api.twitch.tv/kraken/streams/" + indchannel + cb;
var channelURL = "https://api.twitch.tv/kraken/channels/" + indchannel + cb;
$.ajax({
url: streamURL,
type: 'GET',
dataType: "jsonp",
data: {
//action: 'query',
format: 'json',
},
headers: {
"Accept": "application/vnd.twitchtv.v5+json",
},
success: function(data) {
var game;
var status;
if(data.stream === null) {
$.getJSON(data._links.channel + "/?client_id=egn4k1eja0yterrcuu411n5e329rd3&callback=?", function(data2) {
if(data2.status == 404) {
game = "The Account doesn't exist";
status = "none";
} else {
game = "Offline";
status = "offline";
}
$("#offline").append('<div class="indbox ' + status + '"><a target="_blank" href="#">'+ indchannel + '<br/>' + game +'</a></div>');
} );
} else {
game = data.stream.game;
status = "online";
$("#online").append('<div class="indbox ' + status + '"><a target="_blank" href="#">'+ indchannel + '<br/>' + game +'</a></div>');
};
}
});
});
}
html, body{
height:100%;
margin: 0;
background-color: #ffffff;
}
.wrapper {
text-align: center;
position: relative;
width: 100%;
height: 100%;
display:block;
}
.container {
width: 75%;
margin: 30px auto 0;
position: relative;
}
.logobox img {
width: 20%;
margin: 0 auto;
}
.controls {
position: relative;
width: 100%;
}
.con-button {
position: relative;
background-color: white;
border: none;
margin: 0.5em 0 0 0;
padding: 0.5em 1em 0.5em 1em;
text-align: center;
color: rgb(100,65,164);
font-size: 20px;
transition: .4s;
}
.con-button:hover {
cursor: pointer;
/*border-bottom: 3px solid rgba(224, 217, 236, 1);*/
}
.con-button:focus {outline: 0;}
.effect {
position: absolute;
left: 0;
transition: 0.4s ease-in-out;
}
.controls .effect {
/*border-bottom: 3px solid rgba(100, 65, 164, 1);*/
height: 2px;
bottom: 5px;
background: #6441A4;
margin-left:/*-45px*/auto;
margin-right:/*-45px*/auto;
width: 33%;
}
button:nth-child(1).active ~ .effect {left: 0%;}
button:nth-child(2).active ~ .effect {left: 33%;}
button:nth-child(3).active ~ .effect {left: 66%;}
.divider hr {
border-top: 1px solid #6441A4;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="container">
<div class="twitchtvarea">
<div class="logobox">
<img src="https://s6.postimg.org/bay7stotd/Twitch_Purple_RGB.png" />
</div>
<div class="twitchbox">
<div class="controls">
<button id="c-all" class="con-button active" type="button">All</button>
<button id="c-online" class="con-button" type="button">Online</button>
<button id="c-offline" class="con-button" type="button">Offline</button>
</div>
<div class="divider"><hr></div>
<div id="online"></div>
<div id="offline"></div>
</div>
</div>
</div>
</div>
I made sure that .active is working in Javascript but I still need help making the underline moving from one link to another when clicked. All I know is that it has something to do with the CSS. Any help or tutorials are appreciated.
You can use this simple technique if you can use jQuery. It is quite generic and you can use any html elements whether nav, buttons or simple div's. You just need to have an outer element that contains all your links.
The idea is to find the position and width of the clicked anchor tag and then apply the same(or after adding some modification) to the underline element. To make its movement smooth you can add transition for left and width properties of this underline element.
$("#outer-container a").on("click", function(e){
e.preventDefault();
var cssObj = {};
cssObj.left = $(this).position().left;
cssObj.width = $(this).outerWidth();
$("#outer-container #underline").css( cssObj );
});//a click()
$("#outer-container a").eq(0).trigger("click");
#outer-container
{
text-align: center;
position: relative;
}
#outer-container a
{
color: #333;
display: inline-block;
padding: 0 10px;
text-decoration: none;
}
#outer-container #underline
{
content: "";
display: block;
position: absolute;
bottom: 0;
left: 0;
height: 2px;
width: 100px;
background-color: #333;
transition: left 0.3s ease, width 0.3s ease;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="outer-container">
One
Two
Three
Four
<span id="underline"></span>
</div><!--#outer-container-->
Checkout this,
$(document).ready(function() {
$(".con-button").click(function(){
if(this.id == "c-all") {
$(".con-button").removeClass("active");
$("#c-all").addClass("active");
$('.offline').hide();
$('.offline').fadeIn("slow").show();
$('.online').hide();
$('.online').fadeIn("slow").show();
$('.none').fadeIn("slow").show();
} else if (this.id == "c-online") {
$(".con-button").removeClass("active");
$("#c-online").addClass("active");
$('.offline').hide();
$('.online').hide();
$('.online').fadeIn("slow").show();
$('.none').hide();
} else if (this.id == "c-offline") {
$(".con-button").removeClass("active");
$("#c-offline").addClass("active");
$('.offline').hide();
$('.offline').fadeIn("slow").show();
$('.online').hide();
$('.none').hide();
}
})
getSteams();
});
var channels = ["BasicallyIDoWrk", "FreeCodeCamp", "Golgothus", "maatukka", "Vinesauce", "brunofin", "comster404", "OgamingSC2"];
var cb = "?client_id=egn4k1eja0yterrcuu411n5e329rd3&callback=?";
function getSteams() {
channels.forEach(function(indchannel) {
//for (var channel in channels) {
//var indchannel = channel;
var streamURL = "https://api.twitch.tv/kraken/streams/" + indchannel + cb;
var channelURL = "https://api.twitch.tv/kraken/channels/" + indchannel + cb;
$.ajax({
url: streamURL,
type: 'GET',
dataType: "jsonp",
data: {
//action: 'query',
format: 'json',
},
headers: {
"Accept": "application/vnd.twitchtv.v5+json",
},
success: function(data) {
var game;
var status;
if(data.stream === null) {
$.getJSON(data._links.channel + "/?client_id=egn4k1eja0yterrcuu411n5e329rd3&callback=?", function(data2) {
if(data2.status == 404) {
game = "The Account doesn't exist";
status = "none";
} else {
game = "Offline";
status = "offline";
}
$("#offline").append('<div class="indbox ' + status + '"><a target="_blank" href="#">'+ indchannel + '<br/>' + game +'</a></div>');
} );
} else {
game = data.stream.game;
status = "online";
$("#online").append('<div class="indbox ' + status + '"><a target="_blank" href="#">'+ indchannel + '<br/>' + game +'</a></div>');
};
}
});
});
}
html, body{
height:100%;
margin: 0;
background-color: #ffffff;
}
.wrapper {
text-align: center;
position: relative;
width: 100%;
height: 100%;
display:block;
}
.container {
width: 75%;
margin: 30px auto 0;
position: relative;
}
.logobox img {
width: 20%;
margin: 0 auto;
}
.controls {
position: relative;
width: 100%;
}
.con-button {
position: relative;
background-color: white;
border: none;
margin: 0.5em 0 0 0;
padding: 0.5em 1em 0.5em 1em;
text-align: center;
color: rgb(100,65,164);
font-size: 20px;
transition: .4s;
}
.con-button:hover {
cursor: pointer;
/*border-bottom: 3px solid rgba(224, 217, 236, 1);*/
}
.con-button:focus {outline: 0;}
.effect {
position: absolute;
left: 0;
transition: 0.4s ease-in-out;
}
.controls .effect {
/*border-bottom: 3px solid rgba(100, 65, 164, 1);*/
height: 2px;
bottom: 5px;
background: #6441A4;
margin-left:/*-45px*/auto;
margin-right:/*-45px*/auto;
width: 33%;
}
button:nth-child(1).active ~ .effect {left: 0%;}
button:nth-child(2).active ~ .effect {left: 33%;}
button:nth-child(3).active ~ .effect {left: 66%;}
.divider hr {
border-top: 1px solid #6441A4;
}
.effect {
position: absolute;
left: 18%;
transition: 0.4s ease-in-out;
}
.controls button:nth-child(1).active ~ .effect {
left: 28%;
/* the middle of the first <a> */
}
.controls button:nth-child(2).active ~ .effect {
left: 50%;
/* the middle of the second <a> */
}
.controls button:nth-child(3).active ~ .effect {
left: 77%;
/* the middle of the third <a> */
}
.controls button:nth-child(4).active ~ .effect {
left: 93.5%;
/* the middle of the forth <a> */
}
.controls .effect {
width: 55px;
height: 2px;
bottom: 5px;
background: #00ABE8;
margin-left:-45px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<div class="wrapper">
<div class="container">
<div class="twitchtvarea">
<div class="logobox">
<img src="https://s6.postimg.org/bay7stotd/Twitch_Purple_RGB.png" />
</div>
<div class="twitchbox">
<div class="controls">
<button id="c-all" class="con-button active" type="button">All</button>
<button id="c-online" class="con-button" type="button">Online</button>
<button id="c-offline" class="con-button" type="button">Offline</button>
<div class="effect"></div>
</div>
<div class="divider"><hr></div>
<div id="online"></div>
<div id="offline"></div>
</div>
</div>
</div>
</div>
I have made changes in your code to make it work.

Categories

Resources