Browse Source

Crippled version of task display

mj-deploy
Standa Lukeš 4 years ago
parent
commit
6ec2234ef9
  1. 14
      frontend/src/App.svelte
  2. 23
      frontend/src/Graph.svelte
  3. 12
      frontend/src/GraphNode.svelte
  4. 42
      frontend/src/TaskPanel.svelte
  5. 29
      frontend/src/ksp-task-grabber.ts

14
frontend/src/App.svelte

@ -2,10 +2,19 @@
import Graph from "./Graph.svelte";
import GraphNode from "./GraphNode.svelte";
import { loadTasks } from "./task-loader";
import type { TasksFile } from "./task-loader";
import type { TasksFile, TaskDescriptor } from "./task-loader";
import TasksLoader from "./TasksLoader.svelte";
import TaskPanel from "./TaskPanel.svelte";
const tasksPromise: Promise<TasksFile> = loadTasks();
let selectedTask: string | null = null
let finalSelect: boolean = false
function clickTask(e: CustomEvent<TaskDescriptor>) {
finalSelect = true
}
</script>
<style>
@ -37,6 +46,7 @@
</svg>
-->
<TasksLoader promise={tasksPromise} let:data={t}>
<Graph tasks={t} />
<TaskPanel bind:finalSelect={finalSelect} selectedTask={selectedTask} />
<Graph tasks={t} bind:selectedTask={selectedTask} on:selectTask={clickTask} />
</TasksLoader>
</main>

23
frontend/src/Graph.svelte

@ -1,15 +1,32 @@
<script type="ts">
import GraphNode from "./GraphNode.svelte";
import GraphEdge from "./GraphEdge.svelte";
import { onMount } from "svelte";
import { createEventDispatcher, onMount } from "svelte";
import * as d3 from "d3";
import { createLinksFromTaskMap } from "./task-loader";
import type { TasksFile } from "./task-loader";
import type { TasksFile, TaskDescriptor } from "./task-loader";
const eventDispatcher = createEventDispatcher()
export let tasks: TasksFile;
let nodes = tasks.tasks;
let edges = createLinksFromTaskMap(tasks);
export let selectedTask: null | string = null
const nodeClick = (task: TaskDescriptor) => (e: CustomEvent<MouseEvent>) => {
selectedTask = task.id
eventDispatcher("selectTask", task)
}
const nodeHover = (task: TaskDescriptor) => (hovering: CustomEvent<boolean>) => {
if (hovering.detail) {
selectedTask = task.id
} else {
if (selectedTask == task.id)
selectedTask = null
}
}
// Svelte automatically fills this with a reference
let container: HTMLElement;
@ -69,7 +86,7 @@
<GraphEdge {edge} />
{/each}
{#each nodes as task}
<GraphNode {task} />
<GraphNode {task} on:click={nodeClick(task)} on:hoveringChange={nodeHover(task)} />
{/each}
</g>
</svg>

12
frontend/src/GraphNode.svelte

@ -1,5 +1,5 @@
<script lang="ts">
import { onMount } from "svelte";
import { createEventDispatcher, onMount } from "svelte";
import type { TaskDescriptor } from "./task-loader";
@ -7,15 +7,23 @@
let hovering: boolean = false;
let text_element: SVGTextElement;
const eventDispatcher = createEventDispatcher()
$: cx = task === undefined || task.x === undefined ? 0 : task.x;
$: cy = task === undefined || task.y === undefined ? 0 : task.y;
function enter() {
hovering = true;
eventDispatcher("hoveringChange", hovering)
}
function leave() {
hovering = false;
eventDispatcher("hoveringChange", hovering)
}
function click(e: MouseEvent) {
eventDispatcher("click", e)
}
let ellipse_rx = 20;
@ -36,7 +44,7 @@
}
</style>
<g on:mouseenter={enter} on:mouseleave={leave}>
<g on:mouseenter={enter} on:mouseleave={leave} on:click={click}>
<ellipse rx={ellipse_rx} ry={ellipse_ry} {cx} {cy} />
<text
bind:this={text_element}

42
frontend/src/TaskPanel.svelte

@ -0,0 +1,42 @@
<script lang="ts">
import { grabAssignment } from "./ksp-task-grabber";
import type { TasksFile, TaskDescriptor } from "./task-loader";
// export let tasks: TasksFile;
export let selectedTask: string | null = null
export let finalSelect: boolean = false
let mouse: boolean = false
let height: string;
$: height = selectedTask == null && !mouse ? "0" :
finalSelect ? "100%" :
"100px"
let taskPromise: Promise<string | null>
$: {
if (selectedTask != null)
taskPromise = grabAssignment(selectedTask)
}
</script>
<style>
.panel {
position: absolute;
width: 100%;
background-color: #222;
overflow: hidden;
}
</style>
<div class="panel" style="height: {height}" on:mouseover={() => mouse = false} on:mouseout={() => mouse = false}>
{#if selectedTask != null}
{#await taskPromise}
Načítám úložku {selectedTask} ;)
{:then task}
{@html task}
{/await}
<button type=button on:click={() => finalSelect = false}>
Zavřít
</button>
{/if}
</div>

29
frontend/src/ksp-task-grabber.ts

@ -12,28 +12,28 @@ type TaskLocation = {
startElement: string
}
function getLocation(id: string, solution: boolean): TaskLocation {
function getLocation(id: string, solution: boolean): TaskLocation | null {
const m = /^(\d+)-(Z?)(\d)-(\d)$/.exec(id)
if (!m) throw new Error(`Invalid task id: ${m}`)
const [_, rocnik, z, serie, uloha] = m[1]
if (!m) return null
const [_, rocnik, z, serie, uloha] = m
if (z == 'Z') {
const urlX = solution ? "reseni" : "zadani"
return {
url: `z/ulohy/${rocnik}/${urlX}${serie}.html`,
startElement: `task${uloha}`
startElement: `task-${id}`
}
} else {
const urlX = solution ? "solution" : "tasks"
return {
url: `tasks/${rocnik}/${urlX}${serie}.html`,
startElement: `task${uloha}`
startElement: `task-${id}`
}
}
}
function parseTask(startElementId: string, html: string, contentType: string): string {
function parseTask(startElementId: string, html: string): string {
const parser = new DOMParser()
const doc = parser.parseFromString(html, contentType as any)
const doc = parser.parseFromString(html, "text/html")
const titleElement = doc.getElementById(startElementId)
if (!titleElement)
@ -69,14 +69,17 @@ async function loadTask({ url, startElement }: TaskLocation) {
throw Error("Bad request")
}
const rText = await r.text()
const contentType = r.headers.get("Content-Type") || "text/html"
return parseTask(startElement, rText, contentType)
return parseTask(startElement, rText)
}
export function loadAssignment(id: string) {
return loadTask(getLocation(id, false))
export async function grabAssignment(id: string) {
const l = getLocation(id, false)
if (!l) return "úloha je virtuální a neexistuje"
return await loadTask(l)
}
export function loadSolution(id: string) {
return loadTask(getLocation(id, true))
export async function grabSolution(id: string) {
const l = getLocation(id, true)
if (!l) return "úloha je virtuální a neexistuje"
return await loadTask(l)
}