5.Code Chat - asdfgl98/Project-CodeBuddy GitHub Wiki

๐Ÿ“ŒCode Chat ์ฃผ์š” ๊ธฐ๋Šฅ

โœ… Code Editor

  • CodeMirror ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ์›นํŽ˜์ด์ง€์—์„œ Code Editor๋ฅผ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ €๋Š” Back-end ํŒŒํŠธ๋ฅผ ๋‹ด๋‹นํ•˜์˜€์ง€๋งŒ ํ”„๋กœ์ ํŠธ๊ฐ€ ์‹œ์ž‘๋˜๊ธฐ ์ „ codemirror ์‚ฌ์šฉ๋ฒ•์„ ๊ณต๋ถ€ํ•˜์—ฌ
    ์‚ฌ์ „์— ๊ตฌํ˜„์„ ํ•ด ๋†“์•˜๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ์ ํŠธ๊ฐ€ ์‹œ์ž‘๋˜์—ˆ์„ ๋•Œ Front๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ํŒ€์›๋“ค์—๊ฒŒ ๊ณต์œ ๋ฅผ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋˜ํ•œ, Front๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ํŒ€์›๋“ค์ด ์‚ฌ์šฉํ•˜๊ธฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋„์›€์„ ์ค„ ์ˆ˜ ์žˆ๋„๋ก ๊ฐ๊ฐ์˜ ํŒŒ์ผ ๋ณ„๋กœ ์–ด๋–ค ํŒŒ์ผ์„ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š”์ง€ ์ •๋ฆฌํ•˜์—ฌ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ด€๋ จ ์ด๋ฏธ์ง€

image

๐Ÿ’ป CodeDetail

CodeEditor ์ƒ์„ฑ


codeEditor_Jo.js (line 7)

const codeStarting = document.querySelector('#codeStart')
const codeStarting2 = document.querySelector('#codeStart2')

const texthtml = document.querySelector('#html');
const textcss = document.querySelector('#css');
const textjs = document.querySelector('#js');
const outPut = document.querySelector('#live');
let activeEditor = null;

function createEditor(target, mode) {
    return CodeMirror.fromTextArea(target, {
        mode: mode,
        theme: 'darcula',
        lineNumbers: true,
        spellcheck: true,
        extraKeys: { 'Ctrl-Space': 'autocomplete' },
        gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
        foldGutter: true,
    });
}

let html = null;
let css = null;
let js = null;

function updateOutput() {
    const outputHTML = html ? html.getValue() : '';
    const outputCSS = css ? css.getValue() : '';
    const outputJS = js ? js.getValue() : '';

    // HTML, CSS ์ฝ”๋“œ๋ฅผ iframe์˜ body์— ์ถ”๊ฐ€
    outPut.contentWindow.document.body.innerHTML = outputHTML + '<style>' + outputCSS + '</style>';
    
    // JavaScript ์ฝ”๋“œ๋ฅผ iframe์˜ body์— ์ถ”๊ฐ€
    // ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•จ
    const scriptElement = document.createElement('script');
    scriptElement.textContent = outputJS;
    outPut.contentWindow.document.body.appendChild(scriptElement);
}

function setActiveEditor(editor) {
    if (activeEditor) {
        activeEditor.getWrapperElement().style.display = 'none';
    }

    if (editor) {
        editor.getWrapperElement().style.display = 'block';
        editor.refresh();
        activeEditor = editor;
    }
}

const tabItems = document.querySelectorAll('.tab-container__item');
const contentContainers = document.querySelectorAll('.content-container__content');

tabItems.forEach((item, index) => {
    item.addEventListener('click', (e) => {
        e.preventDefault();
        tabItems.forEach((title) => {
            title.classList.remove('active');
        });
        setActiveEditor(null);

        if (index === 0) {
            if (!html) {
                html = createEditor(texthtml, 'html');
                codeStarting.addEventListener('click', updateOutput);
            }
            setActiveEditor(html);
        } else if (index === 1) {
            if (!css) {
                css = createEditor(textcss, 'text/css');
                codeStarting.addEventListener('click', updateOutput);
            }
            setActiveEditor(css);
        } else if (index === 2) {
            if (!js) {
                js = createEditor(textjs, 'text/javascript');
                codeStarting.addEventListener('click', updateOutput);
            }
            setActiveEditor(js);
        }

        item.classList.add('active');
        contentContainers[index].classList.add('target');
        // updateOutput();
    });
});

