This commit is contained in:
lunaticbum 2024-10-23 17:06:27 +09:00
parent 69d2df4ac4
commit 21df7cd3c3
12 changed files with 473 additions and 41 deletions

View File

@ -24,6 +24,8 @@ import org.springframework.web.multipart.MultipartFile
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.servlet.ModelAndView
import java.io.*
import java.net.URLDecoder
import java.text.SimpleDateFormat
import java.util.*
@ -51,6 +53,7 @@ class BlogController() {
vm.modelMap.put(EncTypeKey, EncType11)
vm.modelMap.put(ApiKeyWordKey,"WRITE")
vm.modelMap.put("title","회원이 들어는 구나~!!")
vm.modelMap.put("defaultTitle","무제(無題) (Untitled, ${SimpleDateFormat("yyyy-MM-dd HH:mm").format(Date())})")
} else {
vm.modelMap.put(WRITE_PERMISSION_KEY,"NO")
}
@ -70,7 +73,6 @@ class BlogController() {
logService.log(jsonString)
var lResultCode = 0
var lResultMsg = "Suscces"
var u : UserDetails? = null
val decodedBytes: ByteArray = Base64.getDecoder().decode(jsonString)
String(decodedBytes).let {
Gson().fromJson<RequestModel>(it, RequestModel::class.java)?.let { model ->
@ -87,6 +89,13 @@ class BlogController() {
for (idx in 0..max) { if (idx % 2 == 0) { if (nb.size > 0) { fullData.add(nb.removeLast()) } } else { if (na.size > 0) { fullData.add(na.removeLast()) } } }
logService.log(fullData.joinToString(""))
val target = Gson().fromJson(fullData.joinToString(""), Post::class.java) ?: Post()
if (target.writeTime < 1L) {
target.writeTime = System.currentTimeMillis()
} else {
target.originId = target.id
target.id = null
target.modifyTime = System.currentTimeMillis()
}
var user = postManageg.save(target)
if (user != null) {
lResultMsg = "save post"
@ -124,6 +133,25 @@ class BlogController() {
return vm
}
@GetMapping("modify")
fun modify() : ModelAndView{
logService.log("incoming modify")
val vm = ModelAndView("content/blog/modify")
postManageg.find20()?.apply {
forEach { it.title = URLDecoder.decode(it.title)}
vm.modelMap.put("posts",this)
}
return vm
}
@GetMapping("editor/{postId}")
fun editor(@PathVariable postId : String) : ModelAndView{
val vm = ModelAndView("content/blog/editor")
return vm
}
@GetMapping("recent")
fun recent() : ModelAndView{
val vm = ModelAndView("content/blog/viewer")

View File

@ -29,14 +29,22 @@ class Post {
@BsonRepresentation(BsonType.OBJECT_ID)
var id: String? = null
var originId: String? = null
var title : String? = null
var content : String? = null
var category : String? = null
var tags : String? = null
var writer : String? = null
var writeTime : Long = 0
var modifyTime : Long = 0
var posting : Boolean = false
var firstPostLat : Double = 0.0
var firstPostLon : Double = 0.0
var modifyTime : Long = 0
var modifyLat : Double = 0.0
var modifyLon : Double = 0.0
}

View File

@ -11,13 +11,115 @@
height: var(--ButtonHeight);
}
.layer > * {
/*height: fit-content;*/
}
/*input {*/
/* width: 100%;*/
/*}*/
.write_controllbox {
margin: 0;
padding: 0;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -moz-flex;
display: -webkit-flex;
display: flex;
justify-content: space-between;
list-style: none;
}
.write_option {
display: inline-block;
text-align: center;
line-height: 30px;
width: 100%;
padding: 0;
margin: 2px;
align-content: center;
top: 0;
bottom: 0;
color: white;
background: #40404564;
position: relative;
outline-width: thin;
outline-color: #ec914b8f;
border-color: #ec914b8f;
border-style: groove;
border-width: 1px;
height: var(--ButtonHeight);
}
input {
#title_field {
font-size: 20px;
}
.pop_layer .pop_container {
padding: 20px 25px;
}
.pop_layer p.ctxt {
color: #666;
line-height: 25px;
}
.pop_layer .btn_r {
width: 100%;
margin: 10px 0 20px;
padding-top: 10px;
border-top: 1px solid #DDD;
text-align: right;
}
select , #hashtag{
margin-left: 1%;
width: fit-content;
margin-right: 1%;
.pop_layer {
display: none;
position: absolute;
top: 50%;
left: 50%;
width: 410px;
height: auto;
background-color: #fff;
border: 5px solid #3571B5;
z-index: 10;
}
.dim_layer {
display: none;
position: fixed;
_position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
}
.dim_layer .dimBg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
opacity: .5;
filter: alpha(opacity=50);
}
.dim_layer .pop_layer {
display: block;
}
a.btn_layerClose {
display: inline-block;
height: 25px;
padding: 0 14px 0;
border: 1px solid #304a8a;
background-color: #3f5a9d;
font-size: 13px;
color: #fff;
line-height: 25px;
}
a.btn_layerClose:hover {
border: 1px solid #091940;
background-color: #1f326a;
color: #fff;
}

View File

@ -39,19 +39,6 @@ body > *{
/* border-radius: 10px;*/
/*}*/
input, select ,button {
align-content: center;
top: 0;
bottom: 0;
color: white;
background: #40404564;
position: relative;
outline-width: thin;
outline-color: #ec914b8f;
border-color: #ec914b8f;
border-style: groove;
border-width: 1px;
}
header {
top: 0;

View File

@ -1,18 +1,44 @@
var currentLat = 0.0
var currentLon = 0.0
let baseData = {
'title': "",
'content': "",
'firstPostLat': "",
'firstPostLon': "",
'category' : "none",
'hashTags' : "#none",
}
function onclickWrite(type, keyword, html) {
let title_field = document.getElementById('title_field')
var hasValues = true
if (hasValues) {
let data = {
'title': title_field.value,
'content': encodeURIComponent(html),
}
let uploadUrl = location.protocol + "//" + location.hostname + "/blog/post.ajax";
if(confirm(JSON.stringify(data) + "\n해당 내용으로\n유저 등록 하실??")) {
post(uploadUrl,type,JSON.stringify(data),keyword, function (resultData) {
alert(resultData)
})
} else {
}
baseData.title = encodeURIComponent(title_field.value)
baseData.content = encodeURIComponent(html)
baseData.firstPostLat = encodeURIComponent(currentLat)
baseData.firstPostLon = encodeURIComponent(currentLon)
}
let uploadUrl = getMainPath() + "/blog/post.ajax";
if(confirm(JSON.stringify(baseData) + "\n해당 내용으로\n유저 등록 하실??")) {
post(uploadUrl,type,JSON.stringify(baseData),keyword, function (resultData) {
alert(resultData)
})
} else {
}
}
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
x.innerHTML = "Geolocation is not supported by this browser.";
}
}
function showPosition(position) {
currentLat = position.coords.latitude
currentLon = position.coords.longitude
baseData.firstPostLat = encodeURIComponent(currentLat)
baseData.firstPostLon = encodeURIComponent(currentLon)
document.getElementById('location_field').value = "Lat: " + position.coords.latitude + ", Lon: " + position.coords.longitude;
}

View File

@ -65,3 +65,66 @@ function post(target,type, data, key,callBackResult) {
'type':type,
})));
}
function mainPath() {
console.log(`location.port >> ${location.port}`)
if ('443' === location.port) {
location = location.protocol + "//" + location.hostname + ":" + location.port
} else {
location = location.protocol + "//" + location.hostname
}
}
function getMainPath() {
console.log(`location.port >> ${location.port}`)
if ('443' === location.port) {
return location.protocol + "//" + location.hostname + ":" + location.port
} else {
return location.protocol + "//" + location.hostname
}
}
function openPopup(a) {
var $href = $(a).attr('to');
document.querySelectorAll('[id*=popLayer]').forEach(function (v,k,p) {
$(v).hide();
});
layer_popup($href);
}
function layer_popup(el){
var $el = $(el); //레이어의 id를 $el 변수에 저장
var isDim = true ;//$(document).hasClass('dimBg'); //dimmed 레이어를 감지하기 위한 boolean 변수
isDim ? $('.dim_layer').fadeIn() : $el.fadeIn();
$el.show()
var $elWidth = ~~($el.outerWidth()),
$elHeight = ~~($el.outerHeight()),
docWidth = $(document).width(),
docHeight = $(document).height();
// 화면의 중앙에 레이어를 띄운다.
if ($elHeight < docHeight || $elWidth < docWidth) {
$el.css({
marginTop: -$elHeight /2,
marginLeft: -$elWidth/2
})
} else {
$el.css({top: 0, left: 0});
}
$el.find('a.btn_layerClose').click(function(){
isDim ? $('.dim_layer').fadeOut() : $el.fadeOut(); // 닫기 버튼을 클릭하면 레이어가 닫힌다.
return false;
});
$('.dimBg').click(function(){
$('.dim_layer').fadeOut();
return false;
});
}
function urldecode(t){
return decodeURI(t)
}

