게시판 대댓글에서 페이지 이동없이 댓글 바로 아래에서 (textarea가 아니라) 위지윅 에디터를 로드하고 대댓글을 쓸 수 있을까 고민 중에 있습니다.

일전에 회원 이용약관을 검토해보라는 조언이 있어서 추적해봤더니 에디터 모듈의 dispEditorFrame() 함수까지 오게 됐습니다.

js에서 url을 파라미터와 함께 넘겨줘서 해당 view의 템플릿 결과를 아이프레임으로 얹어주는 방식입니다.

 

1. 회원 약관 생성 소스 코드 : https://github.com/rhymix/rhymix/blob/aa78a03b99df9c7deabfa4fb2d498eed067f54c8/modules/member/tpl/agreements_config.html#L18-L24

 

2. js에서 클릭 이벤트로 아이프레임 생성 : https://github.com/rhymix/rhymix/blob/aa78a03b99df9c7deabfa4fb2d498eed067f54c8/common/js/common.js#L376-L393

 

3. dispEditorFrame() 함수로 액션 실행 : https://github.com/rhymix/rhymix/blob/aa78a03b99df9c7deabfa4fb2d498eed067f54c8/modules/editor/editor.view.php#L21-L49

 

4. editor_frame.html 템플릿으로 에디터 출력 : https://github.com/rhymix/rhymix/blob/aa78a03b99df9c7deabfa4fb2d498eed067f54c8/modules/editor/tpl/editor_frame.html#L1-L18

 

그런데 이게 뭔가 개발이 되다 만 함수 같더라구요.

에디터 옵션이 모듈이나 mid 별로 적용되는 게 아니라 사실상 고정이 되어 있고,

그렇게 연결을 하면 일단 본문이 content로 이전돼서 저장되기는 하는데 (1) escape이 잘 안되는 것 같고 (2) 파일은 (업로드가 되기는 하지만) 첨부 후에 댓글단에 연결되지 않더라구요. https://dev.aporia.blog/board_zjsF61/44317#comment_44423

또, 개별 모듈의 에디터 옵션을 불러와서 좀 더 역동적으로 꾸며보려고 시험 삼아 dispEditorFrame() 함수를 수정해보기도 했는데, 뭔가 누락되거나 잘못된 게 있는지 (에러메시지도 없이) 내용값 전달조차 되지 않습니다;;;

 

이게 에디터를 동적으로 생성해줄 때 유용한 함수인 것 같은데, 이러다 또 애드온을 만들어야 하는 건 아닌지 고민이 깊어갑니다.

 

 

글쓴이 윤삼

