ajax + froalaeditor 진행상황 90%

ajax + froalaeditor 진행상황 90%

QA

ajax + froalaeditor 진행상황 90%

본문

<code>

<?php
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
$comment_editor = true;
$is_dhtml_editor = true;
include_once(G5_EDITOR_LIB);
?>

<?php if ($is_member && !isset($GLOBALS['froala_editor_loaded'])): ?>
    <script>
        // CSS 파일을 로드하는 함수
        function loadCss(href) {
            if (!Array.from(document.styleSheets).some(sheet => sheet.href && sheet.href.includes(href))) {
                var link = document.createElement('link');
                link.href = href;
                link.rel = 'stylesheet';
                document.head.appendChild(link);
            }
        }

        // JS 파일을 로드하는 함수
        function loadJs(src, callback) {
            if (!Array.from(document.scripts).some(script => script.src && script.src.includes(src))) {
                var script = document.createElement('script');
                script.src = src;
                script.onload = callback;
                script.onerror = function() {
                    console.error(`Failed to load script: ${src}`);
                };
                document.body.appendChild(script);
            } else if (callback) {
                callback(); // 이미 로드된 경우, 콜백을 호출
            }
        }

        // CSS 파일들 로드
        loadCss("<?php echo G5_EDITOR_URL ?>/froala_editor_4.2.0/css/froala_editor.pkgd.css");
        loadCss("/plugin/editor/froala_editor_4.2.0/css/sir_custom.css");
        loadCss("https://cdn.jsdelivr.net/npm/tui-image-editor@3.2.2/dist/tui-image-editor.css");
        loadCss("https://uicdn.toast.com/tui-color-picker/latest/tui-color-picker.css");

        // JS 파일들 로드
        loadJs("<?php echo G5_EDITOR_URL ?>/froala_editor_4.2.0/js/froala_editor.pkgd.min.js", function() {
            loadJs("<?php echo G5_EDITOR_URL ?>/froala_editor_4.2.0/Froala_c_1.js?<?php echo time(); ?>");
        });
    </script>
    <?php $GLOBALS['froala_editor_loaded'] = true; ?>
<?php endif; ?>

<script>
    var char_min = parseInt(<?php echo $comment_min ?>); // 최소
    var char_max = parseInt(<?php echo $comment_max ?>); // 최대
</script>

<button type="button" class="cm_btn"><span class="total">댓글 <strong><?php echo $view['wr_comment']; ?></strong></span><i class="fa-kit fa-icon-arrow-down fa-sm fa-rotate-180"></i></button>