iframe์— ์ฝ”๋“œ ์‹คํ–‰๊ฒฐ๊ณผ ์ถœ๋ ฅํ•˜๋Š” ํ•จ์ˆ˜


codeEditor_Jo.js (line 32)

const updateOutput=()=> {
    const outputHTML = html ? html.getValue() : '';
    const outputCSS = css ? css.getValue() : '';
    const outputJS = js ? js.getValue() : '';

    // HTML, CSS ์ฝ”๋“œ๋ฅผ iframe์˜ body์— ์ถ”๊ฐ€
    outPut.contentWindow.document.body.innerHTML = outputHTML + '<style>' + outputCSS + '</style>';
    
    // JavaScript ์ฝ”๋“œ๋ฅผ iframe์˜ body์— ์ถ”๊ฐ€
    // ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•จ
    const scriptElement = document.createElement('script');
    scriptElement.textContent = outputJS;
    outPut.contentWindow.document.body.appendChild(scriptElement);
}

๐Ÿ–ผ๏ธ Preview

CodeEitor.gif

CodeEditor

โœ… Code Editor ํ†ต์‹ (Socket.io)

  • ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘์†ํ•˜๋ฉด ์ ‘์†ํ•œ ์‚ฌ์šฉ์ž์— ํ•ด๋‹นํ•˜๋Š” ํƒญ๊ณผ ์ฒดํฌ๋ฐ•์Šค๊ฐ€ ๋‹ค๋ฅธ ์ธ์›์—๊ฒŒ ๋ณด์—ฌ์ง€๊ฒŒ ๋˜๊ณ ,
    ์ฒดํฌ๋ฐ•์Šค๋ฅผ ํ†ตํ•ด ์›ํ•˜๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  1. ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐฉ์— ์ ‘์†ํ•  ๋•Œ, socket.io์—์„œ ์ž๋™์œผ๋กœ ๋ถ€์—ฌํ•ด์ค€ socketID(๊ณ ์œ  ๊ฐ’)์™€ ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ DB์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

  2. ์‚ฌ์šฉ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ „์†กํ•˜๊ณ ์ž ํ•˜๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์ฒดํฌํ•˜๊ณ  ์ฝ”๋“œ ๋ณด๋‚ด๊ธฐ๋ฅผ ํด๋ฆญํ•˜๋ฉด
    ๋จผ์ € ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ ์†ํ•ด์žˆ๋Š” ๋ฐฉ ๋ฒˆํ˜ธ(๊ณ ์œ  ๊ฐ’)์„ ์‘๋‹ตํ•ด์ค๋‹ˆ๋‹ค.

  3. ์‘๋‹ต๋ฐ›์€ ๋ฐฉ ๋ฒˆํ˜ธ ๊ฐ’๊ณผ ์ฒดํฌํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„์„ ํฌํ•จํ•˜์—ฌ axios๋กœ ๋ผ์šฐํ„ฐ์— ์š”์ฒญํ•˜๊ณ , ๋ผ์šฐํ„ฐ ๋‚ด๋ถ€์—์„œ DB์— ์ ‘๊ทผํ•˜์—ฌ ํ•ด๋‹นํ•˜๋Š” socketID๋ฅผ ์‘๋‹ต๋ฐ›์Šต๋‹ˆ๋‹ค.

  4. ์‘๋‹ต๋ฐ›์€ socketID์™€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์„œ๋ฒ„๋กœ ์ „์†ก ํ•ฉ๋‹ˆ๋‹ค.

  5. ์„œ๋ฒ„์—์„œ ํ•ด๋‹นํ•˜๋Š” socketID๋ฅผ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž์—๊ฒŒ๋งŒ ์ฝ”๋“œ๋ฅผ ์ „์†กํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ’ป CodeDetail

