PHP강좌/[라라벨]게시판만들기강좌

[라라벨+mysql]게시판 만들기 강좌 #21. 웹에디터(섬머노트) 적용 - 글등록 2/3

에스크리토 2024. 8. 1. 15:26
반응형

이제 에디터에 글을 써서 등록을 해보자. 에디터 부분을 수정해서 본문에 이미지를 첨부할 수 있도록 수정한다.

 

/resources/views/boards/summernote.blade.php

<meta name="csrf-token" content="{{ csrf_token() }}">
<div id="summernote"></div>

<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>

 

이미지 첨부 버튼을 클릭해서 이미지를 선택하면 이미지를 등록하고 본문에 첨부 하도록 수정했다.

 

saveimage는 이미 만들어져 있으므로 이렇게만 수정하면 이미지를 첨부할 수 있다. 이제 작성한 글을 디비에 저장할 수 있도록 write 부분을 수정한다.

 

중요한 점은 다른 부분은 바뀐것이 없고 content부분만 웹에디터에서 작성한 글 내용을 가져 오면 된다는 것이다.

 

/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) }}" 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 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

 

기존에 content는 textarea에서 가져왔지만 지금은 iframe에 있는 웹에디터에서 가져온다는 것이 바뀌었다.

 

/app/Http/Controllers/BoardController.php


    public function create(Request $request)
    {
        $form_data = array(
            'subject' => $request->subject,
            'content' => $request->content,
            'userid' => Auth::user()->userid,
            'email' => Auth::user()->email,
            'multi' => $request->multi??'free',
            'status' => 1
        );

        if(auth()->check()){
            $rs=Board::create($form_data);
            FileTables::where('pid', $request->pid)->where('userid', Auth::user()->userid)->wherein('code',['boardattach','editorattach'])->update(array('pid' => $rs->bid));
            return response()->json(array('msg'=> "succ", 'bid'=>$rs->bid), 200);
        }
    }

 

 FileTables::where('pid', $request->pid)->where('userid', Auth::user()->userid)->wherein('code',['boardattach','editorattach'])->update(array('pid' => $rs->bid));

 

이 부분이 조금 바뀌었다. 웹에디터에서 첨부한 파일과 wrte 부분에서 첨부한 이미지의 pid값을 모두 바꿔주기 위헤 wherein을 사용하는걸로 바뀌었다.

 

글을 써보자.

이런식으로 등록을 하면

 

이렇게 등록된다.

 

다음시간엔 웹에디터에서 수정하는 걸해보자

반응형