<!-- 댓글 시작 { -->
<section id="bo_vc">
    <h2 class="sound_only">댓글목록</h2>
    <?php
    $cmt_amt = count($list);
    for ($i = 0; $i < $cmt_amt; $i++) {
        $comment_id = $list[$i]['wr_id'];
        $cmt_depth = strlen($list[$i]['wr_comment_reply']) * 54;
        $comment = $list[$i]['content'];

        $comment = preg_replace("/\[\<a\s.*href\=\"(http|https|ftp|mms)\:\/\/([^[:space:]]+)\.(mp3|wma|wmv|asf|asx|mpg|mpeg)\".*\<\/a\>\]/i", "<script>doc_write(obj_movie('$1://$2.$3'));</script>", $comment);
        $cmt_sv = $cmt_amt - $i + 1; // 댓글 헤더 z-index 재설정 ie8 이하 사이드뷰 겹침 문제 해결
        $c_reply_href = $comment_common_url . '&c_id=' . $comment_id . '&w=c#bo_vc_w';
        $c_edit_href = $comment_common_url . '&c_id=' . $comment_id . '&w=cu#bo_vc_w';
        $is_comment_reply_edit = ($list[$i]['is_reply'] || $list[$i]['is_edit'] || $list[$i]['is_del']) ? 1 : 0;
        ?>

        <article id="c_<?php echo $comment_id ?>"
                 <?php if ($cmt_depth) { ?>style="margin-left:<?php echo $cmt_depth ?>px;0"<?php } ?>>
            <div class="cm_wrap">
                <header style="z-index:<?php echo $cmt_sv; ?>" class="cm_header">
                    <div class="cm_profile"><?php echo get_member_profile_img($list[$i]['mb_id']) ?></div>
                    <div class="cm_w_wrap">
                        <div class="cm_user">
                            <h2 class="sound_only"><?php echo get_text($list[$i]['wr_name']); ?> <?php if ($cmt_depth) { ?>
                                    <span>댓글의</span><?php } ?> 댓글</h2>
                            <span class="only_name"><?php echo $list[$i]['name'] ?></span>
                            <?php if ($write['mb_id'] === $list[$i]['mb_id']) { ?><span class="writer">작성자</span><?php } ?>
                            <?php if ($is_ip_view) { ?>
                                <span class="sound_only">아이피</span>
                                <span class="cm_ip">(<?php echo $list[$i]['ip']; ?>)</span>
                            <?php } ?>
                            <span class="sound_only">작성일</span>
                            <span class="cm_time"> <time datetime="<?php echo date('Y-m-d\TH:i:s+09:00', strtotime($list[$i]['datetime'])) ?>"><?php echo $list[$i]['datetime'] ?></time></span>
                            <?php
                            include(G5_SNS_PATH . '/view_comment_list.sns.skin.php');
                            ?>
                            <?php if ($is_comment_reply_edit) { ?>
                                <div class="bo_vl_opt">
                                    <button type="button" class="btn_cm_opt btn_b01 btn"><i class="fa-light fa-ellipsis-vertical"></i><span class="sound_only">댓글 옵션</span></button>
                                    <ul class="more_opt">
                                        <?php if ($list[$i]['is_reply']) { ?>
                                            <li><a href="<?php echo $c_reply_href; ?>"
                                                   onclick="comment_box('<?php echo $comment_id ?>', 'c'); return false;"><i class="fa-kit fa-icon-regular-reply"></i>답변</a></li>
                                        <?php } ?>
                                        <?php if ($list[$i]['is_edit']) { ?>
                                            <li><a href="<?php echo $c_edit_href; ?>"
                                                   onclick="comment_box('<?php echo $comment_id ?>', 'cu'); return false;"><i class="fa-regular fa-pen-to-square"></i>수정</a></li>
                                        <?php } ?>
                                        <?php if ($list[$i]['is_del']) { ?>
                                            <li><a href="<?php echo $list[$i]['del_link']; ?>"
                                                   onclick="return comment_delete();"><i class="fa-kit fa-icon-light-trash"></i>삭제</a></li>
                                        <?php } ?>
                                    </ul>
                                </div>
                            <?php } ?>
                            <script>
                                $(function () {
                                    $(".btn_cm_opt").on("click", function () {
                                        $(this).parent("div").children(".more_opt").show();
                                    });

                                    $(document).mouseup(function (e) {
                                        var container = $(".more_opt");
                                        if (container.has(e.target).length === 0)
                                            container.hide();
                                    });
                                });

                            </script>
                        </div>
                        <input type="hidden" value="<?php echo strstr($list[$i]['wr_option'], "secret") ?>" id="secret_comment_<?php echo $comment_id ?>">
                        <textarea class="sound_only" id="save_comment_<?php echo $comment_id ?>"><?php echo get_text($list[$i]['content1'], 0) ?></textarea>
                        <div class="cmt_contents fr-view">
                            <p>
                                <?php if (strstr($list[$i]['wr_option'], "secret")) { ?><span class="cm_secret_info"><i class="fa-sharp fa-solid fa-lock" alt="비밀댓글"></i> <span>댓글의 상대자와 작성자에게만 노출됩니다.</span><?php } ?>
                                    <?php echo html_entity_decode($comment, ENT_QUOTES, 'UTF-8'); ?>
                            </p>
                        </div>
                        <div>
                            <span id="edit_<?php echo $comment_id ?>" class="bo_vc_w"></span><!-- 수정 -->
                            <span id="reply_<?php echo $comment_id ?>" class="bo_vc_w"></span><!-- 답변 -->
                        </div>
                    </div>
                </header>
            </div>
        </article>
    <?php } ?>
    <?php if ($i == 0) { ?><p id="bo_vc_empty">등록된 댓글이 없습니다.</p><?php } ?>

</section>
<!-- } 댓글 끝 -->

