Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>UK News</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet">
</head>

<body>
<div class="app">
<div class="header">
<div class="logo">UK News</div>
<div class="search_form">
<form class="search">
<input id='search' type="text" placeholder="Search all news...">
<button type="submit"><i class="fa fa-search"></i></button>
</form>
</div>
</div>
<div class="main">
<div id="newsfeed">

</div>
<button onclick="topFunction()" id="myBtn" title="Go to top">Go to Top</button>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to keep event handler setting in JS rather than apply inline

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

myBtn does not tell much about what the button does. Something more descriptive would work better

</div>
</div>
<script src="src/index.js"></script>
</body>
<footer>Powered by News API</footer>

</html>
167 changes: 167 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
const url =
"https://newsapi.org/v2/top-headlines?" +
"country=gb&" +
"apiKey=7318e7fb7dc04d14af2f0fd675cfda53";

const req = new Request(url);

// Fetch function for the main headlines
fetch(req)
.then(function(response) {
return response.json();
})

.then(function(body) {
displayArticles(body);
});


// Function which generates a div containing the article's headline, time, img, discription, source and link
function displayArticles(body) {
body.articles.forEach(article => {

//Timestamp is converted into GMT date and time format
const ts = new Date(`${article.publishedAt}`);
const date = ts.toGMTString();

//If article does not have description it will not be displayed
if (article.description) {
const divNode = document.createElement("div");

//Two divs are generated due to the final layout for wide screens
// one with img and one without;
const articleSource= article.source.id ? article.source.id : article.source.name

if (article.urlToImage) {
divNode.className = "article-div-w-img";

divNode.innerHTML = `<div class="title"><h2>${article.title}</h2></div>

<div class="date"><h4>${date}</h4></div>

<div class="img"><img src="${article.urlToImage}"></div>

<div class="content"><p>${article.description}</p></div>

<div class="source"><h4>Source: ${
article.source.name
}</h4></div>

<div class="more-news"><button class="news" data-source="${articleSource}">More headlines from this source</button></div>

<div class="link"><a href="${
article.url
}">Read all about it</a></div>`;
} else {
divNode.className = "article-div";

divNode.innerHTML = `<div class="title"><h2>${article.title}</h2></div>

<div class="date"><h4>${date}</h4></div>

<div class="content"><p>${article.description}</p></div>

<div class="source"><h4>Source: ${article.source.name}</h4></div>

<div class="more-news"><button class="news" data-source="${articleSource}>More headlines from this source</button></div>

<div class="link"><a href="${
article.url
}">Read all about it</a></div>`;
}

// The newly created article div is added to the newsfeed
const parentNode = document.querySelector("#newsfeed");
parentNode.appendChild(divNode);
};

});
}


//Add event listener to the search form
document.querySelector("form").addEventListener("submit", e => {
e.preventDefault();
let searchItem = document.querySelector("#search").value;
//The exisiting newsfeed is cleared before search results displayed
document.querySelector("#newsfeed").textContent = "";

const searchURL =
"https://newsapi.org/v2/everything?" +
`q=${searchItem}&` +
"from=2018-09-14&" +
"sortBy=popularity&" +
"language=en&" +
"apiKey=7318e7fb7dc04d14af2f0fd675cfda53";

const reqURL = new Request(searchURL);

fetch(reqURL)
.then(function(response) {
return response.json();
})

.then(function(body) {
displayArticles(body);
});

document.querySelector("#search").value = "";
});

// Tried adding an event listener to 'More news from this source button', but it does not seem to work.
document.querySelectorAll(".news").addEventListener("click", e => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

querySelectorAll returns a NodeList and we can't set an event handler on it. It would have to be done on each element in list individually


let requiredSource = e.target.dataset.source;

document.querySelector("#newsfeed").textContent = "";
let newSourceURL =
"https://newsapi.org/v2/top-headlines?" +
`sources=${requiredSource}&` +
"apiKey=7318e7fb7dc04d14af2f0fd675cfda53";

const source = new Request(newSourceURL);

fetch(source)
.then(function(response) {
return response.json();
})

.then(function(body) {
displayArticles(body);
//This is to remove 'More news from this source button' once the event listener function runs
document.querySelectorAll(".news").style.display = "none";
});
});