profile
아무래도 중급 초반 수준의 코딩 오타쿠인 것 같습니다.
  • profile

    mid가 없는 관리자 화면에서 쓰려고 만든 거라... mid를 받지 않으니까 각 모듈의 에디터 설정이 적용되지도 않고, 업로드한 파일도 미아가 되는 것 같습니다.

  • profile profile

    그런 것 같더라구요.
    그래서 setQuery로 mid값 넘겨주고, 그걸로 module_srl 가져와서 getEditorConfig($module_srl)로 에디터 생성을 해봤는데, 그래도 연결이 잘 이뤄지지 않습니다;;

     

    가변변수를 써서 가독성이 좀 떨어지는데... 이런 식으로 수정을 해봤었거든요.

    무슨 실수가 있는지 이렇게 하면 내용값 전달조차 안 되더라구요;;;

    function dispEditorFrame()
    {
        $module_srl = Context::get('module_srl');
        if ( !$module_srl && Context::get('mid') )
        {
            $module_srl = ModuleModel::getModuleInfoByMid(Context::get('mid'))->module_srl;
        }
    
        // Check parent input ID
        $parent_input_id = Context::get('parent_input_id');
        Context::set('parent_input_id', preg_replace('/[^a-z0-9_]/i', '', $parent_input_id));
        Context::addBodyClass('disable_debug_panel');
    
        // Load editor
        $oEditorModel = getModel('editor');
        $option = $oEditorModel->getEditorConfig($module_srl);
        $mobile = Mobile::isMobileCheckByAgent() ? 'mobile_' : '';
        $type = Context::get('type') === 'comment' ? 'comment_' : '';
    
        $option->editor_skin = $option->{$mobile.$type.'editor_skin'};
        $option->editor_colorset = $option->{$mobile.$type.'editor_colorset'};
        $option->primary_key_name = 'primary_key';
        $option->content_key_name = 'content';
        $option->enable_autosave = $option->enable_autosave ?? FALSE;
        $option->editor_height = $option->{$mobile.$type.'editor_height'};
    
        // Check a group_list of the currently logged-in user for permission check
        if(Context::get('is_logged'))
        {
            $logged_info = Context::get('logged_info');
            $group_list = $logged_info->group_list;
        }
        else
        {
            $group_list = array();
        }
    
        // Permission check for file upload
        if($module_srl)
        {
            if ($logged_info->is_admin === 'Y' || !count($option->{$type.'upload_file_grant'}))
            {
                $option->allow_fileupload = true;
            }
            else
            {
                $option->allow_fileupload = false;
                foreach($group_list as $group_srl => $group_info)
                {
                    if(in_array($group_srl, $option->{$type.'upload_file_grant'}))
                    {
                        $option->allow_fileupload = true;
                        break;
                    }
                }
            }
        }
    
        // Permission check for using default components
        if ($logged_info->is_admin === 'Y' || !count($option->{'enable_'.$type.'default_component_grant'}))
        {
            $option->enable_default_component = true;
        }
        else
        {
            $option->enable_default_component = false;
            foreach($group_list as $group_srl => $group_info)
            {
                if(in_array($group_srl, $option->{'enable_'.$type.'default_component_grant'}))
                {
                    $option->enable_default_component = true;
                    break;
                }
            }
        }
    
        // Permisshion check for using extended components
        if($logged_info->is_admin === 'Y' || !count($option->{'enable_'.$type.'component_grant'}))
        {
            $option->enable_component = true;
        }
        else
        {
            $option->enable_component = false;
            foreach($group_list as $group_srl => $group_info)
            {
                if(in_array($group_srl, $option->{'enable_'.$type.'component_grant'}))
                {
                    $option->enable_component = true;
                    break;
                }
            }
        }
    
        $option->editor_focus = 'Y';
    
        $editor = $oEditorModel->getEditor(0, $option);
        Context::set('editor', $editor);
    
        // Set template
        $this->setLayoutPath('./common/tpl/');
        $this->setLayoutFile("default_layout");
        $this->setTemplatePath($this->module_path . 'tpl');
        $this->setTemplateFile('editor_frame');
    }

     

  • profile
    항상 가려운 곳을 긁어주시는데 감사합니다. (__)/
    응원합니다.
  • profile profile
    근데 이번 일은 정말 난이도가 높네요ㅡㅜ
  • profile

    추가로 알게 된 사항입니다.

    1. 해당 프로세스에서 위지윅 에디터는 ck에디터만 지원되는가 봅니다. 심플에디터로는 내용 전달이 되지 않았는데, ck에디터로 고정을 하면 내용 전달은 됩니다. (물론 태그들을 잔뜩 붙인 채로요ㅎ)
    이것은 아마도 editor_frame.html 파일에 있는 editor_copy_input 메소드가 ck에디터 전용이기 때문인 것 같습니다.

    1-1. 파일 연결이 안 되는 건 위 댓글에서 언급된 것처럼 에디터 초기화 과정에서 mid나 module_srl을 참조하지 않아서인가 봅니다.

    1-2. 파일 첨부 자체는 돼서 db를 확인해보니 파일의 upload_target_srl이 댓글의 comment_srl과 일치하지 않는 것을 확인할 수 있었습니다. 그에 반해 파일 테이블에 module_srl은 잘 되어 있었구요. (혼란의 연속...)

    2. dispEditorFrame() 함수에 있는 $option->height = 300; 이거는
    $option->editor_height = 300; 같은 식으로 해야 에디터 높이 반영되는 것으로 보입니다.

  • profile
    관리자 단에 있는 에디터를 불러와보라는 힌트를 저도 얻었긴 했었는데요
    실제로 작업해보니깐. 해당 에디터는 그냥 에디터 모양 그게 다였고.
    ckeditor.js 툴바 설정도 안 먹히고, 파일 업로드 영역도 없더군요.
    그래서 그건 패스했고.

    기본 에디터를 그대로 띄우면서 시퀀스 번호를 동적으로 다 매겨줘야하는데
    일단 에디터가 떠야지 그게 다 연동이 되는거 같아서 작업하다가 버렸습니다. -_-;

    그런데 이 부분 일전에 작업해보신 적 있으셨지 않으신가요?;
  • profile profile
    일전에 말씀 드린 것처럼 잘 기억이 안 나요ㅋㅋㅋㅋ 어언 수년 전...
    아마도 $.ajax로 dispBoardReplyComment를 불러오고, 해당 페이지의 html은 form만 남겨둔 채로 편집을 했던 것 같습니다.
    이번에 exec_json이랑 $.get으로도 불러와봤는데 잘 안되더군요.
    ajax 옵션이 뭔가 달랐던 것 같기도 하고, 그때는 별 무리 없이 했었는데 엉겁결에 됐던 건가 봐요.
  • profile
    저도 최근에 삽질해본 바..
    저 같은 경우에 처음에 어떻게 했었냐면은..
    댓글마다 에디터를 다 띄워놨었어요.
    그러다보니 post가 계속 로딩된다고 글보기 페이지당 최대 51번(댓글갯수+기본댓글쓰기) post가 요청된다고, 서버자원을 긁어간다고(?) 이 부분을 다르게 작업해달라는 요청이 있어서.
    해볼려고 했는데 ckeditor로는 어렵더군요..

    페이지 이동 없이 댓글수정이랑 댓글삭제를 해달라는 요청이었던지라,
    처음에는 댓글쓰기랑 댓글수정이랑 각각 다르게 했었는데요. 이러다보니 댓글에디터post요청이 댓글갯수만큼 추가가 되니깐 댓글이 늘어날 수록 페이지 로딩이 느려진다고 해서..
    수정에 수정을 거듭하다가 결국 지지치고 textarea로 처리했었어요 ㅠ
  • profile profile

    여기 https://xetown.com/topics/1710052#comment_1710117 에 언급한 것처럼
    - 첨부 파일까지 연결된다면
    - 그리고 ck에디터 외에 다른 에디터도 연결된다면
    좋지 않을까 싶어요.

    그리고 새로고침 없는 대댓글 수정은 또 고심이 되겠네요;;;

  • profile profile

    제가 작업해본 바(2) ckeditor와 프로알라 에디터 두개를 테스트했었는데요,
    프로알라 에디터의 경우에는 파일첨부와 에디터 모두 잘 되었습니다 (__);; (프로알라 에디터 최고!)
    댓글작성과 마찬가지로 댓글수정도 그냥 에디터를 애초에 띄워버리면 문제가 없는데요, (기존에 댓글수정시 에디터가 뜨듯이)

    에디터를 미리 다 수정모드로 불러왔을 경우에 기존 글 내용도 입력해주고, 파일도 자동으로 가져와지고 해서.
    근데 댓글 등록시에는 댓글 내용 영역도 초기화해야하고, 파일 영역도 초기화해줘야했고,
    이게 또 추가로 코드에 따라서 애플 모바일 사파리에서도 코드 같은게 잘 안되는 케이스가 있더라구요.

    산 너머 산이었습니다. ㅎㅎ....

     

    ps. 에디터 영역은 정말 프론트JS와 PHP백단 고수여야(__);; 어느 정도 비벼볼만 하겠더라구요..

  • profile profile
    맞아요. 에디터마다 또 달라서;;;;
    추신 말씀에 백퍼 공감입니다ㅜㅜㅜ
  • profile

    eondcom님 말씀처럼 대댓글 포지션마다 일일이 에디터를 불러오기에는 무리가 있지요. 게다가 ckeditor는 한 페이지에 에디터를 여러 개 띄울 경우 파일 첨부가 꼬이는 등의 부작용이 발생한다는 제보도 있습니다. 회원 약관 편집 화면에서 굳이 iframe으로 에디터를 띄운 것도 이 문제 때문인 것으로 기억합니다. 애당초 XE에서 ckeditor를 도입할 때, 전에 쓰던 xpresseditor와의 호환성 때문에 무척 괴랄한 방식으로 연동해 놓았는데, 라이믹스에서 이걸 좀더 깔끔하게 고치고 싶어도 기존 스킨들이... ㅠㅠ

     

    댓글 포지션에 에디터 하나를 미리 띄워놓고, 대댓글 작성시 그 에디터를 적당한 위치에 옮겨서 보여주는 방법도 괜찮을 것 같습니다. 대댓글 작성 완료 후에는 원위치시키고요. 그 때마다 parent_srl 등 몇몇 값들은 조작이 필요하겠지요. 단, inline script가 상당히 많기 때문에 에디터 영역의 태그 구조를 통째로 떼어서 다른 곳에 붙이기보다는 CSS position 속성으로 눈에 보이는 위치만 옮기는 것을 추천합니다.

  • profile profile

    스케치북 기반으로 하고 있는데, 다행히 textarea 대댓글폼이 그런 식으로 위치 이동하는 방식으로 되어 있어서 말씀하신 방식으로 수월하게 구현했습니다. 이제 파일 연결도 잘 됩니다.

    다만, 두 가지 마이너한 이슈가 있습니다.
    - 일반 댓글 창의 파일업로드 요소랑 id(#xe-fileupload)가 겹쳐서 콘솔에 노란색 경고가 살짝 뜨고요;
    - 그 이유 때문인지 몰라도, (이건 마냥 마이너하지만은 않은데요) 일반 댓글에서는 괜찮은데 대댓글의 텍스트 결과물은 태그가 그대로 노출되네요
    사례. <p>이거냐<img src="/files/attach/images/44239/499/044/30ce532876a01c172277b36a1401563b.png" alt="Survey_Diagram.png" editor_component="image_link" data-file-srl="44500" ></p>

     

    덧. id 중복 문제는 ckeditor 스킨의 file_upload.html에서 해당 id를 제거했더니 에러 출력 없이 다른 기능도 정상 작동합니다. 다른 애드온이나 모듈에 영향이 있지 않을지...

     

    덧2. 이게 심플에디터에서만 되고 ck에디터에서는 아예 키보드 입력이 되질 않네요. 말씀하신 것처럼 position 속성 등으로 다시 시도해봐야겠습니다ㅜㅜ

  • profile profile
    말씀해주신 방법 + ck에디터로 성공했습니다 ;)
    심지어 ck에디터는 파일업로드 요소마저도 id에 일련번호를 매기게 돼 있어서 id 중복 경고도 뜨지 않더라구요.
    언제나 적절한 조언 감사드립니다!
    더 많이 테스트해봐야겠지만 심플에디터로는 말씀드린 것처럼 id 중복 문제(파일업로드 템플릿은 ck에디터 스킨에 있는 템플릿을 가져다 쓰더군요ㅋ), 대댓글에 한정해서 콘텐츠의 html entity 문제가 있었습니다.
  • profile profile
    네 말씀대로 그때마다 parent_srl 이나 파일값등을 변경해야하는게 전 어렵더라구요.
    브라우저 특성도 탔고요 ㅠㅠ
  • profile profile
    ck에디터에서 만들 때 그 내용 태그를 미리 만들어서 넣어줘야 입력이 혹시 되지 않던가요..
  • profile profile

    내용 태그란 name="content" 말씀이시죠?
    textarea태그를 그렇게 지정해서 form태그 안에 넣어놨습니다.
    대댓글 form안의 parent_srl은 대댓글 버튼 클릭할 때 해당 댓글의 comment_srl로 바꿔주었구요.

    자세한 작업 경과는 좀 더 보완 작업을 한 뒤 정리해서 올려볼게요.

  • profile profile

    아뇨 저도 ckeditor로 작업해보다가, 에디터 안쪽 편집하려고 할 때 에디터 내부 클릭이 안되길래 왜 안되나 싶어서 봤더니,
    해당 에디터 안에 <body> 안에 태그가 있어야지 내용입력이 되더라구요.
    그래서 에디터 안에 body 안에 내용 태그를 <p>..</p> 이렇게 넣어주니 클릭이 되더군요.

  • profile profile
    작업하다가 그런 비슷한 경우가 있었던 것도 같은데, 그게 에디터를 부모댓글 아래로 삽입시켰을 때 나타난 현상 같기도 하고... 어느 경우인지 특정하기 어렵지만 저는 그때 바로 원복하고 다시 작업을 했었어요;;;
  • profile profile
    네 대댓글 작업이라서 아마 -_- 그랬을 겁니다.
  • profile profile
    암튼 저는 하얗게 불태웠습니다;;;
    https://xetown.com/tips/1710333