Merge pull request #8 from Gyubin-Han/feature/frontend
Feat: 단축 URL 생성 페이지 구현
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -54,6 +54,7 @@ node_modules/
|
||||
# OS specific
|
||||
.DS_Store
|
||||
# Task files
|
||||
.taskmaster
|
||||
tasks.json
|
||||
tasks/
|
||||
|
||||
@@ -66,3 +67,5 @@ scripts/
|
||||
.taskmasterconfig
|
||||
.windsurfrules
|
||||
compose.yaml
|
||||
|
||||
js/
|
||||
|
||||
209
src/main/resources/templates/index.html
Normal file
209
src/main/resources/templates/index.html
Normal file
@@ -0,0 +1,209 @@
|
||||
<script>
|
||||
const VALIDATE_URL="^((http|https):\\/\\/)?([a-z0-9-]{2,}\\.[a-z]{2,}|([0-9]{1,3}\\.){3}[0-9]{1,3})[\\w.\\/가-힣\\-\\ ?=&:]*";
|
||||
|
||||
// DOM 객체(요소) 체이닝 생성 클래스
|
||||
class Element{
|
||||
// 생성자
|
||||
// type(string) : 요소(태그)의 종류 정의
|
||||
constructor(type){
|
||||
this.element=document.createElement(type);
|
||||
this.element.eventList={}
|
||||
}
|
||||
|
||||
// 하위에 DOM 객체(요소)를 추가하는 메소드
|
||||
// child(Object(Element) || DOMObject) : 하위에 추가할 요소
|
||||
append(child){
|
||||
// child가 Object(Element)인 경우, 하위에 있는 element를 가져와 추가하고,
|
||||
// 아닌 경우, child를 그대로 추가
|
||||
this.element.append(child.element || child);
|
||||
return this;
|
||||
}
|
||||
// 요소 내 html 코드를 직접 설정하는 메소드
|
||||
html(html){
|
||||
this.element.innerHTML=html;
|
||||
return this;
|
||||
}
|
||||
// 요소에 표시할 text 값을 설정하는 메소드
|
||||
text(text){
|
||||
this.element.textContent=text;
|
||||
return this;
|
||||
}
|
||||
// 요소에 class를 추가하는 메소드
|
||||
addClass(name){
|
||||
this.element.classList.add(name);
|
||||
return this;
|
||||
}
|
||||
// 요소에 추가되어 있는 class를 제거하는 메소드
|
||||
removeClass(name){
|
||||
this.element.classList.remove(name);
|
||||
return this;
|
||||
}
|
||||
// 링크 값을 설정하는 메소드
|
||||
href(link){
|
||||
this.element.href=link;
|
||||
return this;
|
||||
}
|
||||
// id 값을 설정하는 메소드
|
||||
id(value){
|
||||
this.element.id=value;
|
||||
return this;
|
||||
}
|
||||
// 요소의 속성 값을 설정하는 메소드
|
||||
setAttr(name,value){
|
||||
this.element.setAttribute(name,value);
|
||||
return this;
|
||||
}
|
||||
// 요소에 설정되어 있는 속성을 제거하는 메소드
|
||||
removeAttr(name){
|
||||
this.element.removeAttribute(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
// 이벤트 리스너를 추가하는 메소드
|
||||
// type(string) : 감지될 이벤트 타입
|
||||
// action(func) : 해당 이벤트가 발생했을 때, 처리될 이벤트 핸들러 함수
|
||||
addEventListener(type,action){
|
||||
this.element.eventList[type]=action;
|
||||
this.element.addEventListener(type,action);
|
||||
return this;
|
||||
}
|
||||
// 추가되어 있는 이벤트 리스너를 제거하는 메소드
|
||||
// type(string) : 제거할 이벤트 타입
|
||||
removeEventListener(type){
|
||||
this.element.eventList[type]=null;
|
||||
this.element.removeEventListener(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
// 최종적으로 완성된 Element 객체를 DOM 요소 형태로 반환
|
||||
get(){
|
||||
return this.element;
|
||||
}
|
||||
}
|
||||
|
||||
// 단축 URL의 복사 버튼을 클릭하였을 때 동작되는 이벤트 함수
|
||||
function clickBtnShortUrlCopy(shortId){
|
||||
// 이 단축 URL의 사용자 내부 ID 값을 통하여, 단축 URL 값을 추출
|
||||
// 주소를 복사할 범위 객체 생성
|
||||
const range=document.createRange();
|
||||
// 범위를 드래그할 객체 생성
|
||||
const selection=window.getSelection();
|
||||
// 드래그하기 전, 기존에 드래그 된 것은 제거
|
||||
selection.removeAllRanges();
|
||||
|
||||
// 범위 지정
|
||||
range.selectNodeContents(document.querySelector(".short-item[data-id='"+shortId+"'] .short-item-short-url"));
|
||||
// 범위를 실제 드래그한 범위로 지정
|
||||
selection.addRange(range);
|
||||
// 사용자 클라이언트의 클립보드에 복사
|
||||
document.execCommand("copy");
|
||||
// 복사 후, 기존의 드래그 범위를 제거
|
||||
selection.removeAllRanges();
|
||||
|
||||
// 사용자에게 성공적으로 복사되었음을 알림
|
||||
alert("성공적으로 복사되었습니다!");
|
||||
}
|
||||
|
||||
// 단축 URL 생성에 성공한 경우 동작하는 메소드
|
||||
// 단축 URL의 정보를 사용자 화면에 출력
|
||||
function createShortResultElement(data){
|
||||
// 사용자의 접속 기본 정보를 추출
|
||||
const userProtocol=window.location.protocol;
|
||||
const userHost=window.location.host;
|
||||
const shortUrl=userProtocol+"//"+userHost+"/"+data.shortUrl;
|
||||
|
||||
// 사용자 화면에 출력될 요소 생성 및 하위 요소 생성, 설정
|
||||
var newRootElement=new Element("td");
|
||||
newRootElement.text("단축되었습니다!");
|
||||
newRootElement.append(
|
||||
new Element("ul")
|
||||
.append(new Element("li").text("원본 URL : "+data.originalUrl).addClass("short-item-original-url"))
|
||||
.append(new Element("li").html("단축 URL : "+data.shortUrl+"<br>\n")
|
||||
.append(new Element("span").html(shortUrl).addClass("short-item-short-url"))
|
||||
.append(new Element("button").text("복사하기").addEventListener("click",function() { clickBtnShortUrlCopy(data.shortUrl); }))
|
||||
)
|
||||
.append(new Element("li").text("유효기간 : "+data.expiredAt))
|
||||
)
|
||||
newRootElement.setAttr("data-id",data.shortUrl);
|
||||
newRootElement.addClass("short-item")
|
||||
|
||||
// 위에서 만들어진 요소를 실제 화면에 배치
|
||||
document.querySelector("#short-list").append(new Element("tr").append(newRootElement).get());
|
||||
}
|
||||
|
||||
// 단축 버튼을 클릭했을 때 동작되는 이벤트 함수
|
||||
function clickBtnGenShort(){
|
||||
// 이벤트(단축 버튼을 클릭)가 발생했을 당시 입력한 원본 URL 값을 가져옴.
|
||||
var inputUrl=document.body.querySelector("input[type='text'][name='input_url']").value;
|
||||
|
||||
// 입력한 원본 URL이 올바른 형태의 URL인지 검증
|
||||
if(!inputUrl.match(VALIDATE_URL)){
|
||||
alert("잘못된 URL 값 입니다. 올바른 URL 값을 입력해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 단축 URL 생성 요청 및 처리
|
||||
var queryUrl="/short?url="+inputUrl;
|
||||
fetch(queryUrl,{
|
||||
method: "POST"
|
||||
})
|
||||
.then(response => {
|
||||
if(!response.ok){
|
||||
alert("통신 중에 오류가 발생했습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log(data);
|
||||
|
||||
// 응답된 데이터의 상태 코드가 success가 아니라면 알림창 출력
|
||||
if(!data.status=="success"){
|
||||
alert("URL 단축에 실패하였습니다. 다시 시도해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 단축 URL 생성 성공
|
||||
console.log("단축 성공 : "+data.shortUrl);
|
||||
|
||||
// 결과를 표시할 새 요소 생성
|
||||
createShortResultElement(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("에러 발생 : ",error);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<head>
|
||||
<style>
|
||||
#short-list{
|
||||
width:100%;
|
||||
margin:10px 0px;
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.short-item td{
|
||||
padding: 7px;
|
||||
}
|
||||
.short-item td ul{
|
||||
margin:3px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<h3>HanGyub의 URL Shortener(단축기)</h3>
|
||||
<table>
|
||||
<tr>
|
||||
정보 입력<br>
|
||||
<input type="text" name="input_url" placeholder="단축할 원본 URL" size="50">
|
||||
<button id="btn-gen-short">단축!</button>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="1" id="short-list">
|
||||
</table>
|
||||
|
||||
<script>
|
||||
document.querySelector("#btn-gen-short").addEventListener("click",function() { clickBtnGenShort(); });
|
||||
</script>
|
||||
Reference in New Issue
Block a user