feat(py-wasm): Attributes and Components module done.
This commit is contained in:
parent
f598ed3217
commit
8438243782
@ -33,6 +33,15 @@
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback python_wasm_preload_callback
|
||||
* @param {HTMLElement|null} item
|
||||
* @param {boolean} asynchronous
|
||||
* @param {number} error
|
||||
* @param {Array.<string>} error_messages
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @constructor
|
||||
@ -92,7 +101,9 @@ export const PythonWASM = (function(){
|
||||
/** @type {string} */
|
||||
gui_mode = PythonWASM.get_value("gui_mode", inputs, "default"),
|
||||
/** @type {number} */
|
||||
ajax_timeout = PythonWASM.get_value("ajax_timeout", inputs, 2000);
|
||||
ajax_timeout = PythonWASM.get_value(["ajax_timeout", "timeout"], inputs, 2000),
|
||||
/** @type {number} */
|
||||
preload_timeout = PythonWASM.get_value(["preload_timeout", "timeout"], inputs, 2000);
|
||||
|
||||
/** @type {PyodideAPI|null} */
|
||||
this.pyodide = null;
|
||||
@ -133,10 +144,22 @@ export const PythonWASM = (function(){
|
||||
null)).filter(file => file);
|
||||
|
||||
(async function(){
|
||||
|
||||
self._print("info", "Building the Pyodide module...");
|
||||
self.pyodide = await loadPyodide();
|
||||
self.pyodide.globals.set("load_file", self.load_file);
|
||||
self.pyodide.globals.set("synchronous_post", self.synchronous_post);
|
||||
|
||||
["load_file", "synchronous_post", "preload_html_item"].forEach(parameters => {
|
||||
|
||||
/** @type {[string|Array.<string>, string]} */
|
||||
const [names, key] = PythonWASM.is_array(parameters) ? parameters : [parameters, parameters];
|
||||
|
||||
PythonWASM.get_keys(names).forEach(name => {
|
||||
self._print("info", "Implementing the '{key}' action interface.", {key : name});
|
||||
self.pyodide.globals.set(name, self[key]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
self._print("info", "Loading the Python files...");
|
||||
self.pyodide.runPython(`
|
||||
from pyodide.http import pyfetch
|
||||
@ -149,6 +172,7 @@ export const PythonWASM = (function(){
|
||||
});
|
||||
PythonWASM.execute(callback, self);
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
};
|
||||
@ -319,12 +343,13 @@ export const PythonWASM = (function(){
|
||||
/**
|
||||
* @param {!string} url
|
||||
* @param {?python_wasm_ajax_callback} [callback = null]
|
||||
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||
* @param {!number} [options = 0]
|
||||
* @returns {XMLHttpRequest}
|
||||
* @access public
|
||||
*/
|
||||
this.load_file = (url, callback = null, options = 0) => {
|
||||
// console.log(url);
|
||||
this.load_file = (url, callback = null, inputs = null, options = 0) => {
|
||||
inputs = PythonWASM.get_default_inputs(inputs);
|
||||
|
||||
/** @type {boolean} */
|
||||
let ended = false;
|
||||
@ -332,23 +357,24 @@ export const PythonWASM = (function(){
|
||||
const ajax = new XMLHttpRequest(),
|
||||
/** @type {number} */
|
||||
date = Date.now(),
|
||||
/** @type {number} */
|
||||
timeout = PythonWASM.get_value(["ajax_timeout", "timeout"], inputs, ajax_timeout),
|
||||
/**
|
||||
* @param {!string} message
|
||||
* @returns {void}
|
||||
*/
|
||||
end = message => {
|
||||
// !ended && console.log([callback, ajax.responseText, ajax.status, ajax.readyState, message == "OK", message]);
|
||||
!ended && (ended = true) && PythonWASM.execute(callback, ajax.responseText, ajax.status, ajax.readyState, message == "OK", message);
|
||||
};
|
||||
|
||||
ajax.open("get", url, true);
|
||||
ajax.timeout = ajax_timeout;
|
||||
ajax.timeout = timeout;
|
||||
ajax.onreadystatechange = () => {
|
||||
if(ended)
|
||||
return;
|
||||
if(ajax.readyState == 4)
|
||||
end([301, 302, 304].includes(ajax.status) || (ajax.status >= 200 && ajax.status < 300) ? "OK" : "HTTP_ERROR");
|
||||
else if(Date.now() - date > ajax_timeout)
|
||||
else if(Date.now() - date > timeout)
|
||||
end("FORCED_TIMOUT");
|
||||
};
|
||||
ajax.send(null);
|
||||
@ -364,11 +390,13 @@ export const PythonWASM = (function(){
|
||||
* @param {!string} url
|
||||
* @param {?Object.<string, any|null>} [variables = null]
|
||||
* @param {?python_wasm_ajax_callback} [callback = null]
|
||||
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||
* @param {!number} [options = 0]
|
||||
* @returns {XMLHttpRequest}
|
||||
* @access public
|
||||
*/
|
||||
this.synchronous_post = (url, variables = null, callback = null, options = 0) => {
|
||||
this.synchronous_post = (url, variables = null, callback = null, inputs = null, options = 0) => {
|
||||
inputs = PythonWASM.get_default_inputs(inputs);
|
||||
|
||||
/** @type {boolean} */
|
||||
let ended = false,
|
||||
@ -378,6 +406,8 @@ export const PythonWASM = (function(){
|
||||
const ajax = new XMLHttpRequest(),
|
||||
/** @type {number} */
|
||||
date = Date.now(),
|
||||
/** @type {number} */
|
||||
timeout = PythonWASM.get_value(["ajax_timeout", "timeout"], inputs, ajax_timeout),
|
||||
/**
|
||||
* @param {!string} message
|
||||
* @returns {void}
|
||||
@ -391,14 +421,14 @@ export const PythonWASM = (function(){
|
||||
variables_uri += (variables_uri ? "&" : "") + encodeURIComponent(key) + "=" + encodeURIComponent(variables[key]);
|
||||
|
||||
ajax.open("get", url, true);
|
||||
ajax.timeout = ajax_timeout;
|
||||
ajax.timeout = timeout;
|
||||
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded;charset=UTF-8")
|
||||
ajax.onreadystatechange = () => {
|
||||
if(ended)
|
||||
return;
|
||||
if(ajax.readyState == 4)
|
||||
end([301, 302, 304].includes(ajax.status) || (ajax.status >= 200 && ajax.status < 300) ? "OK" : "HTTP_ERROR");
|
||||
else if(Date.now() - date > ajax_timeout)
|
||||
else if(Date.now() - date > timeout)
|
||||
end("FORCED_TIMOUT");
|
||||
};
|
||||
ajax.send(variables_uri);
|
||||
@ -410,6 +440,72 @@ export const PythonWASM = (function(){
|
||||
return ajax;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!(string|HTMLElement)} selector
|
||||
* @param {?python_wasm_preload_callback} [callback = null]
|
||||
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||
* @param {!number} [options = 0]
|
||||
* @returns {Array.<HTMLElement|null, number>}
|
||||
* @access public
|
||||
*/
|
||||
this.preload_html_item = (selector, callback = null, inputs = null, options = 0) => {
|
||||
inputs = PythonWASM.get_default_inputs(inputs);
|
||||
|
||||
/** @type {boolean} */
|
||||
let is_html_item = selector && (selector.tagName || selector.nodeName),
|
||||
/** @type {HTMLElement|null} */
|
||||
item = is_html_item ? selector : null,
|
||||
/** @type {number} */
|
||||
error = (
|
||||
((
|
||||
callback === undefined ? 1 << 0 :
|
||||
callback === null ? 1 << 1 :
|
||||
typeof callback != "function" ? 1 << 2 :
|
||||
0) << 0) |
|
||||
((
|
||||
selector === undefined ? 1 << 0 :
|
||||
selector === null ? 1 << 1 :
|
||||
typeof selector != "string" && !is_html_item ? 1 << 2 :
|
||||
0) << 3) |
|
||||
0) << 1,
|
||||
/** @type {boolean} */
|
||||
done = is_html_item;
|
||||
|
||||
if(!done && !error){
|
||||
|
||||
try{
|
||||
done = !!(item = document.querySelector(selector));
|
||||
}catch(exception){
|
||||
error |= 1 << 7;
|
||||
done = true;
|
||||
};
|
||||
|
||||
if(!done){
|
||||
|
||||
/** @type {number} */
|
||||
const date = Date.now(),
|
||||
/** @type {number} */
|
||||
timeout = Utils.get_value(["preload_timeout", "timeout"], inputs, preload_timeout),
|
||||
/** @type {number} */
|
||||
interval = setInterval(() => {
|
||||
if(item = document.querySelector(selector)){
|
||||
clearInterval(interval);
|
||||
PythonWASM.execute(callback, item, true, error, PythonWASM.PRELOAD_ITEM_HTML_ERROR_MESSAGES);
|
||||
}else if(Date.now() - date > timeout){
|
||||
clearInterval(interval);
|
||||
PythonWASM.execute(callback, item, true, error |= 1 << 8, PythonWASM.PRELOAD_ITEM_HTML_ERROR_MESSAGES)
|
||||
};
|
||||
}, 1000 / 24);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
done && PythonWASM.execute(callback, false, error, PythonWASM.PRELOAD_ITEM_HTML_ERROR_MESSAGES);
|
||||
|
||||
return error;
|
||||
};
|
||||
|
||||
constructor();
|
||||
|
||||
};
|
||||
@ -428,6 +524,7 @@ export const PythonWASM = (function(){
|
||||
["Modules/ErrorsManager.py", "https://errorsmanager." + PythonWASM.DOMAIN + "/py/ErrorsManager.py"],
|
||||
"/py/common.py",
|
||||
"/py/Abstracts/AnPMap.py",
|
||||
"/py/Abstracts/PyodideMap.py",
|
||||
"/py/Utils/Patterns.py",
|
||||
"/py/Utils/Options.py",
|
||||
"/py/Utils/Check.py",
|
||||
@ -446,9 +543,24 @@ export const PythonWASM = (function(){
|
||||
"/py/Managers/RandomKeys.py",
|
||||
"/py/Models/Thread.py",
|
||||
"/py/Managers/Threads.py",
|
||||
"/py/Application/Attributes.py",
|
||||
"/py/Application/Components.py",
|
||||
// "/py/run.py"
|
||||
];
|
||||
|
||||
/** @type {Array.<string>} */
|
||||
PythonWASM.PRELOAD_ITEM_HTML_ERROR_MESSAGES = [
|
||||
"exception",
|
||||
"callback_undefined",
|
||||
"callback_null",
|
||||
"callback_not_function",
|
||||
"selector_undefined",
|
||||
"selector_null",
|
||||
"selector_bad_type",
|
||||
"selector_bad_format",
|
||||
"timeout"
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {?any} item
|
||||
* @returns {boolean}
|
||||
@ -497,6 +609,22 @@ export const PythonWASM = (function(){
|
||||
*/
|
||||
PythonWASM.is_function = item => typeof item == "function";
|
||||
|
||||
/**
|
||||
* @param {?any} item
|
||||
* @returns {boolean}
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
PythonWASM.is_integer = item => typeof item == "number" && item >> 0 == item;
|
||||
|
||||
/**
|
||||
* @param {?any} item
|
||||
* @returns {boolean}
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
PythonWASM.is_json_item = item => PythonWASM.is_dictionary(item) || PythonWASM.is_array(item);
|
||||
|
||||
/**
|
||||
* @param {?any} item
|
||||
* @returns {Array.<any|null>}
|
||||
@ -712,7 +840,10 @@ export const PythonWASM = (function(){
|
||||
|
||||
{object_name}:AnP = AnP({
|
||||
"pyodide_javascript_interface_methods" : {
|
||||
"load_file" : load_file
|
||||
"load_file" : load_file,
|
||||
"post" : synchronous_post,
|
||||
"post_synchronous" : synchronous_post,
|
||||
"preload_html_item" : preload_html_item
|
||||
}
|
||||
})
|
||||
|
||||
@ -720,5 +851,16 @@ export const PythonWASM = (function(){
|
||||
object_name : "anp"
|
||||
}, inputs]);
|
||||
|
||||
/**
|
||||
* @param {?(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||
* @returns {Object.<string, any|null>|Array.<any|null>|null}
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
PythonWASM.get_default_inputs = inputs => (
|
||||
PythonWASM.is_integer(inputs) ? {timeout : inputs} :
|
||||
PythonWASM.is_json_item(inputs) ? inputs :
|
||||
null);
|
||||
|
||||
return PythonWASM;
|
||||
})();
|
@ -4,10 +4,47 @@
|
||||
from Modules.ErrorsManager import ErrorsManager
|
||||
from typing import Self, Optional, Any, Callable
|
||||
from Utils.Options import Options
|
||||
from re import Match as REMatch
|
||||
from typing import NewType
|
||||
from sys import platform as SYS_PLATFORM
|
||||
|
||||
AnP = NewType("AnP", Any)
|
||||
|
||||
is_emcripten:bool = SYS_PLATFORM == "emscripten"
|
||||
|
||||
if is_emcripten:
|
||||
|
||||
class ClassList:
|
||||
|
||||
def contains(self:Self, kebab:str) -> bool:pass
|
||||
|
||||
def add(self:Self, kebab:str) -> None:pass
|
||||
|
||||
def remove(self:Self, kebab:str) -> None:pass
|
||||
|
||||
class Style:pass
|
||||
|
||||
class DOM:
|
||||
|
||||
def querySelector(selector:str) -> Self|None:pass
|
||||
|
||||
def querySelectorAll(selector:str) -> list[Self]:pass
|
||||
|
||||
def remove() -> None:pass
|
||||
|
||||
def hasAttribute(name:str) -> bool:pass
|
||||
|
||||
def getAttribute(name:str) -> str:pass
|
||||
|
||||
def setAttribute(name:str, value:Any|None) -> None:pass
|
||||
|
||||
class HTMLElement(DOM, Style):
|
||||
|
||||
def __init__(self):
|
||||
self.style:Style = None
|
||||
|
||||
class HTMLBodyElement(HTMLElement):pass
|
||||
|
||||
class BaseAbstract:
|
||||
|
||||
def __init__(self:Self, anp:AnP, key:str, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None) -> None:
|
||||
@ -34,18 +71,22 @@ class BaseAbstract:
|
||||
|
||||
def is_started(self:Self) -> bool:pass
|
||||
|
||||
class PyodideJavaScriptInterface(BaseAbstract):
|
||||
if is_emcripten:
|
||||
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:
|
||||
self.load_file:Callable[[str, Callable[[str|None, int, int, bool, str], str|None], int], tuple[str|None, int, bool, int]] = None
|
||||
self.post:Callable[[str, Callable[[str|None, int, int, bool, str], str|None], int], tuple[str|None, int, bool, int]] = None
|
||||
self.instances_threads:Callable[[int], bool] = None
|
||||
class PyodideJavaScriptInterface(BaseAbstract):
|
||||
|
||||
def _set_basics(self:Self, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None):pass
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:
|
||||
self.load_file:Callable[[str, Optional[Callable[[str|None, int, int, bool, str], str|None]], Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]], int], tuple[str|None, int, bool, int]] = None
|
||||
self.post:Callable[[str, dict[str|Any|None]|str, Optional[Callable[[str|None, int, int, bool, str], str|None]], Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]], int], tuple[str|None, int, bool, int]] = None
|
||||
self.post_synchronous:Callable[[str, dict[str|Any|None]|str, Optional[Callable[[str|None, int, int, bool, str], str|None]], Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]], int], tuple[str|None, int, bool, int]] = None
|
||||
self.preload_html_item:Callable[[str|HTMLElement, Optional[Callable[[HTMLElement|None, bool, int, list[str]], None]], int], tuple[HTMLElement|None, bool, int, list[str]]] = None
|
||||
self.instances_threads:Callable[[int], bool] = None
|
||||
|
||||
def _build(self:Self, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:pass
|
||||
def _set_basics(self:Self, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None):pass
|
||||
|
||||
def add(self:Self, inputs:dict[str, Callable[[tuple[Any|None]], Any|None]]|list[Any|None]|tuple[Any|None], options:int = 0) -> int:pass
|
||||
def _build(self:Self, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:pass
|
||||
|
||||
def add(self:Self, inputs:dict[str, Callable[[tuple[Any|None]], Any|None]]|list[Any|None]|tuple[Any|None], options:int = 0) -> int:pass
|
||||
|
||||
class Console:
|
||||
|
||||
@ -130,7 +171,7 @@ class JSONLoader:
|
||||
end_callback:Optional[Callable[[], None]] = None,
|
||||
only_dictionaries:bool = False,
|
||||
options:int = 0
|
||||
) -> None:
|
||||
):
|
||||
self.anp:AnP = None
|
||||
self.has:Options = None
|
||||
self.has_console:bool = None
|
||||
@ -364,6 +405,79 @@ class TerminalManager(BaseAbstract):
|
||||
|
||||
def _close_command(self:Self, dictionary:dict[str, Any|None], *arguments:list[Any|None]) -> None:pass
|
||||
|
||||
class CommonAttributes(BaseAbstract):
|
||||
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|tuple[Any|None]] = None) -> None:
|
||||
self.standard_names:list[str] = None
|
||||
|
||||
@staticmethod
|
||||
def set_names_block(names:str|list[str]|tuple[str]|None) -> list[str]|None:pass
|
||||
|
||||
@staticmethod
|
||||
def check(name:str, exclude:list[str]|tuple[str]|None, only:Optional[list[str]|tuple[str]] = None) -> bool:pass
|
||||
|
||||
@staticmethod
|
||||
def set_match_group(matches:REMatch) -> str:pass
|
||||
|
||||
def name_format(self:Self, name:str) -> str:pass
|
||||
|
||||
def set_string(self:Self,
|
||||
attributes:dict[str, Any|None],
|
||||
exclude:Optional[str|list[str]|tuple[str]] = None,
|
||||
only:Optional[str|list[str]|tuple[str]] = None
|
||||
) -> str:pass
|
||||
|
||||
if is_emcripten:
|
||||
|
||||
class BaseAttributes(CommonAttributes):
|
||||
|
||||
def set(self:Self,
|
||||
item:HTMLElement|None,
|
||||
attributes:dict[str, Any|None],
|
||||
exclude:Optional[str|list[str]|tuple[str]] = None,
|
||||
only:Optional[str|list[str]|tuple[str]] = None
|
||||
) -> str|None:pass
|
||||
|
||||
else:
|
||||
|
||||
class BaseAttributes(CommonAttributes):
|
||||
|
||||
def set(self:Self,
|
||||
_:Any|None,
|
||||
attributes:dict[str, Any|None],
|
||||
exclude:Optional[str|list[str]|tuple[str]] = None,
|
||||
only:Optional[str|list[str]|tuple[str]] = None
|
||||
) -> str|None:pass
|
||||
|
||||
class Attributes(BaseAttributes):pass
|
||||
|
||||
if is_emcripten:
|
||||
|
||||
class BaseComponents(BaseAbstract):
|
||||
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:pass
|
||||
|
||||
def preload(self:Self,
|
||||
selector:HTMLElement|None,
|
||||
callback:Optional[Callable[[HTMLElement|None, bool, int, list[str]], None]] = None,
|
||||
inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None,
|
||||
options:int = 0
|
||||
) -> tuple[HTMLElement|None, bool, int, list[str]]:pass
|
||||
|
||||
else:
|
||||
|
||||
class BaseComponents(BaseAbstract):
|
||||
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:pass
|
||||
|
||||
class Components(BaseComponents):
|
||||
|
||||
def set(self:Self, items:list[Any|None]|tuple[Any|None]) -> str:pass
|
||||
|
||||
def i18n(self:Self, i18n:str, tag:str = "span", inputs:Optional[str|dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> str:pass
|
||||
|
||||
def icon(self:Self, icon:str, tag:str = "span", inputs:Optional[str|dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> str:pass
|
||||
|
||||
class AnP:
|
||||
|
||||
def __init__(self:Self, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None) -> None:
|
||||
@ -376,6 +490,8 @@ class AnP:
|
||||
self.i18n:I18NManager = None
|
||||
self.random_keys:RandomKeysManager = None
|
||||
self.threads:ThreadsManager = None
|
||||
self.attributes:Attributes = None
|
||||
self.components:Components = None
|
||||
self.terminal:TerminalManager = None
|
||||
|
||||
def set_subbasics(self:Self, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None]] = None) -> None:pass
|
||||
|
35
Public/py/Abstracts/PyodideMap.py
Normal file
35
Public/py/Abstracts/PyodideMap.py
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from common import Self, Any
|
||||
|
||||
class ClassList:
|
||||
|
||||
def contains(self:Self, kebab:str) -> bool:None
|
||||
|
||||
def add(self:Self, kebab:str) -> None:None
|
||||
|
||||
def remove(self:Self, kebab:str) -> None:None
|
||||
|
||||
class Style:pass
|
||||
|
||||
class DOM:
|
||||
|
||||
def querySelector(selector:str) -> Self|None:pass
|
||||
|
||||
def querySelectorAll(selector:str) -> list[Self]:pass
|
||||
|
||||
def remove() -> None:pass
|
||||
|
||||
def hasAttribute(name:str) -> bool:pass
|
||||
|
||||
def getAttribute(name:str) -> str:pass
|
||||
|
||||
def setAttribute(name:str, value:Any|None) -> None:pass
|
||||
|
||||
class HTMLElement(DOM, Style):
|
||||
|
||||
def __init__(self:Self) -> None:
|
||||
self.style:Style = None
|
||||
|
||||
class HTMLBodyElement(HTMLElement):pass
|
@ -13,6 +13,8 @@ from Managers.Settings import SettingsManager
|
||||
from Managers.I18N import I18NManager
|
||||
from Managers.RandomKeys import RandomKeysManager
|
||||
from Managers.Threads import ThreadsManager
|
||||
from Application.Attributes import Attributes
|
||||
from Application.Components import Components
|
||||
from Utils.Check import Check
|
||||
|
||||
if not Check.is_emscripten():
|
||||
@ -71,6 +73,8 @@ class AnP:
|
||||
self.i18n:I18NManager = I18NManager(self, inputs)
|
||||
self.random_keys:RandomKeysManager = RandomKeysManager(self, inputs)
|
||||
self.threads:ThreadsManager = ThreadsManager(self, inputs)
|
||||
self.attributes:Attributes = Attributes(self, inputs)
|
||||
self.components:Components = Components(self, inputs)
|
||||
if not is_emscripten:
|
||||
self.terminal:TerminalManager = TerminalManager(self, inputs)
|
||||
|
||||
@ -127,7 +131,8 @@ class AnP:
|
||||
try:
|
||||
Utils.execute_asynchronous((
|
||||
("console", "json", "pyodide", "request", "settings", "i18n", "random_keys", "threads") +
|
||||
(tuple() if is_emscripten else ("terminal",))
|
||||
(tuple() if is_emscripten else ("terminal",)) +
|
||||
("attributes", "components")
|
||||
), self.__start_module, lambda:Utils.execute(callback, True))
|
||||
except Exception as exception:
|
||||
self.__error |= 1 << 1
|
||||
@ -168,6 +173,7 @@ class AnP:
|
||||
|
||||
try:
|
||||
Utils.execute_asynchronous((
|
||||
("components", "attributes") +
|
||||
(tuple() if is_emscripten else ("terminal",)) +
|
||||
("i18n", "settings", "request", "pyodide", "json", "console")
|
||||
), self.__close_module, lambda:Utils.execute(callback, True))
|
||||
|
107
Public/py/Application/Attributes.py
Normal file
107
Public/py/Application/Attributes.py
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Abstracts.Base import BaseAbstract
|
||||
from Abstracts.AnPMap import AnP
|
||||
from common import Self, Optional, Any, REMatch
|
||||
from Utils.Check import Check
|
||||
from Utils.Utils import Utils
|
||||
from Utils.Patterns import Patterns
|
||||
|
||||
class CommonAttributes(BaseAbstract):
|
||||
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|tuple[Any|None]] = None) -> None:
|
||||
super().__init__(anp, "attributes", inputs)
|
||||
|
||||
self.standard_names:list[str] = []
|
||||
|
||||
@staticmethod
|
||||
def set_names_block(names:str|list[str]|tuple[str]|None) -> list[str]|None:
|
||||
|
||||
array:list[str] = Utils.get_selector_keys(names)
|
||||
|
||||
return array if len(array) else None
|
||||
|
||||
@staticmethod
|
||||
def check(name:str, exclude:list[str]|tuple[str]|None, only:Optional[list[str]|tuple[str]] = None) -> bool:
|
||||
return (not exclude or name not in exclude) and (not only or name in only)
|
||||
|
||||
@staticmethod
|
||||
def set_match_group(matches:REMatch) -> str:
|
||||
return "-" + (str(matches.group(1)).lower() if matches.group(1) else "")
|
||||
|
||||
def name_format(self:Self, name:str) -> str:
|
||||
|
||||
name = Patterns.RE_TO_KEBAB.sub(name, CommonAttributes.set_match_group)
|
||||
|
||||
return name if name in self.standard_names or name[:5] in ("data-", "aria-") else "data-" + name
|
||||
|
||||
def set_string(self:Self,
|
||||
attributes:dict[str, Any|None],
|
||||
exclude:Optional[str|list[str]|tuple[str]] = None,
|
||||
only:Optional[str|list[str]|tuple[str]] = None
|
||||
) -> str:
|
||||
|
||||
styles:str = ""
|
||||
|
||||
exclude = CommonAttributes.set_names_block(exclude)
|
||||
only = CommonAttributes.set_names_block(only)
|
||||
|
||||
for name, value in Utils.get_dictionary(attributes).items():
|
||||
if CommonAttributes.check(name):
|
||||
styles += " " + self.name_format(name) + "=\"" + value + "\""
|
||||
|
||||
return styles
|
||||
|
||||
if Check.is_emscripten():
|
||||
from Abstracts.PyodideMap import HTMLElement
|
||||
|
||||
class BaseAttributes(CommonAttributes):
|
||||
|
||||
def set(self:Self,
|
||||
item:HTMLElement|None,
|
||||
attributes:dict[str, Any|None],
|
||||
exclude:Optional[str|list[str]|tuple[str]] = None,
|
||||
only:Optional[str|list[str]|tuple[str]] = None
|
||||
) -> str|None:
|
||||
|
||||
styles:str|None = None
|
||||
|
||||
if Check.is_json_item(item):
|
||||
(item, attributes, exclude, only) = (None, item, attributes, exclude)
|
||||
|
||||
if item:
|
||||
|
||||
name:str
|
||||
value:Any|None
|
||||
|
||||
exclude = CommonAttributes.set_names_block(exclude)
|
||||
only = CommonAttributes.set_names_block(only)
|
||||
|
||||
for name, value in Utils.get_dictionary(attributes).items():
|
||||
CommonAttributes.check(name) and item.setAttribute(self.name_format(name), value)
|
||||
|
||||
else:
|
||||
styles = self.set_string(attributes, exclude, only)
|
||||
|
||||
return styles
|
||||
|
||||
else:
|
||||
|
||||
class BaseAttributes(CommonAttributes):
|
||||
|
||||
def set(self:Self,
|
||||
_:Any|None,
|
||||
attributes:dict[str, Any|None],
|
||||
exclude:Optional[str|list[str]|tuple[str]] = None,
|
||||
only:Optional[str|list[str]|tuple[str]] = None
|
||||
) -> str|None:
|
||||
|
||||
if Check.is_dictionary(_):
|
||||
(_, attributes, exclude, only) = (None, _, attributes, exclude)
|
||||
|
||||
return self.set_string(attributes, exclude, only)
|
||||
|
||||
|
||||
class Attributes(BaseAttributes):
|
||||
pass
|
78
Public/py/Application/Components.py
Normal file
78
Public/py/Application/Components.py
Normal file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Abstracts.Base import BaseAbstract
|
||||
from Abstracts.AnPMap import AnP
|
||||
from common import Self, Optional, Any, Callable
|
||||
from Utils.Check import Check
|
||||
from Utils.Utils import Utils
|
||||
|
||||
if Check.is_emscripten():
|
||||
|
||||
from Abstracts.PyodideMap import HTMLElement
|
||||
from js import document
|
||||
|
||||
class BaseComponents(BaseAbstract):
|
||||
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:
|
||||
super().__init__(anp, "components", inputs)
|
||||
|
||||
def preload(self:Self,
|
||||
selector:HTMLElement|None,
|
||||
callback:Optional[Callable[[HTMLElement|None, bool, int, list[str]], None]] = None,
|
||||
inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None,
|
||||
options:int = 0
|
||||
) -> tuple[HTMLElement|None, bool, int, list[str]]:
|
||||
return self.anp.pyodide.preload_html_item(selector, callback, inputs, options)
|
||||
|
||||
else:
|
||||
|
||||
class BaseComponents(BaseAbstract):
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:
|
||||
super().__init__(anp, "components", inputs)
|
||||
|
||||
class Components(BaseComponents):
|
||||
|
||||
def set(self:Self, items:list[Any|None]|tuple[Any|None]) -> str:
|
||||
|
||||
html:str = ''
|
||||
|
||||
if Check.is_array(items):
|
||||
for item in items:
|
||||
item = Utils.get_array(item)
|
||||
|
||||
l:int = len(item)
|
||||
|
||||
if l == 1 and Check.is_array(item[0]):
|
||||
if len(item[0]) and Check.is_string(item[0][0]) and hasattr(self.anp.components, item[0][0]):
|
||||
|
||||
method:Callable[[list[Any|None]], str] = getattr(self.anp.components, item[0][0])
|
||||
|
||||
if callable(method):
|
||||
html += method(*item[0][1:])
|
||||
|
||||
else:
|
||||
|
||||
tag:str = item[0]
|
||||
attributes:dict[str, Any|None]|tuple[Any|None]|list[Any|None]|None = item[1] if l > 1 else None
|
||||
childs:list[Any|None]|tuple[Any|None]|None = item[2] if l > 2 else None
|
||||
|
||||
html += '<' + tag + self.anp.attributes.set(attributes) + '>' + self.set(childs) + '</' + tag + '>'
|
||||
|
||||
elif Check.is_string(items):
|
||||
html += items
|
||||
|
||||
return html
|
||||
|
||||
def i18n(self:Self, i18n:str, tag:str = "span", inputs:Optional[str|dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> str:
|
||||
|
||||
text:str = self.anp.i18n.get(i18n)
|
||||
|
||||
return self.set([[tag, (inputs, {
|
||||
"i18n" : i18n
|
||||
}), text]])
|
||||
|
||||
def icon(self:Self, icon:str, tag:str = "span", inputs:Optional[str|dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> str:
|
||||
return self.set([[tag, (inputs, {
|
||||
"icon" : icon
|
||||
})]])
|
@ -2,6 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Abstracts.Base import BaseAbstract
|
||||
from Abstracts.PyodideMap import HTMLElement
|
||||
from Abstracts.AnPMap import AnP
|
||||
from common import Self, Any, Callable, Optional
|
||||
from Utils.Options import Options
|
||||
@ -27,7 +28,7 @@ class PyodideJavaScriptInterface(BaseAbstract):
|
||||
"default_pyodide_javascript_interface_methods", "default_javascript_interface_methods",
|
||||
"pyodide_javascript_interface_methods", "javascript_interface_methods"
|
||||
):
|
||||
self.add(get(key, inputs)[0])
|
||||
self.add(get(key, inputs)[0], Options.OVERWRITE)
|
||||
|
||||
def _build(self:Self, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:
|
||||
|
||||
@ -40,8 +41,10 @@ class PyodideJavaScriptInterface(BaseAbstract):
|
||||
self.__show_add_error:bool = True
|
||||
self.__show_add_ok:bool = False
|
||||
|
||||
self.load_file:Callable[[str, Callable[[str|None, int, int, bool, str], str|None], int], tuple[str|None, int, bool, int]] = None
|
||||
self.post:Callable[[str, Callable[[str|None, int, int, bool, str], str|None], int], tuple[str|None, int, bool, int]] = None
|
||||
self.load_file:Callable[[str, Optional[Callable[[str|None, int, int, bool, str], str|None]], Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]], int], tuple[str|None, int, bool, int]] = None
|
||||
self.post:Callable[[str, dict[str|Any|None]|str, Optional[Callable[[str|None, int, int, bool, str], str|None]], Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]], int], tuple[str|None, int, bool, int]] = None
|
||||
self.post_synchronous:Callable[[str, dict[str|Any|None]|str, Optional[Callable[[str|None, int, int, bool, str], str|None]], Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]], int], tuple[str|None, int, bool, int]] = None
|
||||
self.preload_html_item:Callable[[str|HTMLElement, Optional[Callable[[HTMLElement|None, bool, int, list[str]], None]], int], tuple[HTMLElement|None, bool, int, list[str]]] = None
|
||||
self.instances_threads:Callable[[int], bool] = None
|
||||
|
||||
def __init__(self:Self, anp:AnP, inputs:Optional[dict[str, Any|None]|tuple[Any|None]|list[Any|None]] = None) -> None:
|
||||
|
@ -5,6 +5,7 @@ from common import REPattern, re_compile, RE_IGNORE_CASE
|
||||
|
||||
class Patterns:
|
||||
RE_KEY:REPattern = re_compile(r'^[a-z0-9_]+$', RE_IGNORE_CASE)
|
||||
RE_SELECTOR_KEY:REPattern = re_compile(r'^[a-z0-9_\-]+$', RE_IGNORE_CASE)
|
||||
RE_STRING_VARIABLES:REPattern = re_compile(r'\{([a-z0-9_]+)\}', RE_IGNORE_CASE)
|
||||
RE_COLOR_HEXADECIMAL:REPattern = re_compile(r'^\#([0-9a-f]{3}|([0-9a-f]{2}){3,4})$', RE_IGNORE_CASE)
|
||||
RE_COLOR_RGB:REPattern = re_compile(r'^rgba?\((' +
|
||||
@ -22,3 +23,4 @@ class Patterns:
|
||||
RE_COMMAND_AND_PARAMETERS:REPattern = re_compile(r'^\s*([^\s]+)(\s+(.*))?$')
|
||||
RE_COMMAND_PARAMETER:REPattern = re_compile(r'((\-{,2})([a-z0-9_]+)\s*[\=\:]\s*("(([^\\\\"]+|\\.)*)"|\'(([^\\\\\']+|\\.)*)\'|([^\s]*)))|"(([^\\\\"]+|\\.)*)"|\'(([^\\\\\']+|\\.)*)\'|([^\s]+)', RE_IGNORE_CASE)
|
||||
RE_SLASH_ESCAPE:REPattern = re_compile(r'\\(.)')
|
||||
RE_TO_KEBAB:REPattern = re_compile('([A-Z0-9]([A-Z0-9]*|[a-z0-9]*))|[^a-zA-Z0-9]+')
|
@ -215,5 +215,10 @@ class Utils:
|
||||
|
||||
return alphabet
|
||||
|
||||
@staticmethod
|
||||
def get_random_item(items:list[Any|None]|tuple[Any|None]) -> Any|None:
|
||||
return get_random_item(items)
|
||||
|
||||
@staticmethod
|
||||
def get_selector_keys(keys:Any|None) -> list[str]:
|
||||
return [key for key in Utils.get_array(keys) if key and Check.is_string(key) and Patterns.RE_SELECTOR_KEY.match(key)]
|
Loading…
Reference in New Issue
Block a user