<?php if ($is_comment_write) {
    if ($w == '')
        $w = 'c';
    ?>
    <!-- 댓글 쓰기 시작 { -->
    <aside id="bo_vc_w" class="bo_vc_w">
        <h2 class="sound_only">댓글쓰기</h2>
        <form name="fviewcomment" id="fviewcomment" action="<?php echo $comment_action_url; ?>"
              onsubmit="return fviewcomment_submit(this);" method="post" autocomplete="off">
            <input type="hidden" name="w" value="<?php echo $w ?>" id="w">
            <input type="hidden" name="bo_table" value="<?php echo $bo_table ?>">
            <input type="hidden" name="wr_id" value="<?php echo $wr_id ?>">
            <input type="hidden" name="comment_id" value="<?php echo $c_id ?>" id="comment_id">
            <input type="hidden" name="sca" value="<?php echo $sca ?>">
            <input type="hidden" name="sfl" value="<?php echo $sfl ?>">
            <input type="hidden" name="stx" value="<?php echo $stx ?>">
            <input type="hidden" name="spt" value="<?php echo $spt ?>">
            <input type="hidden" name="page" value="<?php echo $page ?>">
            <input type="hidden" name="is_good" value="">

            <span class="sound_only">내용</span>
            <?php if ($comment_min || $comment_max) { ?><strong id="char_cnt"><span id="char_count"></span>글자</strong><?php } ?>
            <textarea id="wr_content" name="wr_content" maxlength="10000" required class="required" title="내용" placeholder="댓글내용을 입력해주세요"
                      <?php if ($comment_min || $comment_max) { ?>onkeyup="check_byte('wr_content', 'char_count');"<?php } ?>><?php echo $c_wr_content; ?></textarea>
            <script type="module" src="<?php echo G5_EDITOR_URL ?>/froala_editor_4.2.0/Froala_c_1.js?<?php echo time(); ?>"></script>
            <?php if ($comment_min || $comment_max) { ?>
                <script> check_byte('wr_content', 'char_count'); </script><?php } ?>
            <script>
                $(document).on("keyup change", "textarea#wr_content[maxlength]", function () {
                    var str = $(this).val()
                    var mx = parseInt($(this).attr("maxlength"))
                    if (str.length > mx) {
                        $(this).val(str.substr(0, mx));
                        return false;
                    }
                });
            </script>

            <div class="cm_btn_confirm parents">
                <div class="cm_btn_confirm child">
                    <span class="secret_cm chk_box">
                        <input type="checkbox" name="wr_secret" value="secret" id="wr_secret" class="secret_reply">
                        <label for="wr_secret" class="secret_reply">
                            <i class="fa-sharp fa-light fa-unlock unchecked"></i>
                            <i class="fa-sharp fa-solid fa-lock checked"></i>
                            <span class="text-public">공개댓글</span>
                            <span class="text-secret">비밀댓글</span>
                        </label>
                    </span>
                    <button type="submit" id="btn_submit" class="btn_submit">댓글등록</button>
                </div>

            </div>
            <div class="bo_vc_w_wr">
                <div class="bo_vc_w_info">
                    <?php if ($is_guest) { ?>
                        <label for="wr_name" class="sound_only">이름<strong> 필수</strong></label>
                        <input type="text" name="wr_name" value="<?php echo get_cookie("ck_sns_name"); ?>" id="wr_name"
                               required class="frm_input required" size="25" placeholder="이름">
                        <label for="wr_password" class="sound_only">비밀번호<strong> 필수</strong></label>
                        <input type="password" name="wr_password" id="wr_password" required class="frm_input required"
                               size="25" placeholder="비밀번호">
                        <?php
                    }
                    ?>
                    <?php
                    if ($board['bo_use_sns'] && ($config['cf_facebook_appid'] || $config['cf_twitter_key'])) {
                        ?>
                        <span class="sound_only">SNS 동시등록</span>
                        <span id="bo_vc_send_sns"></span>
                    <?php } ?>
                    <?php if ($is_guest) { ?>
                        <?php echo $captcha_html; ?>
                    <?php } ?>
                </div>
            </div>
        </form>
    </aside>

    <script>
        var save_before = '';
        var save_html = document.getElementById('bo_vc_w').innerHTML;

        function good_and_write() {
            var f = document.fviewcomment;
            if (fviewcomment_submit(f)) {
                f.is_good.value = 1;
                f.submit();
            } else {
                f.is_good.value = 0;
            }
        }

        function fviewcomment_submit(f) {
            var pattern = /(^\s*)|(\s*$)/g;

            f.is_good.value = 0;

            var subject = "";
            var content = "";
            $.ajax({
                url: g5_bbs_url + "/ajax.filter.php",
                type: "POST",
                data: {
                    "subject": "",
                    "content": f.wr_content.value
                },
                dataType: "json",
                async: false,
                cache: false,
                success: function (data, textStatus) {
                    subject = data.subject;
                    content = data.content;
                }
            });

            if (content) {
                alert("내용에 금지단어('" + content + "')가 포함되어있습니다");
                f.wr_content.focus();
                return false;
            }

            var pattern = /(^\s*)|(\s*$)/g;
            document.getElementById('wr_content').value = document.getElementById('wr_content').value.replace(pattern, "");
            if (char_min > 0 || char_max > 0) {
                check_byte('wr_content', 'char_count');
                var cnt = parseInt(document.getElementById('char_count').innerHTML);
                if (char_min > 0 && char_min > cnt) {
                    alert("댓글은 " + char_min + "글자 이상 쓰셔야 합니다.");
                    return false;
                } else if (char_max > 0 && char_max < cnt) {
                    alert("댓글은 " + char_max + "글자 이하로 쓰셔야 합니다.");
                    return false;
                }
            } else if (!document.getElementById('wr_content').value) {
                alert("댓글을 입력하여 주십시오.");
                return false;
            }

            if (typeof (f.wr_name) != 'undefined') {
                f.wr_name.value = f.wr_name.value.replace(pattern, "");
                if (f.wr_name.value == '') {
                    alert('이름이 입력되지 않았습니다.');
                    f.wr_name.focus();
                    return false;
                }
            }

            if (typeof (f.wr_password) != 'undefined') {
                f.wr_password.value = f.wr_password.value.replace(pattern, "");
                if (f.wr_password.value == '') {
                    alert('비밀번호가 입력되지 않았습니다.');
                    f.wr_password.focus();
                    return false;
                }
            }

            <?php if ($is_guest) echo chk_captcha_js();  ?>

            set_comment_token(f);

            document.getElementById("btn_submit").disabled = "disabled";

            return true;
        }

        $(document).ready(function() {
            new FroalaEditor('#wr_content', {
                language: 'ko',
                heightMin: 300,
                key: 'OXC1lD3E3A14C10D8A6kOPVi1b1b2Le2e1G1AWMSGSAFDTGHWsE7D7D6E5A1H4D3C3B6D5=='
            });
        });

        function comment_box(comment_id, work) {
            var el_id,
                form_el = 'fviewcomment',
                respond = document.getElementById(form_el);

            if (comment_id) {
                if (work == 'c')
                    el_id = 'reply_' + comment_id;
                else
                    el_id = 'edit_' + comment_id;
            } else
                el_id = 'bo_vc_w';

            if (save_before != el_id) {
                if (save_before) {
                    document.getElementById(save_before).style.display = 'none';
                }

                document.getElementById(el_id).style.display = '';
                document.getElementById(el_id).appendChild(respond);
                document.getElementById('wr_content').value = '';

                if (work == 'cu') {
                    var commentContent = document.getElementById('save_comment_' + comment_id).value;
                    $('#wr_content').val(commentContent);

                    if (FroalaEditor('#wr_content')) {
                        FroalaEditor('#wr_content').html.set(commentContent);
                    } else {
                        new FroalaEditor('#wr_content', {
                            language: 'ko',
                            heightMin: 300,
                            key: 'OXC1lD3E3A14C10D8A6kOPVi1b1b2Le2e1G1AWMSGSAFDTGHWsE7D7D6E5A1H4D3C3B6D5=='
                        });
                    }

                    if (typeof char_count != 'undefined')
                        check_byte('wr_content', 'char_count');
                    if (document.getElementById('secret_comment_' + comment_id).value)
                        document.getElementById('wr_secret').checked = true;
                    else
                        document.getElementById('wr_secret').checked = false;
                }

                document.getElementById('comment_id').value = comment_id;
                document.getElementById('w').value = work;

                if (save_before)
                    $("#captcha_reload").trigger("click");

                save_before = el_id;
            }
        }

        function comment_delete() {
            return confirm("이 댓글을 삭제하시겠습니까?");
        }

        comment_box('', 'c');
    </script>
<?php } ?>
<!-- } 댓글 쓰기 끝 -->
<script>
    jQuery(function ($) {
        $(".cm_btn").click(function (e) {
            e.preventDefault();
            $(this).toggleClass("cmt_btn_op");
            $("#bo_vc").toggle();

            var icon = $(this).find("i");
            icon.toggleClass("fa-rotate-180");
            icon.toggleClass("font-black");
        });
    });