View File

@ -0,0 +1,152 @@
<!DOCTYPE html>
<html
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/default_layout}"
>
<th:block layout:fragment="head" id="head">
<script type="text/javascript" th:src="@{/js/toast-ui.js}"></script>
<script type="text/javascript" th:src="@{/js/blog.js}"></script>
<link th:href="@{/css/blog.css}" rel="stylesheet" />
<link th:href="@{/css/toast-ui.css}" rel="stylesheet" />
<link th:href="@{/css/toast-ui-dark.css}" rel="stylesheet" />
<!-- <link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor-dark.css" />-->
<script th:inline="javascript">
var currentTitle = [[${defaultTitle}]]
var editor
let onChange = () => {console.log(editor.getMarkdown())}
document.addEventListener("DOMContentLoaded", onLoaded);
function onLoaded() {
getLocation()
var style = getComputedStyle(document.body)
console.log(style.getPropertyValue('--ContentVerticalMargin'))
console.log(window.c)
console.log(style.getPropertyValue('--FooterHeight'))
console.log(style.getPropertyValue('--TopHeight'))
var editorHeght = (
document.querySelector('#main_layer').getBoundingClientRect().height -
(
Number(style.getPropertyValue('--ButtonHegit').replace("px","") * 3)
+ Number(style.getPropertyValue('--TopHeight').replace("px",""))
)
)
editor = new toastui.Editor({
el: document.querySelector('#editor'),
previewStyle: 'tab',
height: editorHeght + 'px',
width:'95%',
theme:'dark',
usageStatistics : false,
toolbar:null,
initialValue:
"# 제목 " +"\n" +
"평문 사이에 **볼드체** *이탤릭체*"+"\n" +
"~~어디쓰지~~"+"\n" +
"***"+"\n" +
"### 모라모라 " +"\n" +
"> 으흐흠..." +"\n" +
"* 쓸까?" +"\n" +
"1. 첫번째" +"\n" +
"* [x] 체크하자" +"\n" +
"* [ ] 체크하자" +"\n" +
" \|dd\|cc\|ff\|\n" +
" \|\-\-\-\|\-\-\-\|\-\-\-\|\n" +
" \|aa\|s\|s\|" +"\n" +
"[링크다](https://youtube.com)" +"\n" +
"`var test = 'real test'`" +"\n" +
"```\n" +
"let test= = 'real test'\n" +
"```"
,
theme:"dark",
initialEditType:"wysiwyg",
hooks: {
addImageBlobHook: (blob, callback) => {
const formData = new FormData();
formData.append('file', blob);
let uploadUrl = getMainPath() + "/blog/post/imageUpload";
let imageUrl = getMainPath() + '/blog/post/images/';
$.ajax({
type: 'POST',
enctype: 'multipart/form-data',
url: uploadUrl,
data: formData,
dataType: 'json',
processData: false,
contentType: false,
cache: false,
timeout: 600000,
success: function (data) {
imageUrl += data.fileName;
callback(imageUrl, '사진 대체 텍스트 입력');
},
error: function (e) {
callback('image_load_fail', '사진 대체 텍스트 입력');
}
});
}
}
});
}
function save() {
console.log(editor.getHTML())
console.log(editor.getMarkdown())
onclickWrite([[${enc}]],[[${keyword}]],editor.getMarkdown())
}
</script>
</th:block>
<th:block layout:fragment="content" id="content">
<div id="main_layer">
<th:block th:if="${PERMISSION != 'OK'}">
<h1>권한이 없는 뎁쇼?!</h1>
</th:block>
<th:block th:if="${PERMISSION == 'OK'}">
<div class="layer">
<input id="title_field" />
</div>
<div id="editor" ></div>
<div class="write_controllbox">
<div class="write_option btn-example" to="#popLayer1" onclick="openPopup(this)" ></div>
<div class="write_option btn-example" to="#popLayer2" onclick="openPopup(this)" id="hashtag_field"></div>
<label for="location_field"></label><input class="write_option" readonly id="location_field"/>
</div>
<h1><button id="save" class="write_option" style="width: 100%; position: relative" onclick="save()">저장하셈</button></h1>
</th:block>
</div>
</th:block>
<th:block layout:fragment="popup_layer">
<div id="popLayer1" class="pop_layer">
<div class="pop_container">
<div class="pop_conts">
<!--content //-->
<p class="ctxt mb20">Thank you.<br>
Your registration was submitted successfully.<br>
Selected invitees will be notified by e-mail on JANUARY 24th.<br><br>
Hope to see you soon!
</p>
<div class="btn_r">
<a href="#" class="btn_layerClose">Close</a>
</div>
<!--// content-->
</div>
</div>
</div>
<div id="popLayer2" class="pop_layer">
<div class="pop_container">
<div class="pop_conts">
<!--content //-->
<p class="ctxt mb20">
test 002
</p>
<div class="btn_r">
<a href="#" class="btn_layerClose">Close</a>
</div>
<!--// content-->
</div>
</div>
</div>
</th:block>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/default_layout}">
<th:block layout:fragment="head">
</th:block>
<th:block layout:fragment="content" id="content">
<table id="main_layer">
<tr id="where" th:each="location : ${locations}">
<tr id="posts" th:each="post : ${posts}">
<td class="post_item"><span th:text="${#dates.format(post.writeTime, 'dd/MMM/yyyy HH:mm')}"></span></td>
<td class="post_item"><span th:text="${post.title}"></span></td>
<td class="post_item"><span th:text="${post.id}"></span></td>
</tr>
</table>
</th:block>
</html>

