- HTML
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@500&display=swap" rel="stylesheet">
<script src="js/main.js"></script>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div class="background-header"></div>
<div class="background-body"></div>
<div class="wrap">
<div class="header">
<h2>Timeline Service</h2>
<p>
공유하고 싶은 소식을 입력해주세요.<br>
24시간이 지난 뒤에는 사라집니다.d
</p>
</div>
<div class="area-write">
<textarea class="field" name="contents" id="contents" cols="30" rows="10" placeholder="공유하고 싶은 소식을 공유해 주세요"></textarea>
<img src="images/send.png" alt="" onclick="writePost()">
</div>
<div id="cards-box" class="area-read">
<div class="card">
<div class="meta-data">
<div class="date">
October 10, 2020
</div>
<div class="username">
anonymous
</div>
</div>
<div class="contents">
<div id="1-contents" class="text">
dsafnkalfklewakflekelafkleajfkleafkldsankflenwaklfnekwlafneklwanfkelawnfkelanfkleanfklew
</div>
<div id="1-editarea" class="edit">
<textarea name="" id="1-textarea" class="te-edit" cols="30" rows="10"></textarea>
</div>
</div>
<div class="footer">
<img src="images/edit.png" id="1-edit" class="icon-start-edit" alt="" onclick="editPost('1')">
<img src="images/delete.png" id="1-delete" class="icon-delete" alt="" onclick="deleteOne('1')">
<img src="images/done.png" id="1-submit" class="icon-end-edit" alt="" onclick="submitEdit('1')">
</div>
</div>
</div>
</div>
</body>
</html>
- Javascript
function isValidContents(contents) {
if (contents === "") {
alert("내용을 입력해주세요");
return false;
}
if (contents.trim().length > 140) {
alert("내용은 140자 이내(공백 포함)이어야 합니다.")
return false;
}
return true;
}
function genRandomName(length) {
let result = '';
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let charactersLength = characters.length;
for (let i = 0; i < length; i++) {
let number = Math.random() * charactersLength;
let index = Math.floor(number);
result += characters.charAt(index);
}
return result;
}
$(document).ready(function (){
getMessages();
});
function writePost() {
let contents = $('#contents').val();
if (isValidContents(contents)=== false) {
return ;
}
let username = genRandomName(10);
let data = {'username': username, 'contents': contents}
$.ajax({
type: 'POST',
url: '/api/memos',
contentType: 'application/json',
data: JSON.stringify(data),
success:function(response){
alert('당신의 소식을 저장하였습니다')
window.location.reload();
}
});
}
function getMessages() {
$('#cards-box').empty();
$.ajax({
type: 'GET',
url: '/api/memos',
success:function(response) {
for (let responseElement of response) {
let id = responseElement.id;
let username = responseElement.username;
let contents = responseElement.contents;
let modifiedAt = responseElement.modifiedAt;
addHTML(id, username, contents, modifiedAt)
}
}
});
}
function addHTML(id, username, contents, modifiedAt) {
let tempHTML = `<div class="card">
<div class="meta-data">
<div class="date">${modifiedAt}</div>
<div class="username" id="${id}-username">
${username}
</div>
</div>
<!-- 그냥 보이는 Text or textarea -->
<div class="contents">
<div id="${id}-contents" class="text">
${contents}
</div>
<div id="${id}-editarea" class="edit">
<textarea name="" id="${id}-textarea" class="te-edit" cols="30" rows="5"></textarea>
</div>
<div class="footer">
<img id="${id}-edit" src="images/edit.png" class="icon-start-edit"token interpolation">${id}')" alt="">
<img id="${id}-delete" src="images/delete.png" class="icon-delete"token interpolation">${id}')" alt="">
<img id="${id}-submit" src="images/done.png" class="icon-end-edit"token interpolation">${id}')" alt="">
</div>
</div>
</div>`
$('#cards-box').append(tempHTML);
}
function editPost(id) {
showEdits(id);
let contents = $(`#${id}-contents`).text().trim();
$(`#${id}-textarea`).val(contents);
}
function showEdits(id) {
$(`#${id}-submit`).show();
$(`#${id}-editarea`).show();
$(`#${id}-delete`).show();
$(`#${id}-edit`).hide();
$(`#${id}-contents`).hide();
}
function hideEdits(id) {
$(`#${id}-edit`).show();
$(`#${id}-contents`).show();
$(`#${id}-delete`).hide();
$(`#${id}-submit`).hide();
$(`#${id}-editarea`).hide();
}
function submitEdit(id) {
let username = $(`#${id}-username`).text().trim();
let contents = $(`#${id}-textarea`).val().trim();
if (isValidContents(contents) === false) {
return;
}
let data = {'username': username, 'contents': contents};
console.log(data);
$.ajax({
type: 'PUT',
url: `/api/memos/${id}`,
contentType: 'application/json',
data: JSON.stringify(data),
success: function (response){
alert('고객님의 소식을 수정하였습니다');
window.location.reload();
}
})
}
function deleteOne(id){
$.ajax({
type: 'DELETE',
url: `/api/memos/${id}`,
success: function (response) {
let deletedId = response.id;
alert('당신의 글이 삭제되었습니다');
window.location.reload();
}
});
}
- CSS
body {
margin: 0;
}
.background-header {
position: fixed;
top: 0;
width: 100%;
height: 428px;
background-color: #339af0;
z-index: -1;
}
.background-body {
position: fixed;
background-color: #dee2e6;
top: 428px;
width: 100%;
height: 100%;
z-index: -1;
}
.wrap {
width: 538px;
margin: 10px auto;
}
.header {
margin-top: 50px;
}
.header h2 {
height: 33px;
color: #ffffff;
font-size: 42px;
font-weight: 500;
font-stretch: normal;
font-style: normal;
line-height: 0.79;
letter-spacing: -0.5px;
text-align: center;
}
.header p {
width: 220px;
height: 48px;
margin: 40px auto;
font-family: 'Noto Sans KR', sans-serif;
font-size: 16px;
font-weight: 500;
font-stretch: normal;
font-style: normal;
line-height: 1.5;
letter-spacing: -1.12px;
text-align: center;
color: #ffffff;
}
textarea.field {
width: 502px;
height: 146px;
border: none;
border-radius: 5px;
padding: 18px;
background-color: #fff;
}
textarea.field::placeholder {
width: 300px;
height: 16px;
font-family: 'Noto Sans KR', sans-serif;
font-size: 16px;
font-weight: normal;
font-stretch: normal;
font-style: normal;
line-height: 1;
letter-spacing: -0.96px;
color: #868e96;
text-align: left;
}
.area-write {
position: relative;
width: 538px;
}
.area-write img {
cursor: pointer;
width: 22.2px;
height: 18.7px;
position: absolute;
bottom: 15px;
right: 17px;
}
#cards-box {
margin-top: 12px;
}
.card {
width: 538px;
background-color: #fff;
border-radius: 5px;
margin-bottom: 12px;
}
.card .meta-data {
position: relative;
display: flex;
font-family: 'Spoqa Han Sans';
font-size: 11px;
font-weight: normal;
font-stretch: normal;
font-style: normal;
line-height: 1;
letter-spacing: -0.77px;
text-align: left;
color: #adb5bd;
height: 14px;
padding: 10px 23px;
}
.card .meta-data .username {
margin-left: 20px;
}
.contents {
padding: 0 23px;
word-wrap: break-word;
word-break: break-all;
}
.contents div.edit {
display: none;
}
.contents textarea.te-edit {
border-top: none;
border-right: none;
border-left: none;
resize: none;
border-bottom: 1px solid #212529;
width: 100%;
font-family: 'Spoqa Han Sans';
}
.footer {
height: 40px;
position: relative;
}
.footer .icon-start-edit {
cursor: pointer;
position: absolute;
bottom: 14px;
right: 55px;
width: 18px;
height: 18px;
}
.footer .icon-delete {
cursor: pointer;
position: absolute;
bottom: 12px;
right: 19px;
width: 14px;
height: 18px;
}
.footer .icon-end-edit {
cursor: pointer;
position: absolute;
display: none;
bottom: 14px;
right: 55px;
width: 20px;
height: 15px;
}