์ฝ”๋“œ ์ „์†ก ํด๋ฆญ ๋กœ์ง


codeChatList.js (line 227)

// ์ฝ”๋“œ ๋ณด๋‚ด๊ธฐ ํด๋ฆญ
const codeSend = document.querySelector('#codeSend')
codeSend.addEventListener('click',()=>{
  chatSocket.emit('sendClick')
  })

chatSocket.on('socketUser',(data)=>{
  const checkUser = document.getElementsByName('checkuser')
  
  let myHtml = html ? html.getValue() : '';
  let myCss = css ? css.getValue() : '';
  let myJs = js ? js.getValue() : '';
  
  checkUser.forEach((user)=>{
    if(user.checked == true){
      axios.post('/codeChat/userSocket', {name : user.value, roomNum : data.roomNum})
        .then(res=>{
          let data = JSON.parse(res.data)
          chatSocket.emit('codeSendBtn', {html : myHtml, css : myCss, js : myJs, name:user.value, socketId : data.SOCKET_ID})
        })
    }
  })
})

//์„ ํƒํ•œ ์œ ์ €์—๊ฒŒ ์ฝ”๋“œ ์ „์†ก
chatSocket.on('codeSend',(data)=>{
  const tabData = document.querySelector('.tab')
  const $tabLang = document.querySelectorAll('.tab-container__item2')
  html2.setValue(data.html)
  css2.setValue(data.css)
  js2.setValue(data.js)
  
  $tabLang.forEach((tab)=>{
    tab.addEventListener('click',()=>{
      if(tab.dataset.tab == 'tab4'){
        html2.setValue(data.html)
      }
      else if(tab.dataset.tab == 'tab5'){
        css2.setValue(data.css)
      }
      else if(tab.dataset.tab == 'tab6'){
        js2.setValue(data.js)
      }
    })
  })

์ฝ”๋“œ๋ฅผ ์ „์†ก๋ฐ›์€ ์„œ๋ฒ„์ธก ๋กœ์ง


server.js (line 287)

// ์ฝ”๋“œ ์ „์†ก ํด๋ฆญ ๊ฐ์ง€ ํ›„, ํ•ด๋‹น ๋ฐฉ์— ์ ‘์†ํ•ด์žˆ๋Š” ์ธ์›์—๊ฒŒ ๋ฐฉ๋ฒˆํ˜ธ ๊ฐ’ ์ „์†ก
  socket.on("sendClick", () => {
    ChatNamespace.to(socket.room_number).emit("socketUser", {
      roomNum: socket.room_number,
    });
  });

  // ์ฝ”๋“œ ์—๋””ํ„ฐ ์ฝ”๋“œ์ „์†ก
  socket.on("codeSendBtn", (data) => {
    socket.to(data.socketId).emit("codeSend", data);
  });

์ฒดํฌ๋ฐ•์Šค ๊ฐ’(์ด๋ฆ„)์œผ๋กœ DB์—์„œ socketID ๊ฒ€์ƒ‰


routes -> codeChat.js (line 181)

router.post('/userSocket',(req,res)=>{
    let roomNum = req.body.roomNum
    let userName = req.body.name
    let sql = 'SELECT * FROM CHAT_USER WHERE ROOM_NUMBER=? AND CONN_USER=?'
    conn.connect()
    conn.query(sql,[roomNum,userName],(err,result)=>{
        if(err){
            console.log('select ์˜ค๋ฅ˜')
        }
        else{
            console.log('socketID ํฌํ•จ ๋ฐ์ดํ„ฐ')
            res.json(JSON.stringify(result[0]))
        }
    })
})

๐Ÿ–ผ๏ธ Preview

CodeChat.gif

codeeditror

โš ๏ธ **GitHub.com Fallback** โš ๏ธ