View File

@ -5,7 +5,6 @@
layout:decorate="~{layout/default_layout}"
>
<th:block layout:fragment="head" id="head">
<script type="text/javascript" th:src="@{https://code.jquery.com/jquery-3.5.1.min.js}" crossorigin="anonymous"></script>
<script type="text/javascript" th:src="@{/js/toast-ui.js}"></script>
<script type="text/javascript" th:src="@{/js/blog.js}"></script>
<link th:href="@{/css/blog.css}" rel="stylesheet" />
@ -17,6 +16,14 @@
let onChange = () => {console.log(editor.getMarkdown())}
document.addEventListener("DOMContentLoaded", onLoaded);
function onLoaded() {
var currentTitle = [[${defaultTitle}]]
getLocation()
var titleField = document.getElementById('title_field')
titleField.addEventListener("change", (event) => {
baseData.title = titleField.value
console.log(baseData.title)
});
titleField.value = currentTitle
var style = getComputedStyle(document.body)
console.log(style.getPropertyValue('--ContentVerticalMargin'))
console.log(window.c)
@ -64,8 +71,8 @@
addImageBlobHook: (blob, callback) => {
const formData = new FormData();
formData.append('file', blob);
let uploadUrl = location.protocol + "//" + location.hostname + "/blog/post/imageUpload";
let imageUrl = location.protocol + "//" + location.hostname + '/blog/post/images/';
let uploadUrl = getMainPath() + "/blog/post/imageUpload";
let imageUrl = getMainPath() + '/blog/post/images/';
$.ajax({
type: 'POST',
enctype: 'multipart/form-data',
@ -102,15 +109,50 @@
</th:block>
<th:block th:if="${PERMISSION == 'OK'}">
<div class="layer">
<input id="title_field" />
<input id="title_field" class="write_option" />
</div>
<div id="editor" ></div>
<div class="layer">
<select > </select>
<input id="hashtag_field" />
<button id="save" onclick="save()">asdsad</button>
<div class="write_controllbox">
<div class="write_option btn-example" to="#popLayer1" onclick="openPopup(this)" ></div>
<div class="write_option btn-example" to="#popLayer2" onclick="openPopup(this)" id="hashtag_field"></div>
<label for="location_field"></label><input class="write_option" readonly id="location_field"/>
</div>
<h1><button id="save" class="write_option" style="width: 100%; position: relative" onclick="save()">저장하셈</button></h1>
</th:block>
</div>
</th:block>
<th:block layout:fragment="popup_layer">
<div id="popLayer1" class="pop_layer">
<div class="pop_container">
<div class="pop_conts">
<!--content //-->
<p class="ctxt mb20">Thank you.<br>
Your registration was submitted successfully.<br>
Selected invitees will be notified by e-mail on JANUARY 24th.<br><br>
Hope to see you soon!
</p>
<div class="btn_r">
<a href="#" class="btn_layerClose">Close</a>
</div>
<!--// content-->
</div>
</div>
</div>
<div id="popLayer2" class="pop_layer">
<div class="pop_container">
<div class="pop_conts">
<!--content //-->
<p class="ctxt mb20">
test 002
</p>
<div class="btn_r">
<a href="#" class="btn_layerClose">Close</a>
</div>
<!--// content-->
</div>
</div>
</div>
</th:block>
</html>

View File

@ -4,7 +4,7 @@
<header>
<table >
<tr id="top">
<td><h2><a aria-label="licenses" style="color: white" href="../" title="Gmail">HOME</a></h2></td>
<td><h2><a aria-label="licenses" style="color: white" href="javascript:mainPath()" title="Gmail">HOME</a></h2></td>
</tr>
</table>
</header>

View File

@ -6,8 +6,9 @@
<meta name="Referrer" content="origin"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1"/>
<script type="text/javascript" th:src="@{https://code.jquery.com/jquery-3.5.1.min.js}" crossorigin="anonymous"></script>
<link th:href="@{/css/common.css}" rel="stylesheet" />
<script type="text/javascript" th:src="@{/js/common.js}"></script>
<script async th:src="@{https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9504446465764716}" crossorigin="anonymous"></script>
<script type="text/javascript" th:src="@{/js/common.js}"></script>
</th:block>
</html>

View File

@ -18,6 +18,10 @@
<!--<th:block layout:fragment="content"></th:block>-->
<th:block layout:fragment="content"></th:block>
<div class="dim_layer">
<div class="dimBg"></div>
<th:block layout:fragment="popup_layer"></th:block>
</div>
<!--<th:block th:replace="fragments/footer :: footer"></th:block>-->
<th:block th:replace="~{fragments/footer :: footer}"></th:block>
</body>