</script>
<script>
    if (!$('script[src="https://cdn.embedly.com/widgets/platform.js"]').length) {
        $('<script>')
            .attr('src', 'https://cdn.embedly.com/widgets/platform.js')
            .attr('charset', 'UTF-8')
            .appendTo('head');
    }
</script>

</code>

 

이런 식으로 처리해서 처음 에디터를 만난 상황에서는 정상적으로 나오는데 까지는 성공했는데

두번째로 에디터를 만나면 비정상이 되어버리는 마법이 일어나네요 ㅜㅜ

 

이런 콘솔 오류도 나고 ㅜㅜ

 

jquery-3.6.0.min.js?_=1724156831292:2jQuery.Deferred exception: FroalaEditor is not defined ReferenceError: FroalaEditor is not defined at HTMLDocument.<anonymous> (<anonymous>:88:13) at e (https://code.jquery.com/jquery-3.6.0.min.js?_=1724156831292:2:30038) at t (https://code.jquery.com/jquery-3.6.0.min.js?_=1724156831292:2:30340) undefined

jquery-3.6.0.min.js?_=1724156831292:2jQuery.Deferred exception: FroalaEditor is not defined ReferenceError: FroalaEditor is not defined at HTMLDocument.<anonymous> (<anonymous>:88:13) at e (https://code.jquery.com/jquery-3.6.0.min.js?_=1724156831292:2:30038) at t (https://code.jquery.com/jquery-3.6.0.min.js?_=1724156831292:2:30340) undefined

jquery-3.6.0.min.js?_=1724156831292:2Uncaught

ReferenceError: FroalaEditor is not defined at HTMLDocument.<anonymous> (<anonymous>:88:13) at e (jquery-3.6.0.min.js?…24156831292:2:30038) at t (jquery-3.6.0.min.js?…24156831292:2:30340)

jquery-3.6.0.min.js?_=1724156831292:2Uncaught

ReferenceError: FroalaEditor is not defined at HTMLDocument.<anonymous> (<anonymous>:88:13) at e (jquery-3.6.0.min.js?…24156831292:2:30038) at t (jquery-3.6.0.min.js?…24156831292:2:30340)

jquery-migrate-3.3.2…s?_=1724156832568:2JQMIGRATE: Migrate is installed, version 3.3.2

5

Third-party cookie will be blocked in future Chrome versions as part of Privacy Sandbox.

 

현재의 오류 메시지를 보면 FroalaEditor가 정의되어 있지 않다는 에러와 jQuery의 froalaEditor 함수가 정의되지 않았다는 에러가 나타나고 있습니다. 이는 FroalaEditor의 JavaScript 파일이 제대로 로드되지 않았거나, jQuery 플러그인으로서의 froalaEditor 함수가 정의되지 않았음을 나타냅니다.

 

이런 문제라고 하는데 해답으로 제시하는 모든 방법이 잘 먹히질 않네요 ㅜㅜ

 

<참고사항>

ajax는 전체 페이지를 단순히 영역에 뿌리는 역할로만 사용하고 있습니다.

혹시나 해답을 알고 계신 귀인을 기다려 봅니다 ㅜㅜ

 

 

테스트 아이디

test / 1234

이 질문에 댓글 쓰기 :

답변 1

확인해 보니 글쓰기에서는 에디터 관련 js 파일이 로딩이 되어 있는데요, 수정할 때 에디터 관련 js 파일들이 로딩이 되어있지 않더라구요. write 페이지에서 파라미터 w 가 u 일 때 js 관련 파일 구성이 제외된 상태로 추정이 됩니다. 잘 해결하시길 바랍니다. 오늘도 좋은 하루 되세요~~^^

답변을 작성하시기 전에 로그인 해주세요.
전체 2,661
QA 내용 검색

회원로그인

(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1404호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT