{"id":642,"date":"2026-04-18T15:26:19","date_gmt":"2026-04-18T06:26:19","guid":{"rendered":"https:\/\/hydrogen.sandboxwork.com\/?page_id=642"},"modified":"2026-04-19T09:02:00","modified_gmt":"2026-04-19T00:02:00","slug":"%e5%85%b1%e6%9c%89%e3%83%9c%e3%83%bc%e3%83%89","status":"publish","type":"page","link":"https:\/\/hydrogen.sandboxwork.com\/?page_id=642","title":{"rendered":"\u5171\u6709\u30dc\u30fc\u30c9"},"content":{"rendered":"\n<p class=\"txtStyle1\"><span>\u4e3b\u306a\u4f7f\u7528\u7528\u9014<\/span>\u5168\u54e1\u3067\u5229\u7528\u3059\u308b\u30d5\u30ea\u30fc\u306e\u5171\u6709\u30dc\u30fc\u30c9<\/p>\n\n\n\t<div id=\"sce-wrap\" class=\"sce-wrap\">\n\t\t<p>\u30cb\u30c3\u30af\u30cd\u30fc\u30e0\u3092\u5165\u529b\u3057\u3066\u53c2\u52a0\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\t\t<div class=\"sce-login\">\n\t\t\t<label for=\"sceNickname\">\u30cb\u30c3\u30af\u30cd\u30fc\u30e0<\/label>\n\t\t\t<div class=\"sce-login-row\">\n\t\t\t\t<input type=\"text\" id=\"sceNickname\" maxlength=\"20\" placeholder=\"\u4f8b\uff1a\u751f\u5f92A\">\n\t\t\t\t<button type=\"button\" id=\"sceJoinBtn\">\u53c2\u52a0\u3059\u308b<\/button>\n\t\t\t<\/div>\n\t\t<\/div>\n\n\t\t<div id=\"sce-main\" style=\"display:none;\">\n\t\t\t<div class=\"sce-participants-card\">\n\t\t\t\t<div class=\"sce-card-title\">\u53c2\u52a0\u8005<\/div>\n\t\t\t\t<div id=\"sce-members\" class=\"sce-members\"> - <\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"sce-status-row\">\n\t\t\t\t<div class=\"sce-status-item\">\n\t\t\t\t\t<span class=\"sce-status-label\">\u7de8\u96c6\u4e2d\uff1a<\/span>\n\t\t\t\t\t<span id=\"sce-lock-status\" class=\"sce-status-value\"> - <\/span>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"sce-status-item\" style=\"display: none;\">\n\t\t\t\t\t<span class=\"sce-status-label\">\u6700\u7d42\u66f4\u65b0\u8005\uff1a<\/span>\n\t\t\t\t\t<span id=\"sce-last-editor\" class=\"sce-status-value\"> - <\/span>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"sce-status-item\">\n\t\t\t\t\t<span class=\"sce-status-label\">\u6700\u7d42\u7de8\u96c6\u7b87\u6240\uff1a<\/span>\n\t\t\t\t\t<span id=\"sce-last-line\" class=\"sce-status-value\"> - <\/span>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<div class=\"sce-editor\">\n\t\t\t\t<label for=\"sceTextarea\">\u7de8\u96c6\u30a8\u30ea\u30a2<\/label>\n\n\t\t\t\t<div class=\"sce-editor-wrap\">\n\t\t\t\t\t<div id=\"sceLineNumbers\" class=\"sce-line-numbers\">1<\/div>\n\t\t\t\t\t<textarea id=\"sceTextarea\" rows=\"14\" disabled><\/textarea>\n\t\t\t\t<\/div>\n\n\t\t\t\t<div class=\"sce-buttons\">\n\t\t\t\t\t<button type=\"button\" id=\"sceEditBtn\">\u7de8\u96c6\u958b\u59cb<\/button>\n\t\t\t\t\t<button type=\"button\" id=\"sceSaveBtn\" disabled>\u78ba\u5b9a\u3057\u3066\u5171\u6709<\/button>\n\t\t\t\t\t<button type=\"button\" id=\"sceCancelBtn\" disabled>\u30ad\u30e3\u30f3\u30bb\u30eb<\/button>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n\t<\/div>\n\n\t<style>\n\t\t.sce-wrap {\n\t\t\tmax-width: 1200px;\n\t\t\tmargin: 32px auto;\n\t\t\tpadding: 0;\n\t\t\tbackground: #fff;\n\t\t}\n\n\t\t.sce-login {\n\t\t\tmargin-bottom: 26px;\n\t\t}\n\n\t\t.sce-login label {\n\t\t\tdisplay: block;\n\t\t\tmargin-bottom: 12px;\n\t\t\tfont-size: 1.05rem;\n\t\t\tfont-weight: 700;\n\t\t\tcolor: #1f2937;\n\t\t}\n\n\t\t.sce-login-row {\n\t\t\tdisplay: flex;\n\t\t\tgap: 18px;\n\t\t\talign-items: center;\n\t\t}\n\n\t\t#sceNickname {\n\t\t\twidth: 50%;\n\t\t\theight: 45px;\n\t\t\tpadding: 0 15px;\n\t\t\tborder: 1px solid #d1d5db;\n\t\t\tborder-radius: 10px;\n\t\t\tbackground: #fff;\n\t\t\tfont-size: 1.15rem;\n\t\t\tcolor: #111827;\n\t\t\tbox-sizing: border-box;\n\t\t\toutline: none;\n\t\t}\n\n\t\t#sceNickname:focus {\n\t\t\tborder-color: #7aaee0;\n\t\t\tbox-shadow: 0 0 0 4px rgba(122, 174, 224, .16);\n\t\t}\n\n\t\t#sceJoinBtn {\n\t\t\tflex: 0 0 auto;\n\t\t\theight: 45px;\n\t\t\tpadding: 0 32px;\n\t\t\tborder: none;\n\t\t\tborder-radius: 10px;\n\t\t\tbackground: #2377bf;\n\t\t\tcolor: #fff;\n\t\t\tfont-size: 1rem;\n\t\t\tfont-weight: 700;\n\t\t\tcursor: pointer;\n\t\t\twhite-space: nowrap;\n\t\t}\n\n\t\t#sceJoinBtn:disabled {\n\t\t\tbackground: #cfd8e6;\n\t\t\tcursor: not-allowed;\n\t\t}\n\n\t\t.sce-participants-card {\n\t\t\tbackground: #f8fafc;\n\t\t\tborder: 1px solid #e5e7eb;\n\t\t\tborder-radius: 18px;\n\t\t\tpadding: 10px 24px;\n\t\t\tmargin-bottom: 24px;\n\t\t}\n\n\t\t.sce-card-title {\n\t\t\tfont-size: 1.1rem;\n\t\t\tfont-weight: 700;\n\t\t\tcolor: #111827;\n\t\t\tmargin-bottom: 16px;\n\t\t}\n\n\t\t.sce-members {\n\t\t\tmin-height: 44px;\n\t\t}\n\n\t\t.sce-tag {\n\t\t\tdisplay: inline-block;\n\t\t\tmargin: 0 12px 0 0;\n\t\t\tpadding: 10px 20px;\n\t\t\tborder-radius: 999px;\n\t\t\tbackground: #dbe7f6;\n\t\t\tcolor: #1d4ed8;\n\t\t\tfont-size: 1rem;\n\t\t\tfont-weight: 700;\n\t\t\tline-height: 1;\n\t\t}\n\n\t\t.sce-tag.you {\n\t\t\tbackground: #d9f0d7;\n\t\t\tcolor: #15803d;\n\t\t}\n\n\t\t.sce-tag.editing {\n\t\t\tbackground: #f7e8b5;\n\t\t\tcolor: #9a6700;\n\t\t}\n\n\t\t.sce-status-row {\n\t\t\tdisplay: flex;\n\t\t\tflex-wrap: wrap;\n\t\t\tgap: 42px;\n\t\t\talign-items: center;\n\t\t\tmargin: 0 0 20px;\n\t\t\tpadding: 0 4px;\n\t\t}\n\n\t\t.sce-status-item {\n\t\t\tfont-size: 1rem;\n\t\t\tfont-weight: 700;\n\t\t}\n\n\t\t.sce-status-label {\n\t\t\tcolor: #b91c1c;\n\t\t}\n\n\t\t.sce-status-value {\n\t\t\tcolor: #111827;\n\t\t}\n\n\t\t.sce-editor {\n\t\t\tmargin-top: 8px;\n\t\t}\n\n\t\t.sce-editor label {\n\t\t\tdisplay: block;\n\t\t\tmargin-bottom: 12px;\n\t\t\tfont-size: 1.1rem;\n\t\t\tfont-weight: 700;\n\t\t\tcolor: #111827;\n\t\t}\n\n\t\t.sce-editor-wrap {\n\t\t\tdisplay: flex;\n\t\t\talign-items: stretch;\n\t\t\tborder: 1px solid #d1d5db;\n\t\t\tborder-radius: 22px;\n\t\t\toverflow: hidden;\n\t\t\tbackground: #fff;\n\t\t}\n\n\t\t.sce-line-numbers {\n\t\t\tflex: 0 0 64px;\n\t\t\twidth: 64px;\n\t\t\tpadding: 18px 10px 18px 0;\n\t\t\tbackground: #f8fafc;\n\t\t\tborder-right: 1px solid #e5e7eb;\n\t\t\tcolor: #94a3b8;\n\t\t\tfont-family: monospace;\n\t\t\tfont-size: 0.95rem;\n\t\t\tline-height: 1.2rem;\n\t\t\ttext-align: right;\n\t\t\twhite-space: pre;\n\t\t\tuser-select: none;\n\t\t\toverflow-y: auto;\n\t\t\toverflow-x: hidden;\n\t\t\tscrollbar-width: none;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\n\t\t.sce-line-numbers::-webkit-scrollbar {\n\t\t\tdisplay: none;\n\t\t}\n\n\t\t#sceTextarea {\n\t\t\tflex: 1;\n\t\t\twidth: 100%;\n\t\t\tborder: none;\n\t\t\tborder-radius: 0;\n\t\t\tpadding: 18px 20px;\n\t\t\tbackground: #fff;\n\t\t\tcolor: #111827;\n\t\t\tfont-family: monospace;\n\t\t\tfont-size: 0.95rem;\n\t\t\tline-height: 1.2rem;\n\t\t\ttab-size: 2;\n\t\t\tbox-sizing: border-box;\n\t\t\toutline: none;\n\t\t\toverflow-y: auto;\n\t\t\toverflow-x: auto;\n\t\t\twhite-space: pre;\n\t\t\tresize: vertical;\n\t\t}\n\n\t\t#sceTextarea:focus {\n\t\t\tbox-shadow: none;\n\t\t}\n\n\t\t.sce-buttons {\n\t\t\tdisplay: flex;\n\t\t\tflex-wrap: wrap;\n\t\t\tgap: 12px;\n\t\t\tmargin-top: 14px;\n\t\t}\n\n\t\t.sce-buttons button {\n\t\t\tpadding: 12px 18px;\n\t\t\tborder: none;\n\t\t\tborder-radius: 12px;\n\t\t\tfont-size: .95rem;\n\t\t\tfont-weight: 700;\n\t\t\tcursor: pointer;\n\t\t\tcolor: #fff;\n\t\t\tbackground: #2377bf;\n\t\t}\n\n\t\t.sce-buttons button:disabled {\n\t\t\tbackground: #cbd5e1;\n\t\t\tcursor: not-allowed;\n\t\t}\n\n\t\t@media (max-width: 768px) {\n\t\t\t.sce-login-row {\n\t\t\t\tflex-direction: column;\n\t\t\t\talign-items: stretch;\n\t\t\t}\n\n\t\t\t#sceJoinBtn {\n\t\t\t\twidth: 100%;\n\t\t\t}\n\n\t\t\t.sce-status-row {\n\t\t\t\tgap: 18px;\n\t\t\t\tflex-direction: column;\n\t\t\t\talign-items: flex-start;\n\t\t\t}\n\n\t\t\t#sceTextarea {\n\t\t\t\theight: 380px;\n\t\t\t}\n\t\t}\n\t<\/style>\n\n\t<script type=\"module\">\n\t\timport { initializeApp } from \"https:\/\/www.gstatic.com\/firebasejs\/10.12.2\/firebase-app.js\";\n\t\timport { getAuth, signInAnonymously, onAuthStateChanged } from \"https:\/\/www.gstatic.com\/firebasejs\/10.12.2\/firebase-auth.js\";\n\t\timport { getDatabase, ref, onValue, set, update, remove, runTransaction, onDisconnect, get } from \"https:\/\/www.gstatic.com\/firebasejs\/10.12.2\/firebase-database.js\";\n\n\t\tconst firebaseConfig = {\n\t\t\tapiKey: \"AIzaSyAAMAFq6I1pzsK_a0vrboG06mTOdK_l5eU\",\n\t\t\tauthDomain: \"shareboard-80020.firebaseapp.com\",\n\t\t\tdatabaseURL: \"https:\/\/shareboard-80020-default-rtdb.asia-southeast1.firebasedatabase.app\",\n\t\t\tprojectId: \"shareboard-80020\",\n\t\t\tstorageBucket: \"shareboard-80020.firebasestorage.app\",\n\t\t\tmessagingSenderId: \"431547836696\",\n\t\t\tappId: \"1:431547836696:web:bd66760b84d349b8b8166d\"\n\t\t};\n\n\t\tconst ROOM_ID = \"classroom-001\";\n\n\t\tconst app = initializeApp(firebaseConfig);\n\t\tconst auth = getAuth(app);\n\t\tconst db = getDatabase(app);\n\n\t\tconst nicknameInput = document.getElementById(\"sceNickname\");\n\t\tconst joinBtn = document.getElementById(\"sceJoinBtn\");\n\t\tconst main = document.getElementById(\"sce-main\");\n\t\tconst membersBox = document.getElementById(\"sce-members\");\n\t\tconst lastEditorBox = document.getElementById(\"sce-last-editor\");\n\t\tconst lockStatusBox = document.getElementById(\"sce-lock-status\");\n\t\tconst lastLineBox = document.getElementById(\"sce-last-line\");\n\t\tconst textarea = document.getElementById(\"sceTextarea\");\n\t\tconst lineNumbersBox = document.getElementById(\"sceLineNumbers\");\n\t\tconst editBtn = document.getElementById(\"sceEditBtn\");\n\t\tconst saveBtn = document.getElementById(\"sceSaveBtn\");\n\t\tconst cancelBtn = document.getElementById(\"sceCancelBtn\");\n\n\t\tconst basePath = `sharedEditor\/${ROOM_ID}`;\n\t\tconst roomRef = ref(db, basePath);\n\t\tconst lockRef = ref(db, `${basePath}\/lock`);\n\t\tconst participantsRef = ref(db, `${basePath}\/participants`);\n\t\tconst draftRef = ref(db, `${basePath}\/draft`);\n\t\tconst draftEditorRef = ref(db, `${basePath}\/draftEditor`);\n\n\t\tlet currentUser = null;\n\t\tlet myNickname = \"\";\n\t\tlet isEditing = false;\n\t\tlet isJoined = false;\n\n\t\tconst clientId = sessionStorage.getItem(\"sceClientId\") || crypto.randomUUID();\n\t\tsessionStorage.setItem(\"sceClientId\", clientId);\n\n\t\tfunction updateTextareaLineNumbers() {\n\t\t\tconst lineCount = (textarea.value.match(\/\\n\/g) || []).length + 1;\n\t\t\tconst numbers = [];\n\t\t\tfor (let i = 1; i <= lineCount; i++) {\n\t\t\t\tnumbers.push(i);\n\t\t\t}\n\t\t\tlineNumbersBox.textContent = numbers.join(\"\\n\");\n\t\t}\n\n\t\tfunction getLastEditedLine(oldCode, newCode) {\n\t\t\tconst oldLines = (oldCode || \"\").split(\"\\n\");\n\t\t\tconst newLines = (newCode || \"\").split(\"\\n\");\n\t\t\tconst maxLength = Math.max(oldLines.length, newLines.length);\n\t\t\tlet lastLine = 0;\n\n\t\t\tfor (let i = 0; i < maxLength; i++) {\n\t\t\t\tif ((oldLines[i] || \"\") !== (newLines[i] || \"\")) {\n\t\t\t\t\tlastLine = i + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn lastLine;\n\t\t}\n\n\t\tsignInAnonymously(auth).catch((error) => {\n\t\t\tconsole.error(\"\u533f\u540d\u8a8d\u8a3c\u30a8\u30e9\u30fc:\", error);\n\t\t\talert(\"\u533f\u540d\u8a8d\u8a3c\u30a8\u30e9\u30fc: \" + error.code + \" \/ \" + error.message);\n\t\t});\n\n\t\tonAuthStateChanged(auth, (user) => {\n\t\t\tif (user) currentUser = user;\n\t\t});\n\n\t\tfunction watchParticipants() {\n\t\t\tonValue(participantsRef, (snapshot) => {\n\t\t\t\tconst data = snapshot.val();\n\n\t\t\t\tif (!data) {\n\t\t\t\t\tmembersBox.innerHTML = \" - \";\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst html = Object.values(data)\n\t\t\t\t\t.sort((a, b) => (a.joinedAt || 0) - (b.joinedAt || 0))\n\t\t\t\t\t.map((item) => {\n\t\t\t\t\t\tconst isMe = item.clientId === clientId;\n\t\t\t\t\t\treturn `<span class=\"sce-tag ${isMe ? 'you' : ''}\">${item.nickname}<\/span>`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\");\n\n\t\t\t\tmembersBox.innerHTML = html || \" - \";\n\t\t\t});\n\t\t}\n\n\t\tfunction watchRoom() {\n\t\t\tonValue(roomRef, (snapshot) => {\n\t\t\t\tconst data = snapshot.val() || {};\n\n\t\t\t\tlastEditorBox.textContent = data.lastEditor || \" - \";\n\t\t\t\tlastLineBox.textContent = data.lastEditedLine ? `${data.lastEditedLine}\u884c\u76ee` : \" - \";\n\n\t\t\t\tif (data.draftEditor) {\n\t\t\t\t\tlockStatusBox.innerHTML = `<span class=\"sce-tag editing\">${data.draftEditor}<\/span>`;\n\t\t\t\t} else if (data.lock && data.lock.nickname) {\n\t\t\t\t\tlockStatusBox.innerHTML = `<span class=\"sce-tag editing\">${data.lock.nickname}<\/span>`;\n\t\t\t\t} else {\n\t\t\t\t\tlockStatusBox.textContent = \" - \";\n\t\t\t\t}\n\n\t\t\t\tconst someoneElseEditing = data.lock && data.lock.uid && data.lock.uid !== currentUser?.uid;\n\n\t\t\t\tif (!isEditing) {\n\t\t\t\t\tif (data.draft && data.draftEditor) {\n\t\t\t\t\t\ttextarea.value = data.draft;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttextarea.value = data.code || \"\";\n\t\t\t\t\t}\n\t\t\t\t\tupdateTextareaLineNumbers();\n\t\t\t\t}\n\n\t\t\t\tif (someoneElseEditing) {\n\t\t\t\t\teditBtn.disabled = true;\n\t\t\t\t} else if (!isEditing) {\n\t\t\t\t\teditBtn.disabled = false;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\teditBtn.addEventListener(\"click\", async () => {\n\t\t\tif (!currentUser || !myNickname) return;\n\n\t\t\tconst result = await runTransaction(lockRef, (current) => {\n\t\t\t\tif (current === null) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tuid: currentUser.uid,\n\t\t\t\t\t\tnickname: myNickname,\n\t\t\t\t\t\tstartedAt: Date.now()\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t});\n\n\t\t\tif (!result.committed) {\n\t\t\t\talert(\"\u73fe\u5728\u307b\u304b\u306e\u4eba\u304c\u7de8\u96c6\u4e2d\u3067\u3059\u3002\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tisEditing = true;\n\t\t\ttextarea.disabled = false;\n\t\t\tsaveBtn.disabled = false;\n\t\t\tcancelBtn.disabled = false;\n\t\t\teditBtn.disabled = true;\n\n\t\t\tonDisconnect(lockRef).remove();\n\t\t});\n\n\t\tsaveBtn.addEventListener(\"click\", async () => {\n\t\t\tif (!isEditing) return;\n\n\t\t\tconst currentSnapshot = await get(roomRef);\n\t\t\tconst currentData = currentSnapshot.val() || {};\n\t\t\tconst oldCode = currentData.code || \"\";\n\t\t\tconst newCode = textarea.value;\n\t\t\tconst lastEditedLine = getLastEditedLine(oldCode, newCode);\n\n\t\t\tawait update(roomRef, {\n\t\t\t\tcode: newCode,\n\t\t\t\tlastEditor: myNickname,\n\t\t\t\tlastEditedLine: lastEditedLine,\n\t\t\t\tupdatedAt: Date.now(),\n\t\t\t\tdraft: \"\",\n\t\t\t\tdraftEditor: \"\"\n\t\t\t});\n\n\t\t\t\/\/await saveLogToTxt(myNickname, newCode, lastEditedLine);\n\t\t\tawait remove(lockRef);\n\n\t\t\tisEditing = false;\n\t\t\ttextarea.disabled = true;\n\t\t\tsaveBtn.disabled = true;\n\t\t\tcancelBtn.disabled = true;\n\t\t\teditBtn.disabled = false;\n\t\t\tupdateTextareaLineNumbers();\n\t\t});\n\n\t\tcancelBtn.addEventListener(\"click\", async () => {\n\t\t\tif (!isEditing) return;\n\n\t\t\tconst currentSnapshot = await get(roomRef);\n\t\t\tconst currentData = currentSnapshot.val() || {};\n\n\t\t\ttextarea.value = currentData.code || \"\";\n\t\t\tupdateTextareaLineNumbers();\n\n\t\t\tawait update(roomRef, {\n\t\t\t\tdraft: \"\",\n\t\t\t\tdraftEditor: \"\"\n\t\t\t});\n\n\t\t\tawait remove(lockRef);\n\n\t\t\tisEditing = false;\n\t\t\ttextarea.disabled = true;\n\t\t\tsaveBtn.disabled = true;\n\t\t\tcancelBtn.disabled = true;\n\t\t\teditBtn.disabled = false;\n\t\t});\n\n\t\ttextarea.addEventListener(\"input\", async () => {\n\t\t\tupdateTextareaLineNumbers();\n\n\t\t\tif (!isEditing) return;\n\n\t\t\ttry {\n\t\t\t\tawait update(roomRef, {\n\t\t\t\t\tdraft: textarea.value,\n\t\t\t\t\tdraftEditor: myNickname\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"draft\u66f4\u65b0\u30a8\u30e9\u30fc:\", error);\n\t\t\t}\n\t\t});\n\n\t\ttextarea.addEventListener(\"scroll\", () => {\n\t\t\tlineNumbersBox.scrollTop = textarea.scrollTop;\n\t\t});\n\n\t\tjoinBtn.addEventListener(\"click\", async () => {\n\t\t\tif (isJoined) {\n\t\t\t\tawait leaveRoom();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst nickname = nicknameInput.value.trim();\n\n\t\t\tif (!nickname) {\n\t\t\t\talert(\"\u30cb\u30c3\u30af\u30cd\u30fc\u30e0\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!currentUser) {\n\t\t\t\talert(\"\u8a8d\u8a3c\u5f85\u6a5f\u4e2d\u3067\u3059\u3002\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmyNickname = nickname;\n\t\t\tisJoined = true;\n\n\t\t\tjoinBtn.textContent = \"\u9000\u51fa\u3059\u308b\";\n\t\t\tjoinBtn.disabled = false;\n\t\t\tnicknameInput.disabled = true;\n\t\t\tmain.style.display = \"block\";\n\n\t\t\tconst myParticipantRef = ref(db, `${basePath}\/participants\/${clientId}`);\n\n\t\t\tawait set(myParticipantRef, {\n\t\t\t\tnickname: myNickname,\n\t\t\t\tuid: currentUser.uid,\n\t\t\t\tclientId: clientId,\n\t\t\t\tjoinedAt: Date.now()\n\t\t\t});\n\n\t\t\tonDisconnect(myParticipantRef).remove();\n\n\t\t\twatchRoom();\n\t\t\twatchParticipants();\n\t\t\tupdateTextareaLineNumbers();\n\t\t});\n\n\t\tasync function leaveRoom() {\n\t\t\tconst myParticipantRef = ref(db, `${basePath}\/participants\/${clientId}`);\n\n\t\t\tawait remove(myParticipantRef);\n\n\t\t\tif (isEditing) {\n\t\t\t\tawait update(roomRef, {\n\t\t\t\t\tdraft: \"\",\n\t\t\t\t\tdraftEditor: \"\"\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait remove(lockRef);\n\n\t\t\tisJoined = false;\n\t\t\tisEditing = false;\n\t\t\tmyNickname = \"\";\n\n\t\t\tjoinBtn.textContent = \"\u53c2\u52a0\u3059\u308b\";\n\t\t\tjoinBtn.disabled = false;\n\n\t\t\tnicknameInput.disabled = false;\n\t\t\tnicknameInput.value = \"\";\n\n\t\t\tmain.style.display = \"none\";\n\n\t\t\ttextarea.value = \"\";\n\t\t\ttextarea.disabled = true;\n\t\t\tupdateTextareaLineNumbers();\n\n\t\t\teditBtn.disabled = false;\n\t\t\tsaveBtn.disabled = true;\n\t\t\tcancelBtn.disabled = true;\n\t\t}\n\n\t\tnicknameInput.value = \"\";\n\n\t\tasync function saveLogToTxt(nickname, code, lastEditedLine) {\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\"\/wp-admin\/admin-ajax.php\", {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\": \"application\/x-www-form-urlencoded\"\n\t\t\t\t\t},\n\t\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\t\taction: \"save_shared_code_log_txt\",\n\t\t\t\t\t\tnickname: nickname,\n\t\t\t\t\t\tcode: code,\n\t\t\t\t\t\tlastEditedLine: String(lastEditedLine)\n\t\t\t\t\t})\n\t\t\t\t});\n\n\t\t\t\tconst result = await response.json();\n\t\t\t\tconsole.log(\"log result:\", result);\n\n\t\t\t\tif (!result.success) {\n\t\t\t\t\tconsole.error(\"\u30ed\u30b0\u4fdd\u5b58\u5931\u6557:\", result);\n\t\t\t\t\talert(\"\u30ed\u30b0\u4fdd\u5b58\u5931\u6557: \" + (result.data?.message || \"\u4e0d\u660e\u306a\u30a8\u30e9\u30fc\"));\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"\u30ed\u30b0\u4fdd\u5b58\u901a\u4fe1\u30a8\u30e9\u30fc:\", error);\n\t\t\t\talert(\"\u30ed\u30b0\u4fdd\u5b58\u901a\u4fe1\u30a8\u30e9\u30fc\");\n\t\t\t}\n\t\t}\n\t<\/script>\n\t\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4e3b\u306a\u4f7f\u7528\u7528\u9014\u5168\u54e1\u3067\u5229\u7528\u3059\u308b\u30d5\u30ea\u30fc\u306e\u5171\u6709\u30dc\u30fc\u30c9<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":6,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"swell_btn_cv_data":"","vkexunit_cta_each_option":"","footnotes":""},"class_list":["post-642","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/hydrogen.sandboxwork.com\/index.php?rest_route=\/wp\/v2\/pages\/642","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hydrogen.sandboxwork.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/hydrogen.sandboxwork.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/hydrogen.sandboxwork.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/hydrogen.sandboxwork.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=642"}],"version-history":[{"count":5,"href":"https:\/\/hydrogen.sandboxwork.com\/index.php?rest_route=\/wp\/v2\/pages\/642\/revisions"}],"predecessor-version":[{"id":669,"href":"https:\/\/hydrogen.sandboxwork.com\/index.php?rest_route=\/wp\/v2\/pages\/642\/revisions\/669"}],"wp:attachment":[{"href":"https:\/\/hydrogen.sandboxwork.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=642"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}