From: Jakob Cornell Date: Sun, 5 Jan 2020 06:34:14 +0000 (-0600) Subject: Implement HTTP table export X-Git-Url: https://jcornell.net/gitweb/gitweb.cgi?a=commitdiff_plain;h=d2d5b89e9b9e1e27bc81423392ea83e9fc3a703e;p=tutoring-tool.git Implement HTTP table export --- diff --git a/main.py b/main.py index f091475..8c2c7d7 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,11 @@ from collections import defaultdict, namedtuple, OrderedDict from contextlib import contextmanager from enum import Enum +import http.server import itertools import json from matplotlib import pyplot +from threading import Thread import tkinter as tk from tkinter import ttk @@ -141,34 +143,25 @@ class MainModel(Model): self.view.set_student(name) -def get_table_bookmarklet(records): - import html - - rows = [ - ['' if v is None else str(v) for v in r] for r in records - ] - table_html = ( - '' - + '' - + ''.join('' for h in DataEditModel.Record.DISPLAY_NAMES) - + '' - + '' - + ''.join( - '' - + ''.join('' for v in row) - + '' - for row in rows - ) - + '' - + '
' + html.escape(h) + '
' + v + '
' - ) - assert "'" not in table_html - js_table_literal = "'{}'".format(table_html) - return ( - 'javascript:(function(){document.querySelector(\'[contenteditable=\\\'true\\\']\')' - + '.innerHTML+=\'
\'+' + js_table_literal + '+\'
\';})()' - ) +class AsyncHttpServer: + def __init__(self, port, data): + class Handler(http.server.BaseHTTPRequestHandler): + def __init__(self): pass + def __call__(self, *args): super().__init__(*args) + + def do_GET(self): + self.send_response(200) + self.send_header('Access-Control-Allow-Origin', '*') + self.end_headers() + self.wfile.write(data) + + self.server = http.server.HTTPServer(('localhost', port), Handler()) + + def start(self): + Thread(target = lambda: self.server.serve_forever()).start() + def stop(self): + self.server.shutdown() class MainView(View): @contextmanager @@ -274,17 +267,16 @@ class MainView(View): def on_gen_table(): name = self.controller.state['student'] - command = get_table_bookmarklet(self.controller.data[name]) - self.root.clipboard_clear() - self.root.clipboard_append(command) + rows = DataEditModel.Record.DISPLAY_NAMES + self.controller.data[name] + data = json.dumps(rows).encode('utf-8') + server = AsyncHttpServer(57853, data) + server.start() messagebox.showinfo( - "Table Command Copied", - "In Gmail, make sure you have a new message box open," - + " then paste the command into the address bar and press Enter." - + "\nMake sure \"javascript:\" shows up at the beginning of the address bar." - , + "Serving Table Data", + "Table data is ready to be transferred to your browser. You may close this dialog when the transfer is complete.", ) - self.gen_table_btn = ttk.Button(actions_frame, text = "Generate Gmail table", command = on_gen_table) + server.stop() + self.gen_table_btn = ttk.Button(actions_frame, text = "Export table", command = on_gen_table) self.student_sel.pack(**TK_PAD, side = tk.LEFT) add_student_btn.pack(**TK_PAD, side = tk.LEFT) diff --git a/table_bookmarklet b/table_bookmarklet new file mode 100644 index 0000000..fadfd81 --- /dev/null +++ b/table_bookmarklet @@ -0,0 +1 @@ +javascript:(function(){var r=new XMLHttpRequest();r.onReadyStateChange=d;function d(){if(r.readyState===XMLHttpRequest.DONE){var rows=JSON.parse(r.responseText);var t=document.createElement('table');var h=t.createTHead();rows.shift().forEach(v=>{var c=document.createElement('th');c.innerText=v;h.appendChild(c);});rows.forEach(r=>{var tr=t.insertRow(-1);r.forEach(v=>{var c=document.createElement('td');c.innerText=v;tr.appendChild(c);});});var box=document.querySelector('[contenteditable="true"]');box.appendChild(document.createElement('br'));box.appendChild(t);box.appendChild(document.createElement('br'));}}})()