//Two functions are executed on scroll - sticky header and 'go to top' button
window.onscroll = function() {
myFunction(), scrollFunction();
Copy link
Contributor

@dmitrigrabov dmitrigrabov Sep 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the function calls should be separated by ; rather than ,

};

// myFunction() activates sticky header
var header = document.querySelector(".header");
var sticky = header.offsetTop;
// Add the sticky class to the header when you reach its scroll position. Remove "sticky" when you leave the scroll position
function myFunction() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function could have a more descriptive name

if (window.pageYOffset >= sticky) {
header.classList.add("sticky");
} else {
header.classList.remove("sticky");
}
}

// When the user scrolls down 20px from the top of the document, show the 'go to top' button
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
document.getElementById("myBtn").style.display = "block";
} else {
document.getElementById("myBtn").style.display = "none";
}
}

// When the user clicks on the 'go to top' button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0; // For Safari

document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
}
189 changes: 189 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
body {
margin: 0px;
}

html {
box-sizing: border-box;
font-family: "Ubuntu", Helvetica, Arial, sans-serif;
}
*,
*:before,
*:after {
/* display: none; */
box-sizing: inherit;
}

.header {
font-family: "Ubuntu", sans-serif;
font-size: 40px;
font-weight: 800;
background-color: #a2b6db;
margin: 0px;
padding: 0.2em;
}

/* The sticky class is added to the header with JS when it reaches its scroll position */
.sticky {
position: fixed;
top: 0;
width: 100%;
}

/* Add some top padding to the page content to prevent sudden quick movement (as the navigation bar gets a new position at the top of the page (position:fixed and top:0) */
.sticky + .main {
padding-top: 80px;
}

/* Style the search field */
form.search input[type="text"] {
padding: 10px;
font-size: 17px;
border: 1px solid grey;
float: left;
width: 80%;
background: #f1f1f1;
}

/* Style the submit button */
form.search button {
float: left;
width: 20%;
padding: 10px;
background: #bbd1e1;
color: white;
font-size: 17px;
border: 1px solid grey;
border-left: none; /* Prevent double borders */
cursor: pointer;
}

form.search button:hover {
background: #95b8d1;
}

/* Clear floats */
form.search::after {
content: "";
clear: both;
display: table;
}

main {
margin: 0px;
}

/*No image displayed in mobile version*/
img {
display: none;
}

h2 {
font-size: 1.2em;
background-color: #d1ebe2;
margin: 0;
}

h4 {
margin: 0.5em 0em 0em 0em;
}

.article-div,
.article-div-w-img {
display: flex;
flex-flow: wrap;
background-color: #f7fbf9;
margin: 2em 1em 1em 1em;
}

.title,
.date,
.link {
width: 100vw;
}

.more-news {
align-self: flex-end;
}

.source {
margin: 0em 2em 0em 0em;
}

.news {
background-color: #d5b3c2;
border-radius: 6px;
}

.news:hover {
background-color: #d64f89;
}

footer {
text-align: right;
margin: 1em;
font-size: 70%;
}

/* CSS relating to 'Go to top' button */
#myBtn {
display: none; /* Hidden by default */
position: fixed; /* Fixed/sticky position */
bottom: 2em;
right: 1em;
z-index: 99; /* Make sure it does not overlap */
border: none;
outline: none;
background-color: #a2b6db;
cursor: pointer; /* Add a mouse pointer on hover */
padding: 15px;
border-radius: 10px;
font-size: 18px;
}

#myBtn:hover {
background-color: #bbd1e1;
}

@media (min-width: 768px) {
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
}

/* Article background colour changes on hover */
.article-div-w-img:hover {
background-color: #f9eef3;
}

/* Where the article has an image, the image and the description will be placed side by side */
.article-div-w-img > .content,
.img {
width: 46vw;
}

img {
display: block;
height: auto;
max-width: 97%;
}

.link {
text-align: right;
}

.article-div {
display: flex;
flex-flow: wrap;
}

.article-div > .content {
width: 100vw;
}

/* Changed 'Go to Top' button position for larger screen due to the general changes in conents position */
#myBtn {
bottom: 3em;
right: 10em;
}
}