Add checkId() for PyButton and PyInputBox, add id check for tags with pys- Event handlers (#400)

* Add id generation to PyButton and PyInputBox components

* Refactor init handlers and add check for id
This commit is contained in:
Yannick Funk
2022-05-16 23:05:11 +02:00
committed by GitHub
parent ca909b4f6b
commit eba42ad9b4
3 changed files with 28 additions and 13 deletions

View File

@@ -37,6 +37,7 @@ export class PyButton extends BaseEvalElement {
} }
connectedCallback() { connectedCallback() {
this.checkId();
this.code = htmlDecode(this.innerHTML); this.code = htmlDecode(this.innerHTML);
this.mount_name = this.id.split('-').join('_'); this.mount_name = this.id.split('-').join('_');
this.innerHTML = ''; this.innerHTML = '';

View File

@@ -17,6 +17,7 @@ export class PyInputBox extends BaseEvalElement {
} }
connectedCallback() { connectedCallback() {
this.checkId();
this.code = htmlDecode(this.innerHTML); this.code = htmlDecode(this.innerHTML);
this.mount_name = this.id.split('-').join('_'); this.mount_name = this.id.split('-').join('_');
this.innerHTML = ''; this.innerHTML = '';

View File

@@ -127,17 +127,36 @@ export class PyScript extends BaseEvalElement {
} }
} }
/** Initialize all elements with py-onClick handlers attributes */ /** Defines all possible pys-on* and their corresponding event types */
const pysAttributeToEvent: Map<string, string> = new Map<string, string>([
["pys-onClick", "click"],
["pys-onKeyDown", "keydown"]
]);
/** Initialize all elements with pys-on* handlers attributes */
async function initHandlers() { async function initHandlers() {
console.log('Collecting nodes...'); console.log('Collecting nodes...');
const pyodide = await pyodideReadyPromise; const pyodide = await pyodideReadyPromise;
let matches: NodeListOf<HTMLElement> = document.querySelectorAll('[pys-onClick]'); for (const pysAttribute of pysAttributeToEvent.keys()) {
let output; await createElementsWithEventListeners(pyodide, pysAttribute);
let source; }
}
/** Initializes an element with the given pys-on* attribute and its handler */
async function createElementsWithEventListeners(pyodide: any, pysAttribute: string) {
const matches: NodeListOf<HTMLElement> = document.querySelectorAll(`[${pysAttribute}]`);
for (const el of matches) { for (const el of matches) {
const handlerCode = el.getAttribute('pys-onClick'); if (el.id.length === 0) {
source = `Element("${el.id}").element.onclick = ${handlerCode}`; throw new TypeError(`<${el.tagName.toLowerCase()}> must have an id attribute, when using the ${pysAttribute} attribute`)
output = await pyodide.runPythonAsync(source); }
const handlerCode = el.getAttribute(pysAttribute);
const event = pysAttributeToEvent.get(pysAttribute);
const source = `
from pyodide import create_proxy
Element("${el.id}").element.addEventListener("${event}", create_proxy(${handlerCode}))
`;
await pyodide.runPythonAsync(source);
// TODO: Should we actually map handlers in JS instead of Python? // TODO: Should we actually map handlers in JS instead of Python?
// el.onclick = (evt: any) => { // el.onclick = (evt: any) => {
@@ -154,12 +173,6 @@ async function initHandlers() {
// } // }
} }
matches = document.querySelectorAll('[pys-onKeyDown]');
for (const el of matches) {
const handlerCode = el.getAttribute('pys-onKeyDown');
source = `Element("${el.id}").element.addEventListener("keydown", ${handlerCode})`;
output = await pyodide.runPythonAsync(source);
}
} }
/** Mount all elements with attribute py-mount into the Python namespace */ /** Mount all elements with attribute py-mount into the Python namespace */