|
@@ -13,33 +13,30 @@
|
|
|
let ssIsLogin = null;
|
|
|
let targetFeed = null;
|
|
|
let username = null;
|
|
|
- const options = { method: 'GET' };
|
|
|
+ const options = {
|
|
|
+ method: 'GET'
|
|
|
+ };
|
|
|
const tagSet = new Set();
|
|
|
let tagArray = [];
|
|
|
+ // fetch url info
|
|
|
+ const selectFeed = ("${ssIsLogin}" === "true") ? 'your-feed' : 'flobal-feed';
|
|
|
let params = {
|
|
|
- articleId: -1,
|
|
|
- feed: selectFeed()
|
|
|
- };
|
|
|
-
|
|
|
+ articleId: -1,
|
|
|
+ feed: selectFeed
|
|
|
+ };
|
|
|
let query = Object.keys(params)
|
|
|
- .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
|
|
|
- .join('&');
|
|
|
-
|
|
|
+ .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
|
|
|
+ .join('&');
|
|
|
let url = '/article/page?' + query;
|
|
|
-
|
|
|
- function selectFeed() {
|
|
|
- if ("${ssIsLogin}" === 'true') {
|
|
|
- return 'your-feed'
|
|
|
- } else {
|
|
|
- return 'global-feed';
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
// 1. feed를 바꾼 경우
|
|
|
// 2. 태그를 클릭한 경우
|
|
|
const filterArticle = (option) => {
|
|
|
- const { clickedTag, clickedFeed } = option;
|
|
|
- const articles = window.document.querySelectorAll('.article-preview');
|
|
|
+ const {
|
|
|
+ clickedTag,
|
|
|
+ clickedFeed
|
|
|
+ } = option;
|
|
|
+ const articles = window.document.querySelectorAll('.article-preview');
|
|
|
const articleList = document.querySelector('#article-list');
|
|
|
|
|
|
articles.forEach(article => {
|
|
@@ -55,12 +52,8 @@
|
|
|
} else if (clickedTag !== undefined) { // 태그가 클릭된 경우
|
|
|
const tags = article.querySelectorAll('.tag');
|
|
|
const tagSet = new Set(Array.from(tags).map(tag => tag.textContent));
|
|
|
-
|
|
|
- if (targetFeed.id === 'global-feed' && tagSet.has(clickedTag)) {
|
|
|
- display = 'block';
|
|
|
- }
|
|
|
|
|
|
- if (targetFeed.id === 'your-feed' && username === writerName && tagSet.has(clickedTag)) {
|
|
|
+ if (tagSet.has(clickedTag)) {
|
|
|
display = 'block';
|
|
|
}
|
|
|
}
|
|
@@ -87,6 +80,22 @@
|
|
|
tagList.style.display = contentDisplay;
|
|
|
}
|
|
|
|
|
|
+ // 자신의 게시글이 없는 경우
|
|
|
+ const noContent = () => {
|
|
|
+ articleList = document.querySelector('#article-list');
|
|
|
+ tagList = document.querySelector('#tag-list');
|
|
|
+
|
|
|
+ if (articleList.firstChild === null) {
|
|
|
+ const p = document.createElement('p');
|
|
|
+ const pTag = document.createElement('p');
|
|
|
+
|
|
|
+ p.classList.add('article-preview');
|
|
|
+ p.textContent = 'No articles are here... yet.';
|
|
|
+ pTag.textContent = 'No tags are here... yet.';
|
|
|
+ articleList.appendChild(p);
|
|
|
+ tagList.appendChild(pTag);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
const focusFeed = () => {
|
|
|
// 이미 포커싱된 탭이라면 중지
|
|
@@ -96,10 +105,23 @@
|
|
|
}
|
|
|
|
|
|
const unFocusedFeed = parentNode;
|
|
|
- const currentFeed = (unFocusedFeed.id === 'global-feed') ? window.document.querySelector('#your-feed') : window.document.querySelector('#global-feed');
|
|
|
+ const currentFeed = (unFocusedFeed.id === 'global-feed') ? window.document.querySelector('#your-feed') :
|
|
|
+ window.document.querySelector('#global-feed');
|
|
|
|
|
|
unFocusedFeed.classList.add('active');
|
|
|
- currentFeed.classList.remove('active');
|
|
|
+ if ("${ssIsLogin}" === "true") {
|
|
|
+ currentFeed.classList.remove('active');
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // your-feed 또는 global-feed 클릭시 tag-feed 없애기
|
|
|
+ const tagToggle = document.querySelector('#tag-feed');
|
|
|
+ const spanTag = document.querySelector('#tag-feed span');
|
|
|
+ if (tagToggle.classList.contains('active')) {
|
|
|
+ tagToggle.classList.remove('active');
|
|
|
+ spanTag.textContent = null;
|
|
|
+ document.querySelector('.fa-hashtag').style.display = 'none';
|
|
|
+ }
|
|
|
|
|
|
// targetFeed 초기화
|
|
|
targetFeed = unFocusedFeed;
|
|
@@ -108,83 +130,92 @@
|
|
|
// 태그와 게시글 초기화
|
|
|
tagArray = [];
|
|
|
articleList = document.querySelector('#article-list');
|
|
|
- while(articleList.firstChild) {
|
|
|
+ while (articleList.firstChild) {
|
|
|
articleList.firstChild.remove();
|
|
|
}
|
|
|
|
|
|
- params['articleId'] = -1;
|
|
|
- params['feed'] = targetFeed.id;
|
|
|
-
|
|
|
+ params = {
|
|
|
+ articleId: -1,
|
|
|
+ feed: targetFeed.id
|
|
|
+ };
|
|
|
query = Object.keys(params)
|
|
|
- .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
|
|
|
- .join('&');
|
|
|
+ .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
|
|
|
+ .join('&');
|
|
|
url = '/article/page?' + query;
|
|
|
|
|
|
fetch(url, options)
|
|
|
.then(response => response.json())
|
|
|
.then(json => {
|
|
|
- const { articles, paging } = json;
|
|
|
+ const {
|
|
|
+ articles,
|
|
|
+ paging
|
|
|
+ } = json;
|
|
|
username = "${ssUsername}";
|
|
|
|
|
|
loadArticle(articles);
|
|
|
nextPageLoad(articles, paging);
|
|
|
+ console.log(tagArray);
|
|
|
});
|
|
|
|
|
|
- filterArticle({ 'clickedFeed': unFocusedFeed.id })
|
|
|
+ filterArticle({
|
|
|
+ 'clickedFeed': unFocusedFeed.id
|
|
|
+ })
|
|
|
setTimeout(() => {
|
|
|
setLoading('off');
|
|
|
+ noContent();
|
|
|
}, 2000);
|
|
|
}
|
|
|
|
|
|
// 좋아요 버튼
|
|
|
- function favoriteBtn(indexNumber) {
|
|
|
+ const favoriteBtn = (indexNumber) => {
|
|
|
const favoriteNum = event.target.querySelector('.count').textContent;
|
|
|
const favorite = event.target.querySelector('.favorite-btn');
|
|
|
let counts = parseInt(favoriteNum);
|
|
|
let newCounts = counts + 1;
|
|
|
- console.log(event.target);
|
|
|
-
|
|
|
+
|
|
|
// 로그인한 경우에만 실행
|
|
|
if ("${ssIsLogin}" === "true") {
|
|
|
if (event.target.classList.contains('active')) { // 이미 좋아요 버튼을 클릭한 경우
|
|
|
event.target.querySelector('.count').textContent = counts - 1;
|
|
|
event.target.classList.remove('active');
|
|
|
|
|
|
- fetch('/article/' + indexNumber + '/favorite', { method: 'DELETE' })
|
|
|
+ fetch('/article/' + indexNumber + '/favorite', {
|
|
|
+ method: 'DELETE'
|
|
|
+ })
|
|
|
.then(response => {
|
|
|
if (response.status === 200) {
|
|
|
- return ;
|
|
|
+ return;
|
|
|
}
|
|
|
});
|
|
|
- } else { // 좋아요 버튼을 클릭하지 않을 경우
|
|
|
+ } else { // 좋아요 버튼을 클릭하지 않은 경우
|
|
|
event.target.querySelector('.count').textContent = newCounts;
|
|
|
- event.target.classList.add('active')
|
|
|
+ event.target.classList.add('active');
|
|
|
|
|
|
fetch('/article/' + indexNumber + '/favorite', {
|
|
|
- body: JSON.stringify({
|
|
|
- articleId: indexNumber,
|
|
|
- userId: "${ssId}",
|
|
|
- created: new Date()
|
|
|
- }),
|
|
|
- method: 'POST',
|
|
|
- headers: {
|
|
|
- "Content-Type": "application/json"
|
|
|
- }
|
|
|
- })
|
|
|
+ body: JSON.stringify({
|
|
|
+ articleId: indexNumber,
|
|
|
+ userId: "${ssId}",
|
|
|
+ created: new Date()
|
|
|
+ }),
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json"
|
|
|
+ }
|
|
|
+ })
|
|
|
.then(response => {
|
|
|
if (response.status === 201) {
|
|
|
- return ;
|
|
|
+ return;
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
} else {
|
|
|
location.href = "/user/signin"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 태그 정렬 https://curryyou.tistory.com/229
|
|
|
- function getSortedArr(array) {
|
|
|
+ const getSortedArr = (array) => {
|
|
|
// 출현 빈도 구하기
|
|
|
const counts = array.reduce((pv, cv) => {
|
|
|
pv[cv] = (pv[cv] || 0) + 1;
|
|
@@ -202,51 +233,54 @@
|
|
|
return second[1] - first[1];
|
|
|
});
|
|
|
|
|
|
+ // 최대 10개까지만 표시
|
|
|
return result.slice(0, 10);
|
|
|
}
|
|
|
|
|
|
- // 클릭한 태그 표시
|
|
|
- function tagFilter(event) {
|
|
|
+ // 현재 클릭한 태그 표시
|
|
|
+ const focusTag = () => {
|
|
|
let currentValue = document.querySelector('.tag.active');
|
|
|
|
|
|
if (currentValue !== null) {
|
|
|
- currentValue.classList.remove('active');
|
|
|
+ currentValue.classList.remove('active');
|
|
|
}
|
|
|
event.target.classList.add('active');
|
|
|
}
|
|
|
|
|
|
// 게시글 및 태그 표시
|
|
|
- function loadArticle(articles) {
|
|
|
+ const loadArticle = (articles) => {
|
|
|
articles.forEach(article => {
|
|
|
console.log(JSON.stringify(article))
|
|
|
const domParser = new DOMParser();
|
|
|
-
|
|
|
+
|
|
|
// 게시글 정보 표시
|
|
|
const domStrArticleMeta =
|
|
|
`
|
|
|
<div class="article-meta">
|
|
|
<div class="metadata">
|
|
|
- <a href="#" class="profile-link">
|
|
|
+ <a href="/user/\${article.writerId}" class="profile-link">
|
|
|
<img src="/resources/images/avatar.png" alt="avatar">
|
|
|
</a>
|
|
|
<div class="article-info">
|
|
|
- <a href="#" class="name"></a>
|
|
|
+ <a href="/user/\${article.writerId}" class="name"></a>
|
|
|
<span class="date"></span>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div>
|
|
|
- <button class="favorite-btn \${article.id}" onclick="favoriteBtn(\${article.id})">
|
|
|
+ <button class="favorite-btn" onclick="favoriteBtn(\${article.id})">
|
|
|
<i class="fas fa-heart"></i>
|
|
|
<span class="count">\${article.favoriteNum}</span>
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
`;
|
|
|
- const divArticleMeta = domParser.parseFromString(domStrArticleMeta, 'text/html').body.firstChild;
|
|
|
+ const divArticleMeta = domParser.parseFromString(domStrArticleMeta, 'text/html').body
|
|
|
+ .firstChild;
|
|
|
divArticleMeta.querySelector('.name').textContent = article.writerName;
|
|
|
divArticleMeta.querySelector('.date').textContent = new Date(article.created).toLocaleString();
|
|
|
-
|
|
|
- if(article.favorite) {
|
|
|
+
|
|
|
+ // 좋아요한 게시글의 경우
|
|
|
+ if (article.favorite) {
|
|
|
divArticleMeta.querySelector('.favorite-btn').classList.add('active');
|
|
|
}
|
|
|
|
|
@@ -294,26 +328,27 @@
|
|
|
|
|
|
articleList.appendChild(articlePreview);
|
|
|
|
|
|
- // 태그 배열 생성
|
|
|
- let tagsArray = article.tags.split(',')
|
|
|
+ // Popular tag 배열 생성
|
|
|
+ let tagsArray = article.tags.split(',');
|
|
|
const tagList = document.querySelector('#tag-list');
|
|
|
-
|
|
|
- while(tagList.firstChild) {
|
|
|
+
|
|
|
+ while (tagList.firstChild) {
|
|
|
tagList.firstChild.remove();
|
|
|
}
|
|
|
|
|
|
tagsArray.forEach(tag => {
|
|
|
-
|
|
|
+
|
|
|
if (tag !== '') {
|
|
|
tagArray.push(tag);
|
|
|
}
|
|
|
})
|
|
|
});
|
|
|
|
|
|
- // 태그 표시
|
|
|
+
|
|
|
const tags = Array.from(tagSet);
|
|
|
const tagList = window.document.querySelector('#tag-list');
|
|
|
|
|
|
+ // Popular tag 표시
|
|
|
getSortedArr(tagArray).forEach(tag => {
|
|
|
const a = document.createElement('a');
|
|
|
const tagString = tag.join(',');
|
|
@@ -323,19 +358,40 @@
|
|
|
a.classList.add("tag");
|
|
|
a.textContent = `\${tagValue} (\${tagCount})`
|
|
|
a.onclick = (event) => {
|
|
|
- // 해당 태그의 토글버튼 생성
|
|
|
const tagToggle = document.querySelector('#tag-feed');
|
|
|
- tagToggle.textContent = tagValue;
|
|
|
-
|
|
|
+ const yourToggle = document.querySelector('#your-feed');
|
|
|
+ const globalToggle = document.querySelector('#global-feed');
|
|
|
+ const moreBtn = document.querySelector('.more-button');
|
|
|
+ const spanTag = document.querySelector('#tag-feed span');
|
|
|
+
|
|
|
// 해당 태그의 게시물 표시
|
|
|
- filterArticle({ 'clickedTag': tagValue });
|
|
|
+ filterArticle({
|
|
|
+ 'clickedTag': tagValue
|
|
|
+ });
|
|
|
+
|
|
|
+ // 해당 태그의 토글버튼 생성
|
|
|
+ document.querySelector('.fa-hashtag').style.display = 'block';
|
|
|
+ spanTag.textContent = '\u00A0' + tagValue;
|
|
|
+ tagToggle.classList.add('active');
|
|
|
+ globalToggle.classList.remove('active');
|
|
|
+
|
|
|
+ // 로그인한 경우에만 your-feed가 생기므로 조건문 처리
|
|
|
+ if ("${ssIsLogin}" === "true") {
|
|
|
+ yourToggle.classList.remove('active');
|
|
|
+ }
|
|
|
+
|
|
|
+ // more 버튼 삭제
|
|
|
+ if (moreBtn !== null) {
|
|
|
+ moreBtn.remove();
|
|
|
+ }
|
|
|
}
|
|
|
tagList.appendChild(a);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- //다음페이지 로드
|
|
|
- function nextPageLoad(articles, paging) {
|
|
|
+ // 다음페이지 로드
|
|
|
+ const nextPageLoad = (articles, paging) => {
|
|
|
+ // 더 조회될 수 있는 게시글이 있는지 여부
|
|
|
if (paging.isNext) {
|
|
|
const moreButton = document.createElement('button');
|
|
|
const articleList = document.querySelector('#article-list');
|
|
@@ -349,9 +405,9 @@
|
|
|
// more 버튼 클릭 시 다음페이지 게시물을 가져온다
|
|
|
moreButton.onclick = () => {
|
|
|
articleList.removeChild(moreButton);
|
|
|
- articleList.appendChild(loading);
|
|
|
+ articleList.appendChild(loading); // 로딩 생성
|
|
|
|
|
|
- // 마지막 게시글의 id
|
|
|
+ // 현재 페이지의 마지막 게시글 id
|
|
|
params['articleId'] = articles[articles.length - 1].id;
|
|
|
query = Object.keys(params)
|
|
|
.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
|
|
@@ -361,12 +417,16 @@
|
|
|
fetch(url, options)
|
|
|
.then(response => response.json())
|
|
|
.then(json => {
|
|
|
- const { articles, paging } = json;
|
|
|
+ const {
|
|
|
+ articles,
|
|
|
+ paging
|
|
|
+ } = json;
|
|
|
username = "${ssUsername}";
|
|
|
- articleList.removeChild(loading);
|
|
|
- loadArticle(articles);
|
|
|
- nextPageLoad(articles, paging);
|
|
|
-
|
|
|
+ setTimeout(() => {
|
|
|
+ articleList.removeChild(loading);
|
|
|
+ loadArticle(articles);
|
|
|
+ nextPageLoad(articles, paging);
|
|
|
+ }, 1000);
|
|
|
})
|
|
|
}
|
|
|
}
|
|
@@ -376,7 +436,8 @@
|
|
|
|
|
|
ssIsLogin = "${ssIsLogin}";
|
|
|
|
|
|
- targetFeed = (ssIsLogin === "true") ? window.document.querySelector('#your-feed') : window.document.querySelector('#global-feed');
|
|
|
+ targetFeed = (ssIsLogin === "true") ? window.document.querySelector('#your-feed') : window.document
|
|
|
+ .querySelector('#global-feed');
|
|
|
targetFeed.classList.add('active');
|
|
|
|
|
|
loadingTag = window.document.querySelector('#tag-loading');
|
|
@@ -385,43 +446,28 @@
|
|
|
noTag = window.document.querySelector('#no-tag');
|
|
|
tagList = window.document.querySelector('#tag-list');
|
|
|
|
|
|
- //fetch api call
|
|
|
- let params = {
|
|
|
- articleId: -1,
|
|
|
- feed: selectFeed()
|
|
|
- };
|
|
|
- let query = Object.keys(params)
|
|
|
- .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
|
|
|
- .join('&');
|
|
|
- let url = '/article/page?' + query;
|
|
|
-
|
|
|
setLoading('on');
|
|
|
-
|
|
|
+ //fetch api call
|
|
|
fetch(url, options)
|
|
|
.then(response => response.json())
|
|
|
.then(json => {
|
|
|
- const { articles, paging } = json;
|
|
|
+ const {
|
|
|
+ articles,
|
|
|
+ paging
|
|
|
+ } = json;
|
|
|
username = "${ssUsername}";
|
|
|
|
|
|
loadArticle(articles);
|
|
|
nextPageLoad(articles, paging);
|
|
|
-
|
|
|
+ console.log(articles)
|
|
|
+
|
|
|
// hide loadings
|
|
|
- setLoading('off');
|
|
|
-
|
|
|
-
|
|
|
- // loadingTag.style.display = 'none';
|
|
|
- // loadingArticle.style.display = 'none';
|
|
|
-
|
|
|
- // // show articles and tags
|
|
|
- // articleList.style.display = 'block';
|
|
|
- // if (tagSet.size === 0) {
|
|
|
- // noTag.style.display = 'block';
|
|
|
- // } else {
|
|
|
- // tagList.style.display = 'block';
|
|
|
- // }
|
|
|
+ setTimeout(() => {
|
|
|
+ setLoading('off');
|
|
|
+ noContent();
|
|
|
+ }, 2000);
|
|
|
});
|
|
|
- }
|
|
|
+ }
|
|
|
</script>
|
|
|
<style>
|
|
|
|
|
@@ -461,7 +507,10 @@
|
|
|
Feed</a>
|
|
|
</li>
|
|
|
<li id="tag-feed" class="nav-item">
|
|
|
- <a href="javascript:void(0);"></a>
|
|
|
+ <a href="javascript:void(0);">
|
|
|
+ <i class="fas fa-hashtag" style="display: none;"></i>
|
|
|
+ <span></span>
|
|
|
+ </a>
|
|
|
</li>
|
|
|
</ul>
|
|
|
</div>
|
|
@@ -474,9 +523,7 @@
|
|
|
</article>
|
|
|
|
|
|
<!-- article list -->
|
|
|
- <div id="article-list" style="display: none;">
|
|
|
- <!-- <article class="noArticle" style="display: none;">Feed not here yet.</article> -->
|
|
|
- </div>
|
|
|
+ <div id="article-list" style="display: none;"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
@@ -490,7 +537,7 @@
|
|
|
</div>
|
|
|
|
|
|
<!-- 태그 -->
|
|
|
- <div id="tag-list" class="tag-list" style="display: none;" onclick="tagFilter(event)">
|
|
|
+ <div id="tag-list" class="tag-list" style="display: none;" onclick="focusTag()">
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|