steveyehtw's picture
Protect student drafts during reconnects and workspace changes
bfe0d21
Raw History Blame Contribute Delete
8.87 kB
<!doctype html>
<html lang="zh-Hant" class="student-page">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<meta name="color-scheme" content="light">
<title>Python 專案教室|學生工作區</title>
<link rel="stylesheet" href="/classroom-assets/vendor/codemirror/codemirror.css">
<link rel="stylesheet" href="/classroom-assets/vendor/codemirror/material-darker.css">
<link rel="stylesheet" href="/classroom-assets/classroom.css?v=2026fall-21">
</head>
<body>
<header class="app-header">
<div class="brand">
<div class="brand-mark">Py</div>
<div class="brand-copy">
<strong>Python 專案教室</strong>
<span id="studentIdentity">尚未進入教室</span>
</div>
</div>
<div class="header-actions">
<div class="connection-state"><i class="status-dot" id="connectionDot"></i><span id="connectionText">未連線</span></div>
<button class="btn help compact" id="helpButton" aria-describedby="helpStatus">請老師協助</button>
<button class="btn secondary compact" id="identityButton">更換身分</button>
</div>
</header>
<span class="sr-only" id="helpStatus" aria-live="polite"></span>
<section class="project-bar">
<div class="project-context">
<label for="weekSelect">Lesson</label><select id="weekSelect"></select>
<label for="projectName">專案</label><input id="projectName" maxlength="36">
</div>
<div class="project-actions">
<button class="copy-button" id="templateButton">匯入專案起始套版</button>
<button class="copy-button" id="progressButton">選擇舊進度</button>
<button class="copy-button" id="importButton">匯入 .py / ZIP</button>
<button class="copy-button" id="exportButton">匯出專案</button>
<button class="copy-button checkpoint-action" id="checkpointButton" title="建立一個可以從進度載回的版本,不會交給老師或發布">暫存版本</button>
<button class="btn compact" id="submitButton" title="正式提交目前版本給老師檢查;老師另行發布後才會公開">正式提交</button>
<input id="fileImport" type="file" accept=".py,.zip" hidden>
</div>
</section>
<nav class="mobile-tabs" role="tablist">
<button class="mobile-tab" data-panel="referencePanel">專案/任務</button>
<button class="mobile-tab" data-panel="editorPanel" aria-selected="true">程式</button>
<button class="mobile-tab" data-panel="consolePanel">執行結果</button>
</nav>
<main class="student-layout" id="studentLayout">
<aside class="panel reference-panel" id="referencePanel">
<div class="side-tabs">
<button class="side-tab active" data-side="filesView">專案檔案</button>
<button class="side-tab" data-side="syntaxView">語法查詢</button>
<button class="side-tab" data-side="lessonView" id="lessonTab">本堂任務</button>
</div>
<section class="side-view" id="filesView">
<div class="panel-heading"><h1>檔案夾</h1><button class="copy-button" id="newFileButton">+新增</button></div>
<div class="file-list" id="fileList"></div>
<p class="side-note">入口固定為 <code>main.py</code>,可用 <code>import</code> 引入其他 Python 檔。</p>
</section>
<section class="side-view" id="syntaxView" hidden>
<div class="panel-heading"><h1>Python 語法查詢</h1><span id="snippetCount">0 項</span></div>
<div class="search-wrap">
<label class="field-label" for="syntaxSearch">輸入語法或用途</label>
<input class="text-field" id="syntaxSearch" type="search">
<div class="chip-row" id="categoryFilters"></div>
</div>
<div class="snippet-list" id="snippetList"></div>
</section>
<section class="side-view" id="lessonView" hidden>
<div class="panel-heading"><h1 id="lessonHeading">本堂任務</h1><span id="lessonLabel"></span></div>
<div class="lesson-guide-content" id="lessonGuideContent"></div>
</section>
</aside>
<div class="panel-resizer reference-resizer" id="referenceResizer" role="separator" aria-label="調整專案側欄寬度" aria-orientation="vertical" tabindex="0" title="拖曳調整寬度;雙擊恢復預設"></div>
<section class="panel editor-panel mobile-active" id="editorPanel">
<div class="panel-heading dark">
<span class="file-name" id="activeFileLabel">main.py</span>
<div class="editor-toolbar">
<button class="editor-toggle" id="toggleReferenceButton" aria-pressed="false">隱藏側欄</button>
<button class="editor-toggle" id="toggleConsoleButton" aria-pressed="false">隱藏 Console</button>
<button class="btn stop compact" id="stopButton" disabled>停止</button>
<button class="btn compact" id="runButton" disabled>載入 Python…</button>
</div>
</div>
<div class="editor-host"><textarea id="codeEditor" aria-label="程式碼"></textarea></div>
</section>
<div class="panel-resizer console-resizer" id="consoleResizer" role="separator" aria-label="調整 Console 寬度" aria-orientation="vertical" tabindex="0" title="拖曳調整寬度;雙擊恢復預設"></div>
<aside class="panel console-panel" id="consolePanel">
<div class="panel-heading"><h2>執行結果</h2><button class="copy-button" id="clearOutputButton">清除</button></div>
<div class="console-body">
<div class="console-tabs" id="consoleTabs" role="tablist" aria-label="執行結果檢視" hidden>
<button class="console-tab active" id="consoleOutputTab" role="tab" aria-selected="true">文字輸出</button>
<button class="console-tab" id="pygameOutputTab" role="tab" aria-selected="false">遊戲畫面</button>
</div>
<div class="console-stream" id="consoleStream" data-view="console">
<pre class="console-output" id="consoleOutput">Python 執行環境載入中…</pre>
<iframe id="pygameFrame" title="Pygame 遊戲畫面" sandbox="allow-scripts" hidden></iframe>
<form class="console-input-row" id="consoleInputForm" hidden>
<span aria-hidden="true">›</span>
<label class="sr-only" for="consoleInput">Python 程式要求輸入</label>
<input id="consoleInput" autocomplete="off">
<button class="btn compact" type="submit">送出</button>
</form>
</div>
<p class="console-hint" id="consoleHint">一般 Python 可使用 <code>input()</code>。Pygame 使用瀏覽器畫布,需用 <code>async main()</code> 與 <code>await asyncio.sleep()</code>;目前支援程式繪圖,不支援 <code>input()</code> 或外部圖片/音效檔。範例請在語法查詢搜尋 Pygame。</p>
<div class="console-status">
<i class="status-dot" id="runStatusDot"></i><span id="runStatusText">準備環境</span>
<span>·</span><span id="saveStatus">尚未同步</span>
<span>·</span><span id="submitStatus">尚未暫存或提交</span>
</div>
</div>
</aside>
</main>
<dialog id="identityDialog">
<form class="dialog-content form-stack" id="identityForm">
<div><h1>進入程式教室</h1><p>選擇班級並輸入自己在名單上的姓名。</p></div>
<div><label class="field-label" for="classCode">課程</label><select class="text-field" id="classCode" required></select></div>
<div><label class="field-label" for="displayName">姓名</label><input class="text-field" id="displayName" autocomplete="name" required><p class="field-help">姓名必須與老師建立的名單一致。</p></div>
<p class="form-error" id="identityError" role="alert"></p>
<button class="btn" type="submit">進入教室</button>
</form>
</dialog>
<dialog id="progressDialog">
<div class="dialog-content">
<h2>選擇已儲存版本</h2>
<p>自動同步更新老師可查看的目前草稿,不會建立歷史版本;「暫存版本」建立可載回的工作版本;「正式提交」凍結一份交給老師檢查,老師另行發布後才會公開。載入舊版本只建立工作副本,不會刪除歷史紀錄。</p>
<div class="progress-list" id="progressList"></div>
<button class="btn secondary dialog-close">關閉</button>
</div>
</dialog>
<div class="toast" id="toast"></div>
<script src="/classroom-assets/vendor/codemirror/codemirror.js"></script>
<script src="/classroom-assets/vendor/codemirror/python.js"></script>
<script src="/classroom-assets/vendor/jszip/jszip.min.js"></script>
<script src="/classroom-assets/pygame-support.js?v=2026fall-1"></script>
<script src="/classroom-assets/student.js?v=2026fall-20"></script>
</body>
</html>