I am working through a Udacity course on JavaScript. The main project is a resume built from a basic skeleton that the instructors provide as a GitHub repo. Here is a screenshot of my most recent version:
As you can see, my skills list moves to the left after it reaches the bottom of my picture. I want to keep the entire bulleted list lined up with the first two list items. How do I do this? Is it possible with the right <div>s or do I need a <table>?
Below is the relevant code:
index.html
<html>
<head>
<meta charset="utf-8">
<title>Resume</title>
<link href="css/style.css" rel="stylesheet">
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
<div id="main">
<div id="header" class="center-content clear-fix">
<ul id="topContacts" class="flex-box"></ul>
</div>
<div style="clear: both;"></div>
<div id="workExperience" class="gray">
<h2>Work Experience</h2>
</div>
<div id="projects">
<h2>Projects</h2>
</div>
<div id="education" class="gray">
<h2>Education</h2>
</div>
<div id="mapDiv">
<h2>Where I've Lived and Worked</h2>
</div>
<div id="lets-connect" class="dark-gray">
<h2 class="orange center-text">Let's Connect</h2>
<ul id="footerContacts" class="flex-box">
</ul>
</div>
</div>
<script src="js/jQuery.js"></script>
<script src="js/helper.js"></script>
<script src="js/resumeBuilder.js"></script>
<script>
if(document.getElementsByClassName('flex-item').length === 0) {
document.getElementById('topContacts').style.display = 'none';
}
if(document.getElementsByTagName('h1').length === 0) {
document.getElementById('header').style.display = 'none';
}
if(document.getElementsByClassName('work-entry').length === 0) {
document.getElementById('workExperience').style.display = 'none';
}
if(document.getElementsByClassName('project-entry').length === 0) {
document.getElementById('projects').style.display = 'none';
}
if(document.getElementsByClassName('education-entry').length === 0) {
document.getElementById('education').style.display = 'none';
}
if(document.getElementsByClassName('flex-item').length === 0) {
document.getElementById('lets-connect').style.display = 'none';
}
if(document.getElementById('map') === null) {
document.getElementById('mapDiv').style.display = 'none';
}
</script>
</body>
</html>
js/resumeBuilder.js
var dataPlaceHolder = "%data%";
var bio = {
"name" : "Code Apprentice",
"role" : "Software Engineer",
"contact" : {
"phone" : "555-555-5555",
"email" : "codeguru42#gmail.com",
"twitter" : "#codeguru42",
"github" : "codeguru42",
"location" : "Code Heaven"
},
"pictureURL" : "images/minion-me.png",
"welcomeMessage" : "Android Developer | Stack Overflow Contributor | Full Stack Web Developer",
"skills" : ["Java", "C++", "Android Development", "HTML", "JavaScript", "CSS", "Python"]
};
var formattedName = HTMLheaderName.replace(dataPlaceHolder, bio.name);
var formattedRole = HTMLheaderRole.replace(dataPlaceHolder, bio.role);
var formattedPhone = HTMLmobile.replace(dataPlaceHolder, bio.contact.phone);
var formattedEmail = HTMLemail.replace(dataPlaceHolder, bio.contact.email);
var formattedTwitter = HTMLtwitter.replace(dataPlaceHolder, bio.contact.twitter);
var formattedGithub = HTMLgithub.replace(dataPlaceHolder, bio.contact.github);var formattedPicture = HTMLbioPic.replace(dataPlaceHolder, bio.pictureURL);
var formattedLocation = HTMLlocation.replace(dataPlaceHolder, bio.contact.location);
var formattedBioPic = HTMLbioPic.replace(dataPlaceHolder, bio.pictureURL);
var formattedWelcomeMessage = HTMLwelcomeMsg.replace(dataPlaceHolder, bio.welcomeMessage);
var formattedSkills = bio.skills.map(function (skill) { return HTMLskills.replace(dataPlaceHolder, skill); });
$("#header").prepend(formattedRole);
$("#header").prepend(formattedName);
$("#header").prepend(formattedBioPic);
$("#header").append(formattedWelcomeMessage);
$("#header").append(HTMLskillsStart);
$("#header").append(formattedSkills);
$("#topContacts").append(formattedPhone);
$("#topContacts").append(formattedEmail);
$("#topContacts").append(formattedLocation);
$("#footerContacts").append(formattedTwitter);
$("#footerContacts").append(formattedGithub);
css/styles.css
body,
div,
ul,
li,
p,
h1,
h2,
h3,
h4,
h5,
h6 {
padding: 0;
margin: 0;
font-family: "Roboto", sans-serif;
}
.clear-fix {
overflow: auto;
}
.education-entry,
.work-entry,
.project-entry {
padding: 0 5%;
}
h1 {
font-size: 40px;
color: #f5a623;
line-height: 48px;
display: inline;
}
h2 {
font-weight: bold;
font-size: 24px;
color: #999;
line-height: 29px;
padding: 10px;
}
h3 {
font-style: italic;
font-size: 20px;
color: #000;
line-height: 22px;
}
h4 {
font-weight: bold;
font-size: 14px;
color: #4a4a4a;
line-height: 17px;
}
h2,
h3,
h4,
h5 {
padding: 10px 5%;
}
.date-text {
font-style: italic;
font-size: 14px;
color: #999;
line-height: 16px;
float: left;
}
.location-text {
font-style: italic;
font-size: 14px;
color: #999;
line-height: 16px;
float: right;
}
p {
font-size: 14px;
color: #333;
line-height: 21px;
}
a {
color: #1199c3;
text-decoration: none;
margin-top: 10px;
display: block;
}
.welcome-message {
font-style: italic;
font-size: 18px;
color: #f3f3f3;
line-height: 28px;
}
#skills-h3 {
color: #f5ae23;
display: none;
}
.orange {
background-color: #f5ae23;
}
.orange-text {
color: #f5ae23;
}
.white-text {
font-weight: bold;
color: #fff;
}
.gray {
background-color: #f3f3f3;
padding-bottom: 10px;
clear: both;
}
.dark-gray {
background-color: #4a4a4a;
}
/* TODO: Replace with image later */
#header {
background-color: #484848;
}
.flex-box {
display: -webkit-flex;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
padding: 10px;
}
.flex-column {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
padding: 10px;
}
.center-content {
padding: 2.5% 5%;
}
ul {
list-style-type: none;
}
.biopic {
float: left;
padding: 10px;
width: 200px;
display: none;
}
img {
padding: 10px;
}
span {
padding: 5px;
}
#lets-connect {
text-align: center;
}
/* Media queries to handle various device widths */
#media only screen and (max-width: 1024px) {
#lets-connect {
margin-top: 5%;
}
}
#media only screen and (max-width:900px) {
.biopic {
width: 175px;
}
}
#media only screen and (max-width: 750px) {
#lets-connect {
margin-top: 10%;
}
.biopic {
width: 150px;
}
.welcome-message {
display: none;
}
}
#map {
display: block;
height: 100%;
margin: 0 5%;
}
#mapDiv {
height: 400px;
width: 100%;
padding-bottom: 5%;
}
#media only screen and (min-width: 750px) {
#skills-h3,
.biopic {
display: block;
}
}
js/helper.js
var HTMLheaderName = '<h1 id="name">%data%</h1>';
var HTMLheaderRole = '<span>%data%</span><hr>';
var HTMLcontactGeneric = '<li class="flex-item"><span class="orange-text">%contact%</span><span class="white-text">%data%</span></li>';
var HTMLmobile = '<li class="flex-item"><span class="orange-text">mobile</span><span class="white-text">%data%</span></li>';
var HTMLemail = '<li class="flex-item"><span class="orange-text">email</span><span class="white-text">%data%</span></li>';
var HTMLtwitter = '<li class="flex-item"><span class="orange-text">twitter</span><span class="white-text">%data%</span></li>';
var HTMLgithub = '<li class="flex-item"><span class="orange-text">github</span><span class="white-text">%data%</span></li>';
var HTMLblog = '<li class="flex-item"><span class="orange-text">blog</span><span class="white-text">%data%</span></li>';
var HTMLlocation = '<li class="flex-item"><span class="orange-text">location</span><span class="white-text">%data%</span></li>';
var HTMLbioPic = '<img src="%data%" class="biopic">';
var HTMLwelcomeMsg = '<span class="welcome-message">%data%</span>';
var HTMLskillsStart = '<h3 id="skills-h3">Skills at a Glance:</h3><ul id="skills" class="flex-column"></ul>';
var HTMLskills = '<li class="flex-item"><span class="white-text">%data%</span></li>';
Try to give clear:both to the image tag, so that the list does not move under the bottom of the picture.
After Inspecting the HTML elements in the generated page, I found that I was not correctly inserting <li> tags for each skill into the <ul> tag defined in HTMLskillsStart. I just had to change
$("#header").append(formattedSkills);
to
$("#skills").append(formattedSkills);
Related
I've made a budgeting app that has expenses and Income tabs. Every time you add an expense or income, the app pushes the information inside of an array of objects and dynamically renders an <li> component and places it inside of a <ul>. I'm having trouble with the edit and delete features. Each individual <li> comes with a delete and edit button. The <li>, delete button, and edit button all have the same id of Date.now(). Date.now() is used because it produces a number based on milliseconds and won't produce the same id twice unless someone types an expense or income twice within one millisecond I want to click on the delete button inside of the <li> and have my app remove that individual object from my entry_list[] array and also remove the <li> from the DOM.
'use strict'
const balanceElement = document.querySelector(".balance .value");
const totalIncome = document.querySelector(".income-total");
const totalOutcome = document.querySelector(".outcome-total");
const incomeElement = document.querySelector(".income-tab");
const expense = document.querySelector(".expense-tab");
const all = document.querySelector(".all-tab");
const incomeList = document.querySelector(".income-tab .list");
const expenseList = document.querySelector(".expense-tab .list");
const allList = document.querySelector(".all-tab .list");
const expensesButton = document.querySelector(".tab1");
const incomeButton = document.querySelector(".tab2");
const allButton = document.querySelector(".tab3");
const addExpense = document.querySelector(".add-expense")
const expenseTitle = document.querySelector(".expense-title-input")
const expenseAmount = document.querySelector(".expense-amount-input")
const addIncome = document.querySelector(".add-income")
const incomeTitle = document.querySelector(".income-title-input")
const incomeAmount = document.querySelector(".income-amount-input")
const list = document.querySelector('.list')
//SWITCHING BETWEEN TABS
expensesButton.addEventListener('click', () => {
expense.classList.remove('hidden');
incomeElement.classList.add('hidden');
expensesButton.classList.add('clicked');
incomeButton.classList.remove('clicked');
})
incomeButton.addEventListener('click', () => {
incomeElement.classList.remove('hidden');
expense.classList.add('hidden');
expensesButton.classList.remove('clicked');
incomeButton.classList.add('clicked');
})
incomeList.addEventListener('click', deleteOrEdit)
expenseList.addEventListener('click', deleteOrEdit)
let entry_list = []
addExpense.addEventListener('click', () =>{
if(expenseTitle.value == '' || expenseAmount.value == ''){
return;
}
let expense = {
type: 'expense',
title: expenseTitle.value,
amount: expenseAmount.value,
id: Date.now()
}
entry_list.push(expense)
clearExpense()
changeLists()
})
addIncome.addEventListener('click', () =>{
if(incomeTitle.value == '' || incomeAmount.value == ''){
return;
}
let income = {
type: 'income',
title: incomeTitle.value,
amount: incomeAmount.value,
id: Date.now()
}
entry_list.push(income)
clearIncome()
changeLists()
})
const clearExpense = () =>{
expenseTitle.value = '';
expenseAmount.value = '';
}
const clearIncome = () =>{
incomeTitle.value = ''
incomeAmount.value = ''
}
const changeLists = () =>{
expenseList.innerHTML = ''
incomeList.innerHTML = ''
entry_list.map((entry) =>{
if(entry.type == 'expense'){
return expenseList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
}
else if(entry.type == 'income'){
return incomeList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
}
})
addIncomes()
}
const addIncomes = () =>{
let sum = 0;
let income = 0;
let outcome = 0;
balanceElement.innerHTML = 0
totalIncome.innerHTML = 0
totalOutcome.innerHTML = 0
entry_list.forEach(list =>{
if(list.type == 'expense'){
sum -= list.amount
outcome -= list.amount
}else if(list.type == 'income'){
sum += Number(list.amount)
income += Number(list.amount)
}
balanceElement.innerHTML = '$' + sum
totalIncome.innerHTML = '$' + income
totalOutcome.innerHTML = '$' + outcome
})
}
// // DETERMINE IF BUTTON IS EDIT OR DELETE
function deleteOrEdit(e){
const targetButton = e.target;
const entry = targetButton.parentNode.parentNode;
if(targetButton.classList == ('delete')){
deleteEntry(entry)
}else if(targetButton.classList == ('edit')){
editEntry(entry);
}
}
// //DELETE FUNCTION
const deleteEntry = (entry) =>{
console.log(entry.id)
entry_list.splice(entry.id, 1)
// entry.innerHTML = ''
console.log(entry.id)
addIncomes()
}
// EDIT FUNCTION
const editEntry = (entry) =>{
let Entry = entry_list[entry.id]
if(entry.type == "income"){
incomeAmount.value = Entry.amount;
incomeTitle.value = Entry.title;
}else if(entry.type == "expense"){
expenseAmount.value = Entry.amount;
expenseTitle.value = Entry.title;
}
deleteEntry(entry);
}
#import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght#400;700&family=Raleway:wght#400;700&display=swap');
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Open Sans', sans-serif;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.budget-container{
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100%;
background-color: #4F98CA;
}
.balance-container{
width: 360px;
height: 470px;
background-color: #50D890;
border-radius: 30px;
margin-right: 100px;
}
.app-title{
color: white;
margin-top: 1rem;
margin-left: 1rem;
}
.month{
color: white;
margin-top: 1rem;
text-align: center;
}
.budget-header{
display: flex;
flex-direction:column;
justify-content: center;
}
.balance{
margin-top: 1rem;
margin-left: 1rem;
}
.title{
color: white;
font-size: 1.25rem;
opacity: .75;
}
.value{
font-size: 1.75rem;
color: white;
font-weight: bold;
margin-left: 1rem;
}
.account{
margin-top: 2.5rem;
margin: 2.5rem 1.5rem 2.5rem 1.5rem;
display: flex;
justify-content: space-between
}
.income-total{
color: white;
text-align: center;
font-size: 1.5rem;
}
.outcome-total{
color: #4F98CA;
text-align: center;
font-size: 1.5rem;
}
/* DASHBOARD */
.budget-dashboard{
display: block;
width: 360px;
height: 470px;
position: relative;
border-radius: 30px;
background-color: white;
}
.dash-title{
margin-top: 2rem;
margin-left: 1rem;
font-size: 1.5rem;
}
.toggle{
margin: 1rem;
display: flex;
cursor: pointer;
}
.toggle .tab2, .tab3{
margin-left: 1rem;
cursor: pointer;
}
.clicked{
font-weight: bold !important;
}
.hidden{
display: none !important;
}
/* EXPENSES TAB */
.expense-tab{
display: flex;
justify-content: center;
}
.expense-input-container{
position: absolute;
top: 400px;
border-top: solid 1px gray;
width: 100%;
}
.expense-amount-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.expense-title-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.add-expense{
color: none;
background-color: none;
border: none;
outline: none;
color: inherit;
}
/* INCOME TAB */
.income-tab{
display: flex;
justify-content: center;
}
.income-input-container{
position: absolute;
top: 400px;
border-top: solid 1px gray;
width: 100%;
}
.input{
display: flex;
justify-content: space-between;
align-items: center;
margin: 1rem;
}
.income-amount-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.income-title-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.add-income{
color: none;
background-color: none;
border: none;
outline: none;
}
.plus-img{
width: 40px;
}
/* li */
ul{
width: 360px;
height: 255px;
list-style: none;
margin-top:20px;
overflow-x: auto;
}
/* BUTTON ICONS */
.edit{
background-image: url('media/Icons/icons8-edit-48.png');
background-size: contain;
width: 25px;
height: 25px;
background-repeat: no-repeat;
margin-right: 10px;
}
.delete{
background-image: url('media/Icons/icons8-trash-can-48 (2).png');
background-size: contain;
width:25px;
height: 25px;
background-repeat: no-repeat;
}
.income{
width:250px;
height: auto;
padding-left: 20px;
margin-bottom: 10px;;
word-wrap: break-word;
color: black
}
.expense{
width:250px;
height: auto;
padding-left: 20px;
margin-bottom: 10px;;
word-wrap: break-word;
font-family: 'Gilroy Bold';
color: #4F98CA;
}
li{
display: flex;
justify-content: space-between;
width: 100% !important;
padding-right: 20px;
}
.icon-container{
display: flex;
}
#media (max-width:900px){
.budget-container{
display: inline-block;
position: relative
}
.balance-container{
position: absolute;
top: 10%;
left: 25%;
}
.budget-dashboard{
position: absolute;
left: 25%;
top: 40%;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Budgetrr</title>
</head>
<body>
<main class="budget-container">
<section class="balance-container">
<div class="app-title">
<p>Budgetrr</p>
</div>
<h1 class="month">OCTOBER</h1>
<section class="budget-header">
<div class="balance">
<div class="title">
Balance
</div>
<div class="value">
<small>$</small>0
</div>
</div>
<div class="account">
<div class="budget-income">
<div class="title">
Income
</div>
<div class="income-total">
<small>$</small>0
</div>
</div>
<div class="chart"></div>
<div class="budgetoutcome">
<div class="title">
Expenses
</div>
<div class="outcome-total">
<small>$</small>0
</div>
</div>
</div>
</section>
</section>
<section class="budget-dashboard">
<div class="dash-title">Dashboard</div>
<div class="toggle">
<div class="tab1 clicked">Expenses</div>
<div class="tab2">Income</div>
<!-- <div class="tab3 clicked">All</div> -->
</div>
<div class="income-tab hidden">
<ul class="list"></ul>
<div class="income-input-container">
<form class="input">
<input type="text" class="income-title-input" name="title" placeholder="Title">
<input type="number" class="income-amount-input" name="amount" placeholder="$0">
<button type = "button" class="add-income"><img class= "plus-img"src="media/Icons/icons8-add-new-48.png" alt=""></button>
</form>
</div>
</div>
<div class = "expense-tab">
<ul class="list"></ul>
<div class="expense-input-container">
<div class="input">
<input type="text" class="expense-title-input" name="title" placeholder="Title">
<input type="number" class="expense-amount-input" name="amount" placeholder="$0">
<button type="button" class="add-expense"><img class= "plus-img" src="media/Icons/icons8-add-new-48.png" alt=""></button>
</div>
</div>
</div>
</section>
</main>
<script src="JavaScript/budget.js"></script>
</body>
</html>
I've tried to use .splice() but I can't seem to get it to work.
Your entry is an object. And entry has an id property with Date type.
Your delete function calls this:
entry_list.splice(entry.id, 1)
Javascript splice function
function takes number as argument(s).
You should find the id of element you want to delete and get its index. After that you can delete the element with splice method.
Here is how to delete:
// Find the index of object at the given list
const index = entry_list.findIndex(x => x.id === entry.id);
// Starting from index of element to delete, remove 1 element.
entry_list.splice(index, 1);
I need to get a list of all files by iterating all folders in the specified parent folder.
I have heard that recursion is the best way to achieve, but I am unsure how to use recursion for fetching list of files in a folder using Dropbox API.
The below code works well for fetching the files in a single folder, I am looking to modify the code so it does a recursive fetch
<!doctype html>
<html>
<head>
<title>Dropbox JavaScript SDK</title>
<style>
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
line-height: 1.5;
}
.container {
display: block;
width: 90%;
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.container.main {
padding-top: 30px;
}
code, .code {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
color: #666;
}
.info {
font-size: 13px;
font-style: italic;
color: #666;
margin-top: 40px;
}
a {
color: #007ee5;
}
input {
border: 2px solid #007ee5;
border-radius: 3px;
padding: 8px;
font-size: 16px;
}
.button, button {
border-radius: 3px;
background-color: #007ee5;
border: none;
color: #fff;
font-size: 16px;
padding: 10px 15px;
text-decoration: none;
}
.page-header {
background-color: #007ee5;
padding: 10px 0 0 0;
}
.page-header .container {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 150px;
}
.page-header a {
color: #fff;
text-decoration: none;
}
.page-header nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.page-header h1 {
display: flex;
align-items: center;
color: #fff;
font-size: 17px;
font-weight: 200;
}
.page-header .logo {
width: 100px;
margin-right: 10px;
}
.page-header .view-source {
font-weight: 200;
font-size: 12px;
}
.page-header h2 {
color: #fff;
font-size: 18px;
font-weight: normal;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill#7/dist/polyfill.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropbox.js/10.27.0/Dropbox-sdk.min.js" integrity="sha512-nTLJySi/DUYzRvvxWOxf31QS5191sN1gpoq6EqGFHPFH0RlM6xOiY6jEp9dmwhDlyFmCmicwLOMnE+fUmo02KQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<!-- Example layout boilerplate -->
<header class="page-header">
<div class="container">
<nav>
<a href="/">
<h1>
<img src="https://cfl.dropboxstatic.com/static/images/brand/logotype_white-vflRG5Zd8.svg" class="logo" />
JavaScript SDK Examples
</h1>
</a>
View Source
</nav>
<h2 class="code">
examples / basic
</h2>
</div>
</header>
<!-- Example description and UI -->
<section class="container main">
<p>This example fetches the contents of your root Dropbox directory. It uses the <code>Dropbox.filesListFolder()</code> method [docs].</p>
<form id="basic-form" onSubmit="return listFiles()">
<input type="text" id="access-token" placeholder="Access token" />
<button type="submit">Submit</button>
</form>
<!-- The files returned from the SDK will be added here -->
<ul id="files"></ul>
<p class="info">To obtain an access token for quick testing, you can go to API Explorer click the "Get Token" button on the top right, copy the token it creates and then paste it here.</p>
</section>
<!-- Scripts to run example -->
<script>
var form = document.getElementById('basic-form');
form.onsubmit = function listFiles(e) {
e.preventDefault();
var ACCESS_TOKEN = document.getElementById('access-token').value;
var dbx = new Dropbox.Dropbox({ accessToken: ACCESS_TOKEN });
dbx.filesListFolder({path: ''})
.then(function(response) {
console.log('response', response)
displayFiles(response.result.entries);
})
.catch(function(error) {
console.error(error);
});
}
function displayFiles(files) {
var filesList = document.getElementById('files');
var li;
for (var i = 0; i < files.length; i++) {
li = document.createElement('li');
li.appendChild(document.createTextNode(files[i][".tag"] + " " + files[i].name));
filesList.appendChild(li);
}
}
</script>
</body>
</html>
Quick attempt, non-tested code but you can use it as inspiration:
form.onsubmit = function listFiles(e) {
e.preventDefault();
var ACCESS_TOKEN = document.getElementById('access-token').value;
var dbx = new Dropbox.Dropbox({ accessToken: ACCESS_TOKEN });
var entries = {};
let fetch_files = function(_path, entries){
await dbx.filesListFolder({path: _path})
.then(function(response) {
console.log('response', response);
entries = response.result.entries;
for (var i = 0; i < entries.length; i++) {
if(entries[i]['.tag'] == 'folder'){
entries[i]['subentries'] = {};
fetch_files(entries[i]['path_display'], entries[i]['subentries']);
}
}
})
.catch(function(error) {
console.error(error);
});
};
fetch_files('', entries);
if(Object.keys(entries).length !== 0){
displayFiles(entries);
}
}
function displayFiles(files) {
var filesList = document.getElementById('files');
let append_list = function(arr, recursion){
var li;
for (var i = 0; i < arr.length; i++) {
li = document.createElement('li');
li.appendChild(document.createTextNode(" ".repeat(recursion * 4) + arr[i][".tag"] + " " + arr[i].name));
filesList.appendChild(li);
if('subentries' in arr[i]){
append_list(arr[i]['subentries'], recursion + 1);
}
}
}
append_list(files, 0)
}
I am making a todo page and want to count the number of todos and display them.
<div class='numtodos'>3</div>
I want to display them here in the text content of numtodos.
Trying to count the number of todo lis using jQuery (I could also use a non-jQuery answer).
I know I would need the length of <li> elements, but how should I save it to update when a new todo is added.
Here is my code pen. trying to make the large number on the right be the number of todos.
$('ul').on('click', 'li', function() {
$(this).toggleClass('completed');
})
$('ul').on('click', 'span', function(event) {
$(this).parent().fadeOut(500, function() {
$(this).remove();
})
event.stopPropagation();
});
$("input[type='text']").keypress(function(event) {
if (event.which === 13) {
//get the new todo text from inut
var todoText = $(this).val();
$(this).val('');
//create a new li and add it ul
$('ul').append('<li><i class="far fa-circle"></i> ' + todoText + ' <span>X</span></li>')
}
});
$(".fa-plus-circle").click(function() {
$("input[type='text']").fadeToggle();
});
// let lis = document.querySelectorAll('li');
// let input = document.querySelector('input');
// let numtodos = document.querySelector('.numtodos')
// input.addEventListener('change', function(){
// let howmany = lis.length;
// numtodos.textContent= howmany;
// })
$('input').change(function() {
console.log($('.numtodos'));
})
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: rgb(67, 0, 192);
font-family: 'Roboto', sans-serif;
}
.container {
background-color: whitesmoke;
width: 480px;
height: 100%;
padding: 35px 40px;
}
/* NAV */
#nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.tinyburger {
cursor: pointer;
}
.line {
height: 3px;
width: 21px;
background: black;
margin: 3px;
border-radius: 1px;
}
/* header */
.header {
display: flex;
margin: 40px 0px 30px;
font-family: 'Roboto Condensed', sans-serif;
}
h1 {
margin-right: 8px;
font-size: 3em;
}
h2 {
font-size: 1.4em;
margin-top: 26px;
color: rgb(153, 153, 153);
}
/* Input */
input {
width: 100%;
padding: 10px 5px;
border: none;
font-size: 17px;
}
ul {
list-style: none;
}
li {
line-height: 1.2;
border-bottom: 1px rgb(202, 202, 202) solid;
margin: 20px 5px;
padding: 0px 0 20px 0;
font-weight: bold;
cursor: pointer;
}
li span {
float: right;
}
.fa-plus-circle {
color: rgb(67, 0, 192);
font-size: 40px;
text-align: center;
width: 100%;
margin-top: 30px;
}
.numtodos {
font-size: 12em;
position: absolute;
top: 0%;
left: 75%;
line-height: 0.7;
color: rgba(153, 153, 153, 0.2);
font-family: 'Roboto Condensed', sans-serif;
}
.fa-circle {
color: rgba(153, 153, 153, 0.4);
font-size: 20px;
}
.completed {
text-decoration: line-through;
color: grey;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght#0,400;1,700&family=Roboto:wght#400;500;700;900&display=swap" rel="stylesheet">
</head>
<body>
<div class="container">
<div id='nav'>
<div class='tinyburger'>
<div class='line'></div>
<div class='line'></div>
<div class='line'></div>
</div>
<i class="fas fa-search"></i>
</div>
<div class="header">
<h1>TO-DO</h1>
<h2 class="date">NOV 23</h2>
</div>
<input type="text" name='newtodo' id='newtodo' placeholder="Write a new to-do">
<ul class='todos'>
<li><i class="far fa-circle"></i> Lunch with Helena Barnes <span>X</span> </li>
<li><i class="far fa-circle"></i> Evening Workout<span>X</span></li>
<li><i class="far fa-circle"></i> Lunch with Helena Barnes <span>X</span></li>
</ul>
<i class="fas fa-plus-circle"></i>
<div class='numtodos'>3</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
https://codepen.io/laurynatlanta/pen/QWNxYeN
I think this should be fine:
// Get todos number container div element.
var numTodosContainer = document.getElementsByClassName('numtodos')[0];
// Get all todos available.
var todos = document.getElementsByClassName(todosclassname);
// Get todos length to add it to the container.
var lastTodosNum = todos.length;
// Add it to the container.
numTodosContainer.innerHTML = lastTodosNum;
// Loop to check every 10ms if the number of todos is changed.
setInterval(function(){
// This variable will change every 10ms to get the new todos number.
var newTodosNum = document.getElementsByClassName(todosclassname).length;
// Check if the new number isn't equals the old num.
if (newTodosNum != lastTodosNum) {
numTodosContainer.innerHTML = newTodosNum;
}
// Make lastTodosNum equals newTodosNum to stop the if statement above from execute the code block inside it.
lastTodosNum = newTodosNum;
}, 10);
you have todo something like that:
const numtodos = document.querySelector('div.numtodos')
numtodos.setCount =_=> {
numtodos.textContent = document.querySelectorAll('ul.todos>li:not(.completed)').length
}
then just add numtodos.setCount(); on rights places.
so, you JS become:
const numtodos = document.querySelector('div.numtodos')
numtodos.setCount =_=> {
numtodos.textContent = document.querySelectorAll('ul.todos>li:not(.completed)').length
}
$('ul').on('click', 'li', function () {
$(this).toggleClass('completed');
numtodos.setCount();
});
$('ul').on('click', 'span', function (event) {
$(this).parent().fadeOut(500, function () {
$(this).remove();
numtodos.setCount();
});
event.stopPropagation();
});
$("input[type='text']").keypress(function (event) {
if (event.which === 13) {
//get the new todo text from inut
var todoText = $(this).val();
$(this).val('');
//create a new li and add it ul
$('ul').append(`<li><i class="far fa-circle"></i>${todoText}<span>X</span></li>`);
numtodos.setCount();
}
});
$(".fa-plus-circle").click(function () {
$("input[type='text']").fadeToggle();
});
Based on your current code, I'd suggest creating the following named function, and then calling that function in the areas of your code where you're updating the the to-do list (whether adding to, or removing from, it):
// we're not planning to change the function within the code, so we
// declare using 'const' (though 'let' would be perfectly okay, but would
// potentially allow for the variable to be overwritten); we also use
// Arrow function syntax since - within the function - we have no need
// to use 'this':
const todosLength = () => {
// here we find the number of <li> elements that do not have
// the class of 'completed' that are the children of a parent
// with the class of 'todos'; and then we retrieve the length
// of the resulting jQuery collection:
const num = $('.todos > li:not(.completed)').length;
// here we set the text of the element(s) with the
// class of 'numtodos':
$('.numtodos').text(num);
// here we return the number to the calling context
// (just in case it's ever of use):
return num;
};
When the above is merged with your code it yields the following:
const todosLength = () => {
const num = $('.todos li:not(.completed)').length;
$('.numtodos').text(num);
return num;
}
$('ul').on('click', 'li', function() {
$(this).toggleClass('completed');
})
$('ul').on('click', 'span', function(event) {
$(this).parent().fadeOut(500, function() {
$(this).remove();
todosLength();
});
event.stopPropagation();
});
$("input[type='text']").keypress(function(event) {
if (event.which === 13) {
//get the new todo text from inut
var todoText = $(this).val();
$(this).val('');
//create a new li and add it ul
$('ul').append('<li><i class="far fa-circle"></i> ' + todoText + ' <span>X</span></li>');
todosLength();
}
});
$(".fa-plus-circle").click(function() {
$("input[type='text']").fadeToggle();
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: rgb(67, 0, 192);
font-family: 'Roboto', sans-serif;
}
.container {
background-color: whitesmoke;
width: 480px;
height: 100%;
padding: 35px 40px;
}
/* NAV */
#nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.tinyburger {
cursor: pointer;
}
.line {
height: 3px;
width: 21px;
background: black;
margin: 3px;
border-radius: 1px;
}
/* header */
.header {
display: flex;
margin: 40px 0px 30px;
font-family: 'Roboto Condensed', sans-serif;
}
h1 {
margin-right: 8px;
font-size: 3em;
}
h2 {
font-size: 1.4em;
margin-top: 26px;
color: rgb(153, 153, 153);
}
/* Input */
input {
width: 100%;
padding: 10px 5px;
border: none;
font-size: 17px;
}
ul {
list-style: none;
}
li {
line-height: 1.2;
border-bottom: 1px rgb(202, 202, 202) solid;
margin: 20px 5px;
padding: 0px 0 20px 0;
font-weight: bold;
cursor: pointer;
}
li span {
float: right;
}
.fa-plus-circle {
color: rgb(67, 0, 192);
font-size: 40px;
text-align: center;
width: 100%;
margin-top: 30px;
}
.numtodos {
font-size: 12em;
position: absolute;
top: 0%;
left: 75%;
line-height: 0.7;
color: rgba(153, 153, 153, 0.2);
font-family: 'Roboto Condensed', sans-serif;
}
.fa-circle {
color: rgba(153, 153, 153, 0.4);
font-size: 20px;
}
.completed {
text-decoration: line-through;
color: grey;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght#0,400;1,700&family=Roboto:wght#400;500;700;900&display=swap" rel="stylesheet">
<div class="container">
<div id='nav'>
<div class='tinyburger'>
<div class='line'></div>
<div class='line'></div>
<div class='line'></div>
</div>
<i class="fas fa-search"></i>
</div>
<div class="header">
<h1>TO-DO</h1>
<h2 class="date">NOV 23</h2>
</div>
<input type="text" name='newtodo' id='newtodo' placeholder="Write a new to-do">
<ul class='todos'>
<li><i class="far fa-circle"></i> Lunch with Helena Barnes <span>X</span> </li>
<li><i class="far fa-circle"></i> Evening Workout<span>X</span></li>
<li><i class="far fa-circle"></i> Lunch with Helena Barnes <span>X</span></li>
</ul>
<i class="fas fa-plus-circle"></i>
<div class='numtodos'>3</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
JS Fiddle demo.
References:
CSS:
Negation (:not()) pseudo-class.
jQuery:
text().
on my website, there are 2 buttons. one button is to indent text to the left and the other button is to indent text to the right. what I am trying to achieve is that whenever I press the indent left or right button, currently selected (on focus) text should move left or right (depending on what button I press). at the same time, I want the font size of that text to go down by one level, so when compared to the text above, it's smaller to the text above.
// global variable
let onFocus = null;
// this function
function focusedText(event) {
onFocus = event.target;
}
function init() {
const newLineButton = document.querySelector('#newLine');
newLineButton.addEventListener("click", newLine);
newLine();
document.querySelector("#printButton").addEventListener("click", printPage)
}
function newLine() {
const newLine = document.createElement("p");
newLine.setAttribute("contenteditable", true);
newLine.addEventListener("keydown", handleKeyDown)
newLine.addEventListener("focus", focusedText)
newLine.classList.add("textLine")
const parent = document.querySelector('#textBox');
parent.appendChild(newLine);
newLine.focus();
}
function handleKeyDown(event) {
if (event.which === 13) {
event.preventDefault();
newLine();
}
}
// this runs the init(); function
init();
// this prints the page
function printPage() {
window.print();
}
// this fuction changes the text size
function textSize(selectTag) {
const listValue = selectTag.options[selectTag.selectedIndex].value;
onFocus.style.fontSize = listValue;
}
* {
padding-top: 0em;
padding-bottom: 0em;
margin-top: 0em;
margin-bottom: 0em;
}
*:focus {
outline: 0px solid transparent;
}
body {
margin: 0;
}
.title {
font-family: 'Assistant', sans-serif;
font-size: 2em;
text-align: center;
text-transform: uppercase;
color: white;
background: #6a0dad;
letter-spacing: 0.20em;
}
.navMenu {
display: flex;
align-items: stretch;
padding-top: 0.5em;
padding-bottom: 0.5em;
justify-content: center;
}
.navMenu button,
#dropDown {
padding: 0.3em 1.2em;
margin: 0 0.1em 0.1em 0;
border: 0.16em solid rgba(255, 255, 255, 0);
border-radius: 2em;
box-sizing: border-box;
font-family: 'Assistant', sans-serif;
font-weight: bold;
font-size: 1rem;
color: white;
text-shadow: 0 0.04em 0.04em rgba(0, 0, 0, 0.35);
text-align: center;
transition: all 0.2s;
background-color: #6a0dad;
cursor: pointer;
}
.navMenu button:hover,
#dropDown:hover {
border-color: white;
}
#dropDown option {
font-weight: bold;
}
#textBox {
display: flex;
justify-content: left;
width: auto;
flex-flow: column nowrap;
font-family: 'Assistant', sans-serif;
}
.textLine {
color: black;
width: 100%;
padding-left: 0.8em;
padding-right: 0.8em;
box-sizing: border-box;
transition: background-color 0.25s;
}
#media screen {
.textLine:hover {
background-color: #6a0dad;
color: white;
}
}
#media print {
.navMenu,
.title {
display: none;
}
}
.textLine:empty::before {
content: "Enter your text here";
color: grey;
font-family: 'Assistant', sans-serif;
pointer-events: none;
}
.textLine:hover:empty::before {
content: "Enter your text here";
color: white;
font-family: 'Assistant', sans-serif;
}
<!DOCTYPE html>
<html>
<head>
<title>Outline Editing</title>
<link rel="stylesheet" type="text/css" href="main-css.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<main>
<h1 class="title">Outline Editing</h1>
<nav class="navMenu">
<button type="button" id="indentLeft"><i class="material-icons">format_indent_decrease</i></button>
<select id="dropDown" onchange="textSize(this);" size="1">
<option value="" selected disabled hidden>Levels</option>
<option value="200%">Level 1</option>
<option value="170%">Level 2</option>
<option value="150%">Level 3</option>
<option value="130%">Level 4</option>
<option value="100%">Level 5</option>
</select>
<button type="button" id="newLine">New Line</button>
<button type="button" id="indentRight"><i class="material-icons">format_indent_increase</i></button>
<button type="button" id="printButton">Print</button>
</nav>
<div id="textBox">
</div>
<script src="main.js"></script>
</main>
</body>
</html>
You could just add "Horizontal Tab" as an HTML entity on your focused text.
First change the <p> to <pre>.
function newLine() {
const newLine = document.createElement("pre");
//...
}
Update your init function:
function init() {
var newLineButton = document.querySelector('#newLine');
newLineButton.addEventListener("click", newLine);
newLine();
document.querySelector("#printButton").addEventListener("click", printPage);
let indentRight = document.getElementById("indentRight");
indentRight.addEventListener("click", IndentRight_Click);
let indentLeft = document.getElementById("indentLeft");
indentLeft.addEventListener("click", IndentLeft_Click);
}
Then you can add the "Horizontal Tab" on the text that is focused, checking if you have already added:
function IndentRight_Click(event) {
let horizontalTab = " ";
let originalHtml = onFocus.innerHTML;
if (!originalHtml.includes("\t")) onFocus.innerHTML = horizontalTab + originalHtml;
onFocus.focus();
}
And finally, check for it again on your "Left Indentation":
function IndentLeft_Click(event) {
var originalHtml = onFocus.innerHTML;
if (originalHtml.includes("\t")) onFocus.innerHTML = originalHtml.replace("\t", "");
onFocus.focus();
}
I am just fooling around with some JavaScript, I am new to it so this is probably a simple solution. Basically what I want is for only 1 div to be visible at a time so if a user clicks on one link to expose a div the current div that is exposed will collapse and the new one clicked will appear.
I have included the code below:
<html>
<head>
<title> test</title>
<LINK href="blah.css" rel="stylesheet" type="text/css">
<script language="javascript" type="text/javascript">
function toggle2(showHideDiv, switchTextDiv) {
var ele = document.getElementById(showHideDiv);
var text = document.getElementById(switchTextDiv);
if(ele.style.display == "block") {
ele.style.display = "none";
text.innerHTML = "restore";
}
else {
ele.style.display = "block";
text.innerHTML = "collapse";
}
}
function toggle22(showHideDiv2, switchTextDiv2) {
var ele = document.getElementById(showHideDiv2);
var text = document.getElementById(switchTextDiv2);
if(ele.style.display == "block") {
ele.style.display = "none";
text.innerHTML = "restore";
}
else {
ele.style.display = "block";
text.innerHTML = "collapse";
}
}
</script>
</head>
<body>
<div id="mainContent">
<div id="headerDiv">
<div id="titleText">Change Password - Click here ==></div><a id="myHeader" href="javascript:toggle2('myContent','myHeader');" >restore</a>
</div>
<div style="clear:both;"></div>
<div id="contentDiv">
<div id="myContent" style="display: none;">This is the content that is dynamically being collapsed.</div>
<!--DIV2 -->
<div id="headerDiv2">
<div id="titleText2">Change Username - Click here ==></div><a id="myHeader2" href="javascript:toggle22('myContent2','myHeader2');" >restore</a>
</div>
<div style="clear:both;"></div>
<div id="contentDiv2">
<div id="myContent2" style="display: none;">This is the content that is dynamically being collapsed.</div>
</div>
</div>
</body>
</html>
The CSS:
#headerDiv, #contentDiv {
float: left;
width: 510px;
}
#titleText {
float: left;
font-size: 1.1em;
font-weight: bold;
margin: 5px;
}
#myHeader {
font-size: 1.1em;
font-weight: bold;
margin: 5px;
}
#headerDiv {
background-color: #0037DB;
color: #9EB6FF;
}
#contentDiv {
background-color: #FFE694;
}
#myContent {
margin: 5px 10px;
}
#headerDiv a {
color: gold;
float: right;
margin: 10px 10px 5px 5px;
}
#headerDiv a:hover {
color: #FFFFFF;
}
#headerDiv2, #contentDiv2 {
float: left;
width: 510px;
}
#titleText2 {
float: left;
font-size: 1.1em;
font-weight: bold;
margin: 5px;
}
#myHeader2 {
font-size: 1.1em;
font-weight: bold;
margin: 5px;
}
#headerDiv2 {
background-color: #0037DB;
color: #9EB6FF;
}
#contentDiv2 {
background-color: #FFE694;
}
#myContent2 {
margin: 5px 10px;
}
#headerDiv2 a {
color: gold;
float: right;
margin: 10px 10px 5px 5px;
}
#headerDiv2 a:hover {
color: #FFFFFF;
}
style.display only reflects the style that's been explicitly set on the element. Unless you specify it with style="display:block" in HTML, the initial value of style.display will be empty, even though the default value of that property, applied by CSS cascading, is indeed block.