기존 방식처럼 write 파일을 그대로 사용해서 수정을 해 볼 것이다. 여기서 가장 중요한 것은 수정할 내용을 summernote에 뿌리는 것이다.
write의 iframe 부분에 bid를 전달해줘서 summernote에 수정할 내용이 표시되도록 해보자.
/resources/views/boards/write.blade.php
@extends('boards.layout')
@section('header')
<?php
if($bid){
$pid=$bid;
$btitle = "수정";
}else{
$pid=time();
$btitle = "쓰기";
}
?>
@include('boards.toptitle', ['toptitle'=>'게시판 '.$btitle, 'multi'=>$multi])
@endsection
@section('content')
<br />
<form method="post" action="/boards/create" enctype="multipart/form-data">
@csrf
@method('post')
<input type="hidden" name="pid" id="pid" value="{{ $pid }}">
<input type="hidden" name="bid" id="bid" value="{{ $bid??0 }}">
<input type="hidden" name="code" id="code" value="boardattach">
<input type="hidden" name="attcnt" id="attcnt" value="0">
<input type="hidden" name="imgUrl" id="imgUrl" value="">
<div class="form-group">
<div class="col-md-12">
<input type="text" name="subject" id="subject" class="form-control input-lg" placeholder="제목을 입력하세요." value="{{ $boards->subject??'' }}" />
</div>
<br />
</div>
<div class="form-group">
<div class="col-md-12">
<iframe id="summerframe" src="{{ route('boards.summernote',['multi' => $multi, 'bid' => $bid]) }}" style="width:100%; height:450px; border:none" scrolling = "no"></iframe>
</div>
</div>
<br />
<div class="form-group">
@if($attaches)
<div id="attach_site" class="col-md-12">
<div class="row row-cols-1 row-cols-md-6 g-4" id="attachFiles" style="margin-left:0px;">
@foreach ($attaches as $att)
@if($att)
<div id="af_{{ $att->id }}" class='card h-100' style='width:120px;margin-right: 10px;margin-bottom: 10px;'><img src="/images/{{ $att->filename }}" width='100' /><div class='card-body'><button type='button' class='btn btn-warning' onclick="deletefile('{{ $att->filename }}','{{ $att->id }}')">삭제</button></div></div>
@endif
@endforeach
</div>
</div>
@else
<div id="attach_site" class="col-md-12">
<div class="row row-cols-1 row-cols-md-6 g-4" id="attachFiles" style="margin-left:0px;">
</div>
</div>
@endif
<div class="col-md-12">
<input type="file" name="afile" id="afile" multiple accept="image/*" multiple class="form-control" aria-label="Large file input example">
</div>
</div>
<br />
<br />
<div class="form-group">
@if($bid)
<div class="col-md-12 text-center">
<button type="button" name="edit" class="btn btn-primary input-lg" onclick="updatesubmit()">수정</button>
</div>
@else
<div class="col-md-12 text-center">
<button type="button" name="edit" class="btn btn-primary input-lg" onclick="sendsubmit()">등록</button>
</div>
@endif
</div>
</form>
<script>
$("#afile").change(function(){
var formData = new FormData();
var attcnt=$("#attcnt").val();
var files = $('#afile').prop('files');
var totcnt=parseInt(attcnt)+parseInt(files.length)
if(totcnt>5){
alert('5개까지만 등록할 수 있습니다.');
return false;
}
for(var i=0; i < files.length; i++) {
attachFile(files[i]);
}
});
function attachFile(file) {
var formData = new FormData();
var pid = $("#pid").val();
var code = $("#code").val();
formData.append("file", file);
formData.append("uptype", "attach");
formData.append("pid", pid);
formData.append("code", code);
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
url: '{{ route('boards.saveimage') }}',
data: formData,
cache: false,
contentType: false,
processData: false,
dataType : 'json' ,
type: 'POST',
success: function (return_data) {
// console.log(JSON.stringify(return_data));
if(return_data.result=='fail'){
alert(return_data.msg);
return false;
}else{
//var img="<img src='"+data+"' width='50'><br>";
var html = "<div id='af_"+return_data.fid+"' class='card h-100' style='width:120px;margin-right: 10px;margin-bottom: 10px;'><img src='/images/"+return_data.fn+"' width='100' /><div class='card-body'><button type='button' class='btn btn-warning' onclick=\"deletefile('"+return_data.fn+"', '"+return_data.fid+"')\">삭제</button></div></div>";
$("#attachFiles").append(html);
var rcnt=parseInt(attcnt)+1;
$("#attcnt").val(rcnt);
var attachFile=$("#attachFile").val();
if(attachFile){
attachFile=attachFile+",";
}
$("#attachFile").val(attachFile+return_data.fn);
}
}
, beforeSend: function () {
var width = 0;
var height = 0;
var left = 0;
var top = 0;
width = 50;
height = 50;
top = ( $(window).height() - height ) / 2 + $(window).scrollTop();
left = ( $(window).width() - width ) / 2 + $(window).scrollLeft();
if($("#div_ajax_load_image").length != 0) {
$("#div_ajax_load_image").css({
"top": top+"px",
"left": left+"px"
});
$("#div_ajax_load_image").show();
}
else {
$('body').append('<div id="div_ajax_load_image" style="position:absolute; top:' + top + 'px; left:' + left + 'px; width:' + width + 'px; height:' + height + 'px; z-index:9999;" class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div>');
}
}
, complete: function () {
$("#div_ajax_load_image").hide();
}
});
}
function deletefile(fn,fid){
var pid = $("#pid").val();
var code = $("#code").val();
var data = {
fn : fn,
pid : pid,
code : code
};
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
type: 'post',
url: '{{ route('boards.deletefile') }}',
dataType: 'json',
data: data,
success: function(data) {
alert("삭제했습니다.");
$("#af_"+fid).hide();
},
error: function(data) {
console.log("error" +JSON.stringify(data));
}
});
}
function sendsubmit(){
var subject=$("#subject").val();
//var content=$("#content").val();
var content=$('#summerframe').get(0).contentWindow.$('#summernote').summernote('code');//iframe에 있는 값을 가져온다
var pid = $("#pid").val();
var code = $("#code").val();
var data = {
multi : '{{ $multi }}',
subject : subject,
content : content,
pid : pid,
code : code
};
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
type: 'post',
url: '{{ route('boards.create') }}',
dataType: 'json',
enctype: 'multipart/form-data',
data: data,
success: function(data) {
location.href='/boards/show/'+data.bid+'/1';
},
error: function(data) {
console.log("error" +data);
}
});
}
function updatesubmit(){
var subject=$("#subject").val();
//var content=$("#content").val();
var content=$('#summerframe').get(0).contentWindow.$('#summernote').summernote('code');//iframe에 있는 값을 가져온다
var bid='{{ $bid }}';
var data = {
subject : subject,
content : content,
bid : bid
};
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
type: 'post',
url: '{{ route('boards.update') }}',
dataType: 'json',
enctype: 'multipart/form-data',
data: data,
success: function(data) {
location.href='/boards/show/'+data.bid+'/1';
},
error: function(data) {
console.log("error" +data);
}
});
}
</script>
@endsection
iframe 부분을 살펴보자.
<iframe id="summerframe" src="{{ route('boards.summernote',['multi' => $multi, 'bid' => $bid]) }}" style="width:100%; height:450px; border:none" scrolling = "no"></iframe>
summernote에 multi값과 bid값을 전달해 주었다. 두개의 변수를 전달해 줄때는 배열 형식으로 보내주어야 한다.
updatesubmit 함수에도 content값을 웹에디터에서 받도록 수정했다.
이제 라우터를 수정해 준다.
/routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\BoardController;
use App\Http\Controllers\MemberController;
Route::get('/', function () {
return view('welcome');
});
//게시판
Route::get('/boards/{multi?}', [BoardController::class, 'index'])->name('boards.index');
Route::get('/boards/show/{id}/{page}', [BoardController::class, 'show'])->name('boards.show');
Route::middleware('auth') -> group(function (){
Route::get('/boards/write/{multi}/{bid?}', [BoardController::class, 'write'])->name('boards.write');
Route::post('/boards/create', [BoardController::class, 'create'])->name('boards.create');
Route::post('/boards/saveimage', [BoardController::class, 'saveimage'])->name('boards.saveimage');
Route::post('/boards/deletefile', [BoardController::class, 'deletefile'])->name('boards.deletefile');
Route::get('/boards/imgpop/{imgfile}', [BoardController::class, 'imgpop'])->name('boards.imgpop');
Route::post('/boards/update', [BoardController::class, 'update'])->name('boards.update');
Route::get('/boards/delete/{bid}/{page}', [BoardController::class, 'delete'])->name('boards.delete');
Route::get('/boards/summernote/{multi}/{bid?}', [BoardController::class, 'summernote'])->name('boards.summernote');
});
//회원
Route::get('/login', [MemberController::class, 'login'])->name('auth.login');
Route::get('/signup', [MemberController::class, 'signup'])->name('auth.signup');
Route::post('/signupok', [MemberController::class, 'signupok'])->name('auth.signupok');
Route::post('/emailcheck', [MemberController::class, 'emailcheck'])->name('auth.emailcheck');
Route::post('/loginok', [MemberController::class, 'loginok']) -> name('auth.loginok');
Route::post('/logout', [MemberController::class, 'logout']) -> name('auth.logout');
bid는 값이 있는 경우도 있고 없는 경우도 있으니 bid? 이렇게 받아 준다. 이제 콘트롤러를 수정한다.
/app/Http/Controllers/BoardController.php
public function summernote($multi, $bid = null)
{
if($bid){
$boards = Board::findOrFail($bid);
}else{
$boards = array();
}
return view('boards.summernote', ['multi' => $multi, 'boards' => $boards]);
}
게시판의 값을 summernote에도 보내준다. 뷰도 수정해 주자.
/resources/views/boards/summernote.blade.php
<meta name="csrf-token" content="{{ csrf_token() }}">
@if($boards)
<div id="summernote">{!! $boards->content !!}</div>
@else
<div id="summernote"></div>
@endif
<script>
$(document).ready(function() {
var $summernote = $('#summernote').summernote({
codeviewFilter: false,
codeviewIframeFilter: true,
lang: 'ko-KR',
height: 400,
callbacks: {
onImageUpload: function (files) {//이미지등록
for(var i=0; i < files.length; i++) {
saveFile($summernote, files[i]);
}
}
}
});
});
function saveFile($summernote, file){
var pid = parent.$("#pid").val();
var formData = new FormData();
formData.append("file", file);
formData.append("code", "editorattach");
formData.append("pid", pid);
$.ajax({
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
url: '/boards/saveimage',
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function (data) {
if(data.result==-1){
alert('용량이 너무크거나 이미지 파일이 아닙니다.');
return;
}else{
$('#summernote').summernote('insertImage', '/images/'+data.fn, function ($image) {
$image.css('max-width', '100%');
$image.css('padding', '10px');
});
}
}
});
}
</script>
수정인 경우에만 값을 뿌리도록 수정해 주었다.
수정할때 본문에는 없지만 file_tables에 값이 있는 경우 file_tables 값과 파일을 삭제하도록 코드를 수정한다.
/app/Http/Controllers/BoardController.php
public function update(Request $request)
{
$form_data = array(
'subject' => $request->subject,
'content' => $request->content
);
if(auth()->check()){
$boards = Board::findOrFail($request->bid);
if(Auth::user()->userid==$boards->userid){
$attaches = FileTables::where('pid',$request->bid)->where('status',1)->where('code','editorattach')->get();
foreach($attaches as $att){//file_tables에 있는 파일명이 본문에 있는지 확인해서 없으면 삭제한다.
if(!strpos($request->content, $att->filename)){
unlink(public_path('images')."/".$att->filename);
FileTables::where('id', $att->id)->update(array('status' => 0));
}
}
Board::where('bid', $request->bid)->update($form_data);
return response()->json(array('msg'=> "succ", 'bid'=>$request->bid), 200);
}else{
return response()->json(array('msg'=> "fail", 200));
}
}
}
웹에디터에 이미지를 첨부했다가 삭제하는 경우도 있을 수 있으므로 본문과 비교해서 file_tables 테이블에 남아있는 값들을 정리해 주었다.
삭제는 웹에디터가 있거나 없거나 그대로 사용하면 된다. 수정할 것이 없다.