@pyscript/core 0.7.17 → 0.7.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core-Bjp0SMKu.js +4 -0
- package/dist/core-Bjp0SMKu.js.map +1 -0
- package/dist/core.js +1 -1
- package/dist/{deprecations-manager-CNkhZguT.js → deprecations-manager-D9xq2ZDO.js} +2 -2
- package/dist/{deprecations-manager-CNkhZguT.js.map → deprecations-manager-D9xq2ZDO.js.map} +1 -1
- package/dist/{donkey-BrYzh4xv.js → donkey-CMXMK7T1.js} +2 -2
- package/dist/{donkey-BrYzh4xv.js.map → donkey-CMXMK7T1.js.map} +1 -1
- package/dist/{error-DyXnDQD6.js → error-DPKYB3DP.js} +2 -2
- package/dist/{error-DyXnDQD6.js.map → error-DPKYB3DP.js.map} +1 -1
- package/dist/{mpy-CFGtXz07.js → mpy-B5jAqLMe.js} +2 -2
- package/dist/{mpy-CFGtXz07.js.map → mpy-B5jAqLMe.js.map} +1 -1
- package/dist/{py-2phVPCOx.js → py-B8CNrnyx.js} +2 -2
- package/dist/{py-2phVPCOx.js.map → py-B8CNrnyx.js.map} +1 -1
- package/dist/{py-editor-BEXl536W.js → py-editor-xN1N9yI9.js} +2 -2
- package/dist/{py-editor-BEXl536W.js.map → py-editor-xN1N9yI9.js.map} +1 -1
- package/dist/{py-game-2rFAfqnI.js → py-game-C3wCOsJw.js} +2 -2
- package/dist/{py-game-2rFAfqnI.js.map → py-game-C3wCOsJw.js.map} +1 -1
- package/dist/{py-terminal-C30BBFzh.js → py-terminal-CdFh6UPZ.js} +2 -2
- package/dist/{py-terminal-C30BBFzh.js.map → py-terminal-CdFh6UPZ.js.map} +1 -1
- package/package.json +2 -2
- package/src/stdlib/pyscript/web.py +36 -14
- package/src/stdlib/pyscript/workers.py +1 -0
- package/src/stdlib/pyscript.js +1 -1
- package/dist/core-CzWfmqHV.js +0 -4
- package/dist/core-CzWfmqHV.js.map +0 -1
|
@@ -201,7 +201,8 @@ document and provides access to common elements like `page.body` and methods
|
|
|
201
201
|
like `page.find()` for querying the DOM.
|
|
202
202
|
"""
|
|
203
203
|
|
|
204
|
-
from
|
|
204
|
+
from js import console
|
|
205
|
+
from pyscript import document, Event # noqa: F401
|
|
205
206
|
from pyscript.ffi import create_proxy, is_none
|
|
206
207
|
|
|
207
208
|
|
|
@@ -642,7 +643,7 @@ class Element:
|
|
|
642
643
|
Append items to this element's `children`.
|
|
643
644
|
|
|
644
645
|
Accepts `Element` instances, `ElementCollection` instances, lists,
|
|
645
|
-
tuples, raw DOM elements, and
|
|
646
|
+
tuples, raw DOM elements, NodeLists, str, int, float, and bool.
|
|
646
647
|
"""
|
|
647
648
|
for item in items:
|
|
648
649
|
if isinstance(item, Element):
|
|
@@ -660,6 +661,8 @@ class Element:
|
|
|
660
661
|
# NodeList or similar iterable.
|
|
661
662
|
for element in item:
|
|
662
663
|
self._dom_element.appendChild(element)
|
|
664
|
+
elif isinstance(item, (str, int, float, bool)):
|
|
665
|
+
self._dom_element.append(item)
|
|
663
666
|
else:
|
|
664
667
|
raise TypeError(f"Cannot append {type(item).__name__} to element.")
|
|
665
668
|
|
|
@@ -717,13 +720,15 @@ class Element:
|
|
|
717
720
|
|
|
718
721
|
class Classes(set):
|
|
719
722
|
"""
|
|
723
|
+
Manages CSS classes for an element.
|
|
724
|
+
|
|
720
725
|
Behaves like a Python `set` with changes automatically reflected in the
|
|
721
726
|
element's `classList`.
|
|
722
727
|
|
|
723
728
|
```python
|
|
724
729
|
# Add and remove classes.
|
|
725
730
|
element.classes.add("active")
|
|
726
|
-
element.classes.remove("inactive")
|
|
731
|
+
element.classes.remove("inactive") # Warns if not present.
|
|
727
732
|
element.classes.discard("maybe-missing") # No error if absent.
|
|
728
733
|
|
|
729
734
|
# Check membership.
|
|
@@ -740,7 +745,9 @@ class Classes(set):
|
|
|
740
745
|
"""
|
|
741
746
|
|
|
742
747
|
def __init__(self, element):
|
|
743
|
-
"""
|
|
748
|
+
"""
|
|
749
|
+
Initialise the CSS Classes set for the given element.
|
|
750
|
+
"""
|
|
744
751
|
self._class_list = element._dom_element.classList
|
|
745
752
|
super().__init__(self._class_list)
|
|
746
753
|
|
|
@@ -757,26 +764,40 @@ class Classes(set):
|
|
|
757
764
|
)
|
|
758
765
|
|
|
759
766
|
def add(self, class_name):
|
|
760
|
-
"""
|
|
767
|
+
"""
|
|
768
|
+
Add a CSS class.
|
|
769
|
+
"""
|
|
761
770
|
for name in self._extract_class_names(class_name):
|
|
762
771
|
super().add(name)
|
|
763
772
|
self._class_list.add(name)
|
|
764
773
|
|
|
765
774
|
def remove(self, class_name):
|
|
766
|
-
"""
|
|
775
|
+
"""
|
|
776
|
+
Remove a CSS class.
|
|
777
|
+
|
|
778
|
+
Will log a warning if the class is not present, but will not raise an
|
|
779
|
+
error.
|
|
780
|
+
"""
|
|
767
781
|
for name in self._extract_class_names(class_name):
|
|
768
|
-
|
|
769
|
-
|
|
782
|
+
if name in self:
|
|
783
|
+
super().remove(name)
|
|
784
|
+
self._class_list.remove(name)
|
|
785
|
+
else:
|
|
786
|
+
console.warn(f"Class '{name}' not found in element classes.")
|
|
770
787
|
|
|
771
788
|
def discard(self, class_name):
|
|
772
|
-
"""
|
|
789
|
+
"""
|
|
790
|
+
Remove a CSS class if present.
|
|
791
|
+
"""
|
|
773
792
|
for name in self._extract_class_names(class_name):
|
|
774
793
|
super().discard(name)
|
|
775
794
|
if name in self._class_list:
|
|
776
795
|
self._class_list.remove(name)
|
|
777
796
|
|
|
778
797
|
def clear(self):
|
|
779
|
-
"""
|
|
798
|
+
"""
|
|
799
|
+
Remove all CSS classes.
|
|
800
|
+
"""
|
|
780
801
|
super().clear()
|
|
781
802
|
while self._class_list.length > 0:
|
|
782
803
|
self._class_list.remove(self._class_list.item(0))
|
|
@@ -1138,18 +1159,19 @@ class ElementCollection:
|
|
|
1138
1159
|
elements.extend(_find_and_wrap(element._dom_element, selector))
|
|
1139
1160
|
return ElementCollection(elements)
|
|
1140
1161
|
|
|
1141
|
-
def update_all(self, **kwargs):
|
|
1162
|
+
def update_all(self, classes=None, style=None, **kwargs):
|
|
1142
1163
|
"""
|
|
1143
|
-
Explicitly update all elements with the given
|
|
1164
|
+
Explicitly update all elements with the given `classes`, `style`, and
|
|
1165
|
+
`attributes`. Delegates to each element's `update` method.
|
|
1144
1166
|
|
|
1145
1167
|
```python
|
|
1146
1168
|
collection.update_all(innerHTML="Hello")
|
|
1169
|
+
collection.update_all(classes="active", style={"color": "red"})
|
|
1147
1170
|
collection.update_all(className="active", title="Updated")
|
|
1148
1171
|
```
|
|
1149
1172
|
"""
|
|
1150
1173
|
for element in self._elements:
|
|
1151
|
-
|
|
1152
|
-
setattr(element, name, value)
|
|
1174
|
+
element.update(classes=classes, style=style, **kwargs)
|
|
1153
1175
|
|
|
1154
1176
|
|
|
1155
1177
|
# Special elements with custom methods and mixins.
|
package/src/stdlib/pyscript.js
CHANGED
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
"media.py": "from pyscript import window\nfrom pyscript.ffi import to_js\nclass Device:\n\tdef __init__(A,device):A._device_info=device\n\t@property\n\tdef id(self):return self._device_info.deviceId\n\t@property\n\tdef group(self):return self._device_info.groupId\n\t@property\n\tdef kind(self):return self._device_info.kind\n\t@property\n\tdef label(self):return self._device_info.label\n\tdef __getitem__(A,key):return getattr(A,key)\n\t@classmethod\n\tasync def request_stream(F,audio=False,video=True):\n\t\tE='video';D='audio';C=video;B=audio;A={}\n\t\tif isinstance(B,bool):A[D]=B\n\t\telif isinstance(B,dict):A[D]=B\n\t\tif isinstance(C,bool):A[E]=C\n\t\telif isinstance(C,dict):A[E]=C\n\t\treturn await window.navigator.mediaDevices.getUserMedia(to_js(A))\n\t@classmethod\n\tasync def load(A,audio=False,video=True):return await A.request_stream(audio=audio,video=video)\n\tasync def get_stream(A):B=A.kind.replace('input','').replace('output','');C={B:{'deviceId':{'exact':A.id}}};return await A.request_stream(**C)\nasync def list_devices():A=await window.navigator.mediaDevices.enumerateDevices();return[Device(A)for A in A]",
|
|
13
13
|
"storage.py": "_C='memoryview'\n_B='bytearray'\n_A='generic'\nfrom polyscript import storage as _polyscript_storage\nfrom pyscript.flatted import parse as _parse\nfrom pyscript.flatted import stringify as _stringify\nfrom pyscript.ffi import is_none\ndef _convert_to_idb(value):\n\tA=value\n\tif is_none(A):return _stringify(['null',0])\n\tif isinstance(A,(bool,float,int,str,list,dict,tuple)):return _stringify([_A,A])\n\tif isinstance(A,bytearray):return _stringify([_B,list(A)])\n\tif isinstance(A,memoryview):return _stringify([_C,list(A)])\n\traise TypeError(f\"Cannot serialize type {type(A).__name__} for storage.\")\ndef _convert_from_idb(value):\n\tC=value;A,B=_parse(C)\n\tif A=='null':return\n\tif A==_A:return B\n\tif A==_B:return bytearray(B)\n\tif A==_C:return memoryview(bytearray(B))\n\treturn C\nclass Storage(dict):\n\tdef __init__(B,store):A=store;super().__init__({A:_convert_from_idb(B)for(A,B)in A.entries()});B._store=A\n\tdef __delitem__(A,key):A._store.delete(key);super().__delitem__(key)\n\tdef __setitem__(B,key,value):A=value;B._store.set(key,_convert_to_idb(A));super().__setitem__(key,A)\n\tdef clear(A):A._store.clear();super().clear()\n\tasync def sync(A):await A._store.sync()\nasync def storage(name='',storage_class=Storage):\n\tif not name:raise ValueError('Storage name must be a non-empty string')\n\tA=await _polyscript_storage(f\"@pyscript/{name}\");return storage_class(A)",
|
|
14
14
|
"util.py": "import js,inspect\ndef as_bytearray(buffer):\n\tA=js.Uint8Array.new(buffer);B=A.length;C=bytearray(B)\n\tfor D in range(B):C[D]=A[D]\n\treturn C\nclass NotSupported:\n\tdef __init__(A,name,error):object.__setattr__(A,'name',name);object.__setattr__(A,'error',error)\n\tdef __repr__(A):return f\"<NotSupported {A.name} [{A.error}]>\"\n\tdef __getattr__(A,attr):raise AttributeError(A.error)\n\tdef __setattr__(A,attr,value):raise AttributeError(A.error)\n\tdef __call__(A,*B):raise TypeError(A.error)\ndef is_awaitable(obj):\n\tA=obj;from pyscript import config as C\n\tif C['type']=='mpy':\n\t\tB=repr(A)\n\t\tif'<closure <generator>'in B:return True\n\t\tif'<bound_method'in B and'<generator>'in B:return True\n\t\treturn inspect.isgeneratorfunction(A)\n\treturn inspect.iscoroutinefunction(A)",
|
|
15
|
-
"web.py": "_D='object'\n_C='tagName'\n_B='on_'\n_A=None\nfrom pyscript import document,when,Event\nfrom pyscript.ffi import create_proxy,is_none\ndef _wrap_if_not_none(dom_element):return Element.wrap_dom_element(dom_element)if not is_none(dom_element)else _A\ndef _find_by_id(dom_node,target_id):element_id=target_id[1:]if target_id.startswith('#')else target_id;result=dom_node.querySelector(f\"#{element_id}\");return _wrap_if_not_none(result)\ndef _find_and_wrap(dom_node,selector):return ElementCollection.wrap_dom_elements(dom_node.querySelectorAll(selector))\nclass Element:\n\telement_classes_by_tag_name={}\n\t@classmethod\n\tdef get_tag_name(cls):return cls.__name__.replace('_','')\n\t@classmethod\n\tdef register_element_classes(cls,element_classes):\n\t\tfor element_class in element_classes:tag_name=element_class.get_tag_name();cls.element_classes_by_tag_name[tag_name]=element_class\n\t@classmethod\n\tdef unregister_element_classes(cls,element_classes):\n\t\tfor element_class in element_classes:tag_name=element_class.get_tag_name();cls.element_classes_by_tag_name.pop(tag_name,_A)\n\t@classmethod\n\tdef wrap_dom_element(cls,dom_element):element_cls=cls.element_classes_by_tag_name.get(dom_element.tagName.lower(),cls);return element_cls(dom_element=dom_element)\n\tdef __init__(self,dom_element=_A,classes=_A,style=_A,**kwargs):\n\t\tif is_none(dom_element):self._dom_element=document.createElement(type(self).get_tag_name())\n\t\telse:self._dom_element=dom_element\n\t\tself._on_events={};self.update(classes=classes,style=style,**kwargs)\n\tdef __eq__(self,obj):return isinstance(obj,Element)and obj._dom_element==self._dom_element\n\tdef __getitem__(self,key):\n\t\tif isinstance(key,(int,slice)):return self.children[key]\n\t\tif isinstance(key,str):return _find_by_id(self._dom_element,key)\n\t\traise TypeError(f\"Element indices must be integers, slices, or strings, not {type(key).__name__}.\")\n\tdef __getattr__(self,name):\n\t\tif name.startswith(_B):return self.get_event(name)\n\t\tdom_name=self._normalize_attribute_name(name);return getattr(self._dom_element,dom_name)\n\tdef __setattr__(self,name,value):\n\t\tif name.startswith('_'):super().__setattr__(name,value)\n\t\telif name.startswith(_B):self.get_event(name).add_listener(value)\n\t\telse:dom_name=self._normalize_attribute_name(name);setattr(self._dom_element,dom_name,value)\n\tdef _normalize_attribute_name(self,name):\n\t\tif name.endswith('_'):name=name[:-1]\n\t\tif name=='for':return'htmlFor'\n\t\tif name=='class':return'className'\n\t\treturn name\n\tdef get_event(self,name):\n\t\tif not name.startswith(_B):raise ValueError(\"Event names must start with 'on_'.\")\n\t\tevent_name=name[3:]\n\t\tif not hasattr(self._dom_element,event_name):raise ValueError(f\"Element has no '{event_name}' event.\")\n\t\tif name in self._on_events:return self._on_events[name]\n\t\tev=Event();self._on_events[name]=ev;self._dom_element.addEventListener(event_name,create_proxy(ev.trigger));return ev\n\t@property\n\tdef children(self):return ElementCollection.wrap_dom_elements(self._dom_element.children)\n\t@property\n\tdef classes(self):\n\t\tif not hasattr(self,'_classes'):self._classes=Classes(self)\n\t\treturn self._classes\n\t@property\n\tdef style(self):\n\t\tif not hasattr(self,'_style'):self._style=Style(self)\n\t\treturn self._style\n\t@property\n\tdef parent(self):\n\t\tif is_none(self._dom_element.parentElement):return\n\t\treturn Element.wrap_dom_element(self._dom_element.parentElement)\n\tdef append(self,*items):\n\t\tfor item in items:\n\t\t\tif isinstance(item,Element):self._dom_element.appendChild(item._dom_element)\n\t\t\telif isinstance(item,ElementCollection):\n\t\t\t\tfor element in item:self._dom_element.appendChild(element._dom_element)\n\t\t\telif isinstance(item,(list,tuple)):\n\t\t\t\tfor child in item:self.append(child)\n\t\t\telif hasattr(item,_C):self._dom_element.appendChild(item)\n\t\t\telif hasattr(item,'length'):\n\t\t\t\tfor element in item:self._dom_element.appendChild(element)\n\t\t\telse:raise TypeError(f\"Cannot append {type(item).__name__} to element.\")\n\tdef clone(self,clone_id=_A):clone=Element.wrap_dom_element(self._dom_element.cloneNode(True));clone.id=clone_id;return clone\n\tdef find(self,selector):return _find_and_wrap(self._dom_element,selector)\n\tdef show_me(self):self._dom_element.scrollIntoView()\n\tdef update(self,classes=_A,style=_A,**kwargs):\n\t\tif classes:\n\t\t\tif isinstance(classes,str):self.classes.add(classes)\n\t\t\telse:\n\t\t\t\tfor class_name in classes:self.classes.add(class_name)\n\t\tif style:\n\t\t\tfor(key,value)in style.items():self.style[key]=value\n\t\tfor(name,value)in kwargs.items():setattr(self,name,value)\nclass Classes(set):\n\tdef __init__(self,element):self._class_list=element._dom_element.classList;super().__init__(self._class_list)\n\tdef _extract_class_names(self,class_name):return[name for name in class_name.split()if name]if' 'in class_name else[class_name]\n\tdef add(self,class_name):\n\t\tfor name in self._extract_class_names(class_name):super().add(name);self._class_list.add(name)\n\tdef remove(self,class_name):\n\t\tfor name in self._extract_class_names(class_name):super().remove(name);self._class_list.remove(name)\n\tdef discard(self,class_name):\n\t\tfor name in self._extract_class_names(class_name):\n\t\t\tsuper().discard(name)\n\t\t\tif name in self._class_list:self._class_list.remove(name)\n\tdef clear(self):\n\t\tsuper().clear()\n\t\twhile self._class_list.length>0:self._class_list.remove(self._class_list.item(0))\nclass Style(dict):\n\tdef __init__(self,element):self._style=element._dom_element.style;super().__init__()\n\tdef __setitem__(self,key,value):super().__setitem__(key,value);self._style.setProperty(key,str(value))\n\tdef __delitem__(self,key):super().__delitem__(key);self._style.removeProperty(key)\nclass HasOptions:\n\t@property\n\tdef options(self):\n\t\tif not hasattr(self,'_options'):self._options=Options(self)\n\t\treturn self._options\nclass Options:\n\tdef __init__(self,element):self._element=element\n\tdef __getitem__(self,key):return self.options[key]\n\tdef __iter__(self):yield from self.options\n\tdef __len__(self):return len(self.options)\n\tdef __repr__(self):return f\"{self.__class__.__name__} (length: {len(self)}) {self.options}\"\n\t@property\n\tdef options(self):return[Element.wrap_dom_element(o)for o in self._element._dom_element.options]\n\t@property\n\tdef selected(self):return self.options[self._element._dom_element.selectedIndex]\n\tdef add(self,value=_A,html=_A,text=_A,before=_A,**kwargs):\n\t\tif value:kwargs['value']=value\n\t\tif html:kwargs['innerHTML']=html\n\t\tif text:kwargs['text']=text\n\t\tnew_option=option(**kwargs)\n\t\tif before and isinstance(before,Element):before=before._dom_element\n\t\tself._element._dom_element.add(new_option._dom_element,before)\n\tdef clear(self):self._element._dom_element.length=0\n\tdef remove(self,index):self._element._dom_element.remove(index)\nclass ContainerElement(Element):\n\tdef __init__(self,*args,children=_A,dom_element=_A,style=_A,classes=_A,**kwargs):\n\t\tsuper().__init__(dom_element=dom_element,style=style,classes=classes,**kwargs)\n\t\tfor child in list(args)+(children or[]):\n\t\t\tif isinstance(child,(Element,ElementCollection)):self.append(child)\n\t\t\telse:self._dom_element.insertAdjacentHTML('beforeend',child)\n\tdef __iter__(self):yield from self.children\nclass ElementCollection:\n\t@classmethod\n\tdef wrap_dom_elements(cls,dom_elements):return cls([Element.wrap_dom_element(dom_element)for dom_element in dom_elements])\n\tdef __init__(self,elements):self._elements=elements\n\tdef __eq__(self,obj):return isinstance(obj,ElementCollection)and obj._elements==self._elements\n\tdef __getitem__(self,key):\n\t\tif isinstance(key,int):return self._elements[key]\n\t\tif isinstance(key,slice):return ElementCollection(self._elements[key])\n\t\tif isinstance(key,str):\n\t\t\tfor element in self._elements:\n\t\t\t\tresult=_find_by_id(element._dom_element,key)\n\t\t\t\tif result:return result\n\t\t\treturn\n\t\traise TypeError(f\"Collection indices must be integers, slices, or strings, not {type(key).__name__}\")\n\tdef __iter__(self):yield from self._elements\n\tdef __len__(self):return len(self._elements)\n\tdef __repr__(self):return f\"{self.__class__.__name__} (length: {len(self._elements)}) {self._elements}\"\n\t@property\n\tdef elements(self):return self._elements\n\tdef find(self,selector):\n\t\telements=[]\n\t\tfor element in self._elements:elements.extend(_find_and_wrap(element._dom_element,selector))\n\t\treturn ElementCollection(elements)\n\tdef update_all(self,**kwargs):\n\t\tfor element in self._elements:\n\t\t\tfor(name,value)in kwargs.items():setattr(element,name,value)\nclass canvas(ContainerElement):\n\tdef download(self,filename='snapped.png'):download_link=a(download=filename,href=self._dom_element.toDataURL());self.append(download_link);download_link._dom_element.click()\n\tdef draw(self,what,width=_A,height=_A):\n\t\tif isinstance(what,Element):what=what._dom_element\n\t\tctx=self._dom_element.getContext('2d')\n\t\tif width or height:ctx.drawImage(what,0,0,width,height)\n\t\telse:ctx.drawImage(what,0,0)\nclass video(ContainerElement):\n\tdef snap(self,to=_A,width=_A,height=_A):\n\t\tB='CANVAS';A='Element to snap to must be a canvas.';width=width if width else self.videoWidth;height=height if height else self.videoHeight\n\t\tif is_none(to):to=canvas(width=width,height=height)\n\t\telif isinstance(to,Element):\n\t\t\tif to.tag!='canvas':raise TypeError(A)\n\t\telif getattr(to,_C,'')==B:to=canvas(dom_element=to)\n\t\telif isinstance(to,str):\n\t\t\tnodelist=document.querySelectorAll(to)\n\t\t\tif nodelist.length==0:raise TypeError(f\"No element with selector {to} to snap to.\")\n\t\t\tif nodelist[0].tagName!=B:raise TypeError(A)\n\t\t\tto=canvas(dom_element=nodelist[0])\n\t\tto.draw(self,width,height);return to\nclass datalist(ContainerElement,HasOptions):0\nclass optgroup(ContainerElement,HasOptions):0\nclass select(ContainerElement,HasOptions):0\nCONTAINER_TAGS=['a','abbr','address','article','aside','audio','b','blockquote','body','button','caption','cite','code','colgroup','data','dd','del','details','dialog','div','dl','dt','em','fieldset','figcaption','figure','footer','form','h1','h2','h3','h4','h5','h6','head','header','hgroup','html','i','iframe','ins','kbd','label','legend','li','main','map','mark','menu','meta','meter','nav',_D,'ol','option','output','p','param','picture','pre','progress','q','s','script','section','small','span','strong','style','sub','summary','sup','table','tbody','td','template','textarea','tfoot','th','thead','time','title','tr','u','ul','var','wbr']\nVOID_TAGS=['area','base','br','col','embed','hr','img','input','link','source','track']\ndef _create_element_classes():\n\tA='__doc__';classes=[canvas,video,datalist,optgroup,select]\n\tfor tag in CONTAINER_TAGS:class_name=f\"{tag}_\"if tag in('del','map',_D)else tag;doc=f\"HTML <{tag}> element. Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/{tag}\";cls=type(class_name,(ContainerElement,),{A:doc});globals()[class_name]=cls;classes.append(cls)\n\tfor tag in VOID_TAGS:class_name=f\"{tag}_\"if tag=='input'else tag;doc=f\"HTML <{tag}> element. Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/{tag}\";cls=type(class_name,(Element,),{A:doc});globals()[class_name]=cls;classes.append(cls)\n\tElement.register_element_classes(classes)\n_create_element_classes()\nclass Page:\n\tdef __init__(self):self.html=Element.wrap_dom_element(document.documentElement);self.body=Element.wrap_dom_element(document.body);self.head=Element.wrap_dom_element(document.head)\n\tdef __getitem__(self,key):return _find_by_id(document,key)\n\t@property\n\tdef title(self):return document.title\n\t@title.setter\n\tdef title(self,value):document.title=value\n\tdef append(self,*items):self.body.append(*items)\n\tdef find(self,selector):return _find_and_wrap(document,selector)\npage=Page()",
|
|
15
|
+
"web.py": "_D='object'\n_C='tagName'\n_B='on_'\n_A=None\nfrom js import console\nfrom pyscript import document,Event\nfrom pyscript.ffi import create_proxy,is_none\ndef _wrap_if_not_none(dom_element):return Element.wrap_dom_element(dom_element)if not is_none(dom_element)else _A\ndef _find_by_id(dom_node,target_id):element_id=target_id[1:]if target_id.startswith('#')else target_id;result=dom_node.querySelector(f\"#{element_id}\");return _wrap_if_not_none(result)\ndef _find_and_wrap(dom_node,selector):return ElementCollection.wrap_dom_elements(dom_node.querySelectorAll(selector))\nclass Element:\n\telement_classes_by_tag_name={}\n\t@classmethod\n\tdef get_tag_name(cls):return cls.__name__.replace('_','')\n\t@classmethod\n\tdef register_element_classes(cls,element_classes):\n\t\tfor element_class in element_classes:tag_name=element_class.get_tag_name();cls.element_classes_by_tag_name[tag_name]=element_class\n\t@classmethod\n\tdef unregister_element_classes(cls,element_classes):\n\t\tfor element_class in element_classes:tag_name=element_class.get_tag_name();cls.element_classes_by_tag_name.pop(tag_name,_A)\n\t@classmethod\n\tdef wrap_dom_element(cls,dom_element):element_cls=cls.element_classes_by_tag_name.get(dom_element.tagName.lower(),cls);return element_cls(dom_element=dom_element)\n\tdef __init__(self,dom_element=_A,classes=_A,style=_A,**kwargs):\n\t\tif is_none(dom_element):self._dom_element=document.createElement(type(self).get_tag_name())\n\t\telse:self._dom_element=dom_element\n\t\tself._on_events={};self.update(classes=classes,style=style,**kwargs)\n\tdef __eq__(self,obj):return isinstance(obj,Element)and obj._dom_element==self._dom_element\n\tdef __getitem__(self,key):\n\t\tif isinstance(key,(int,slice)):return self.children[key]\n\t\tif isinstance(key,str):return _find_by_id(self._dom_element,key)\n\t\traise TypeError(f\"Element indices must be integers, slices, or strings, not {type(key).__name__}.\")\n\tdef __getattr__(self,name):\n\t\tif name.startswith(_B):return self.get_event(name)\n\t\tdom_name=self._normalize_attribute_name(name);return getattr(self._dom_element,dom_name)\n\tdef __setattr__(self,name,value):\n\t\tif name.startswith('_'):super().__setattr__(name,value)\n\t\telif name.startswith(_B):self.get_event(name).add_listener(value)\n\t\telse:dom_name=self._normalize_attribute_name(name);setattr(self._dom_element,dom_name,value)\n\tdef _normalize_attribute_name(self,name):\n\t\tif name.endswith('_'):name=name[:-1]\n\t\tif name=='for':return'htmlFor'\n\t\tif name=='class':return'className'\n\t\treturn name\n\tdef get_event(self,name):\n\t\tif not name.startswith(_B):raise ValueError(\"Event names must start with 'on_'.\")\n\t\tevent_name=name[3:]\n\t\tif not hasattr(self._dom_element,event_name):raise ValueError(f\"Element has no '{event_name}' event.\")\n\t\tif name in self._on_events:return self._on_events[name]\n\t\tev=Event();self._on_events[name]=ev;self._dom_element.addEventListener(event_name,create_proxy(ev.trigger));return ev\n\t@property\n\tdef children(self):return ElementCollection.wrap_dom_elements(self._dom_element.children)\n\t@property\n\tdef classes(self):\n\t\tif not hasattr(self,'_classes'):self._classes=Classes(self)\n\t\treturn self._classes\n\t@property\n\tdef style(self):\n\t\tif not hasattr(self,'_style'):self._style=Style(self)\n\t\treturn self._style\n\t@property\n\tdef parent(self):\n\t\tif is_none(self._dom_element.parentElement):return\n\t\treturn Element.wrap_dom_element(self._dom_element.parentElement)\n\tdef append(self,*items):\n\t\tfor item in items:\n\t\t\tif isinstance(item,Element):self._dom_element.appendChild(item._dom_element)\n\t\t\telif isinstance(item,ElementCollection):\n\t\t\t\tfor element in item:self._dom_element.appendChild(element._dom_element)\n\t\t\telif isinstance(item,(list,tuple)):\n\t\t\t\tfor child in item:self.append(child)\n\t\t\telif hasattr(item,_C):self._dom_element.appendChild(item)\n\t\t\telif hasattr(item,'length'):\n\t\t\t\tfor element in item:self._dom_element.appendChild(element)\n\t\t\telif isinstance(item,(str,int,float,bool)):self._dom_element.append(item)\n\t\t\telse:raise TypeError(f\"Cannot append {type(item).__name__} to element.\")\n\tdef clone(self,clone_id=_A):clone=Element.wrap_dom_element(self._dom_element.cloneNode(True));clone.id=clone_id;return clone\n\tdef find(self,selector):return _find_and_wrap(self._dom_element,selector)\n\tdef show_me(self):self._dom_element.scrollIntoView()\n\tdef update(self,classes=_A,style=_A,**kwargs):\n\t\tif classes:\n\t\t\tif isinstance(classes,str):self.classes.add(classes)\n\t\t\telse:\n\t\t\t\tfor class_name in classes:self.classes.add(class_name)\n\t\tif style:\n\t\t\tfor(key,value)in style.items():self.style[key]=value\n\t\tfor(name,value)in kwargs.items():setattr(self,name,value)\nclass Classes(set):\n\tdef __init__(self,element):self._class_list=element._dom_element.classList;super().__init__(self._class_list)\n\tdef _extract_class_names(self,class_name):return[name for name in class_name.split()if name]if' 'in class_name else[class_name]\n\tdef add(self,class_name):\n\t\tfor name in self._extract_class_names(class_name):super().add(name);self._class_list.add(name)\n\tdef remove(self,class_name):\n\t\tfor name in self._extract_class_names(class_name):\n\t\t\tif name in self:super().remove(name);self._class_list.remove(name)\n\t\t\telse:console.warn(f\"Class '{name}' not found in element classes.\")\n\tdef discard(self,class_name):\n\t\tfor name in self._extract_class_names(class_name):\n\t\t\tsuper().discard(name)\n\t\t\tif name in self._class_list:self._class_list.remove(name)\n\tdef clear(self):\n\t\tsuper().clear()\n\t\twhile self._class_list.length>0:self._class_list.remove(self._class_list.item(0))\nclass Style(dict):\n\tdef __init__(self,element):self._style=element._dom_element.style;super().__init__()\n\tdef __setitem__(self,key,value):super().__setitem__(key,value);self._style.setProperty(key,str(value))\n\tdef __delitem__(self,key):super().__delitem__(key);self._style.removeProperty(key)\nclass HasOptions:\n\t@property\n\tdef options(self):\n\t\tif not hasattr(self,'_options'):self._options=Options(self)\n\t\treturn self._options\nclass Options:\n\tdef __init__(self,element):self._element=element\n\tdef __getitem__(self,key):return self.options[key]\n\tdef __iter__(self):yield from self.options\n\tdef __len__(self):return len(self.options)\n\tdef __repr__(self):return f\"{self.__class__.__name__} (length: {len(self)}) {self.options}\"\n\t@property\n\tdef options(self):return[Element.wrap_dom_element(o)for o in self._element._dom_element.options]\n\t@property\n\tdef selected(self):return self.options[self._element._dom_element.selectedIndex]\n\tdef add(self,value=_A,html=_A,text=_A,before=_A,**kwargs):\n\t\tif value:kwargs['value']=value\n\t\tif html:kwargs['innerHTML']=html\n\t\tif text:kwargs['text']=text\n\t\tnew_option=option(**kwargs)\n\t\tif before and isinstance(before,Element):before=before._dom_element\n\t\tself._element._dom_element.add(new_option._dom_element,before)\n\tdef clear(self):self._element._dom_element.length=0\n\tdef remove(self,index):self._element._dom_element.remove(index)\nclass ContainerElement(Element):\n\tdef __init__(self,*args,children=_A,dom_element=_A,style=_A,classes=_A,**kwargs):\n\t\tsuper().__init__(dom_element=dom_element,style=style,classes=classes,**kwargs)\n\t\tfor child in list(args)+(children or[]):\n\t\t\tif isinstance(child,(Element,ElementCollection)):self.append(child)\n\t\t\telse:self._dom_element.insertAdjacentHTML('beforeend',child)\n\tdef __iter__(self):yield from self.children\nclass ElementCollection:\n\t@classmethod\n\tdef wrap_dom_elements(cls,dom_elements):return cls([Element.wrap_dom_element(dom_element)for dom_element in dom_elements])\n\tdef __init__(self,elements):self._elements=elements\n\tdef __eq__(self,obj):return isinstance(obj,ElementCollection)and obj._elements==self._elements\n\tdef __getitem__(self,key):\n\t\tif isinstance(key,int):return self._elements[key]\n\t\tif isinstance(key,slice):return ElementCollection(self._elements[key])\n\t\tif isinstance(key,str):\n\t\t\tfor element in self._elements:\n\t\t\t\tresult=_find_by_id(element._dom_element,key)\n\t\t\t\tif result:return result\n\t\t\treturn\n\t\traise TypeError(f\"Collection indices must be integers, slices, or strings, not {type(key).__name__}\")\n\tdef __iter__(self):yield from self._elements\n\tdef __len__(self):return len(self._elements)\n\tdef __repr__(self):return f\"{self.__class__.__name__} (length: {len(self._elements)}) {self._elements}\"\n\t@property\n\tdef elements(self):return self._elements\n\tdef find(self,selector):\n\t\telements=[]\n\t\tfor element in self._elements:elements.extend(_find_and_wrap(element._dom_element,selector))\n\t\treturn ElementCollection(elements)\n\tdef update_all(self,classes=_A,style=_A,**kwargs):\n\t\tfor element in self._elements:element.update(classes=classes,style=style,**kwargs)\nclass canvas(ContainerElement):\n\tdef download(self,filename='snapped.png'):download_link=a(download=filename,href=self._dom_element.toDataURL());self.append(download_link);download_link._dom_element.click()\n\tdef draw(self,what,width=_A,height=_A):\n\t\tif isinstance(what,Element):what=what._dom_element\n\t\tctx=self._dom_element.getContext('2d')\n\t\tif width or height:ctx.drawImage(what,0,0,width,height)\n\t\telse:ctx.drawImage(what,0,0)\nclass video(ContainerElement):\n\tdef snap(self,to=_A,width=_A,height=_A):\n\t\tB='CANVAS';A='Element to snap to must be a canvas.';width=width if width else self.videoWidth;height=height if height else self.videoHeight\n\t\tif is_none(to):to=canvas(width=width,height=height)\n\t\telif isinstance(to,Element):\n\t\t\tif to.tag!='canvas':raise TypeError(A)\n\t\telif getattr(to,_C,'')==B:to=canvas(dom_element=to)\n\t\telif isinstance(to,str):\n\t\t\tnodelist=document.querySelectorAll(to)\n\t\t\tif nodelist.length==0:raise TypeError(f\"No element with selector {to} to snap to.\")\n\t\t\tif nodelist[0].tagName!=B:raise TypeError(A)\n\t\t\tto=canvas(dom_element=nodelist[0])\n\t\tto.draw(self,width,height);return to\nclass datalist(ContainerElement,HasOptions):0\nclass optgroup(ContainerElement,HasOptions):0\nclass select(ContainerElement,HasOptions):0\nCONTAINER_TAGS=['a','abbr','address','article','aside','audio','b','blockquote','body','button','caption','cite','code','colgroup','data','dd','del','details','dialog','div','dl','dt','em','fieldset','figcaption','figure','footer','form','h1','h2','h3','h4','h5','h6','head','header','hgroup','html','i','iframe','ins','kbd','label','legend','li','main','map','mark','menu','meta','meter','nav',_D,'ol','option','output','p','param','picture','pre','progress','q','s','script','section','small','span','strong','style','sub','summary','sup','table','tbody','td','template','textarea','tfoot','th','thead','time','title','tr','u','ul','var','wbr']\nVOID_TAGS=['area','base','br','col','embed','hr','img','input','link','source','track']\ndef _create_element_classes():\n\tA='__doc__';classes=[canvas,video,datalist,optgroup,select]\n\tfor tag in CONTAINER_TAGS:class_name=f\"{tag}_\"if tag in('del','map',_D)else tag;doc=f\"HTML <{tag}> element. Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/{tag}\";cls=type(class_name,(ContainerElement,),{A:doc});globals()[class_name]=cls;classes.append(cls)\n\tfor tag in VOID_TAGS:class_name=f\"{tag}_\"if tag=='input'else tag;doc=f\"HTML <{tag}> element. Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/{tag}\";cls=type(class_name,(Element,),{A:doc});globals()[class_name]=cls;classes.append(cls)\n\tElement.register_element_classes(classes)\n_create_element_classes()\nclass Page:\n\tdef __init__(self):self.html=Element.wrap_dom_element(document.documentElement);self.body=Element.wrap_dom_element(document.body);self.head=Element.wrap_dom_element(document.head)\n\tdef __getitem__(self,key):return _find_by_id(document,key)\n\t@property\n\tdef title(self):return document.title\n\t@title.setter\n\tdef title(self,value):document.title=value\n\tdef append(self,*items):self.body.append(*items)\n\tdef find(self,selector):return _find_and_wrap(document,selector)\npage=Page()",
|
|
16
16
|
"websocket.py": "import js\nfrom pyscript.ffi import create_proxy\nfrom pyscript.util import as_bytearray,is_awaitable\ndef _attach_event_handler(websocket,handler_name,handler_function):\n\tA=handler_function\n\tif is_awaitable(A):\n\t\tasync def C(event):await A(WebSocketEvent(event))\n\t\tB=create_proxy(C)\n\telse:B=create_proxy(lambda event:A(WebSocketEvent(event)))\n\tsetattr(websocket,handler_name,B)\nclass WebSocketEvent:\n\tdef __init__(A,event):A._event=event\n\tdef __getattr__(B,attr):\n\t\tA=getattr(B._event,attr)\n\t\tif attr=='data'and not isinstance(A,str):\n\t\t\tif hasattr(A,'to_py'):return A.to_py()\n\t\t\telse:return memoryview(as_bytearray(A))\n\t\treturn A\nclass WebSocket:\n\tCONNECTING=0;OPEN=1;CLOSING=2;CLOSED=3\n\tdef __init__(B,url,protocols=None,**D):\n\t\tC=protocols\n\t\tif C:A=js.WebSocket.new(url,C)\n\t\telse:A=js.WebSocket.new(url)\n\t\tA.binaryType='arraybuffer';object.__setattr__(B,'_js_websocket',A)\n\t\tfor(E,F)in D.items():setattr(B,E,F)\n\tdef __getattr__(A,attr):return getattr(A._js_websocket,attr)\n\tdef __setattr__(B,attr,value):\n\t\tC=value;A=attr\n\t\tif A in['onclose','onerror','onmessage','onopen']:_attach_event_handler(B._js_websocket,A,C)\n\t\telse:setattr(B._js_websocket,A,C)\n\tdef send(B,data):\n\t\tA=data\n\t\tif isinstance(A,str):B._js_websocket.send(A)\n\t\telse:\n\t\t\tC=js.Uint8Array.new(len(A))\n\t\t\tfor(D,E)in enumerate(A):C[D]=E\n\t\t\tB._js_websocket.send(C)\n\tdef close(B,code=None,reason=None):\n\t\tC=reason;A=code\n\t\tif A and C:B._js_websocket.close(A,C)\n\t\telif A:B._js_websocket.close(A)\n\t\telse:B._js_websocket.close()",
|
|
17
17
|
"workers.py": "import js,json\nfrom polyscript import workers as _polyscript_workers\nclass _ReadOnlyWorkersProxy:\n\tdef __getitem__(A,name):return js.Reflect.get(_polyscript_workers,name)\n\tdef __getattr__(A,name):return js.Reflect.get(_polyscript_workers,name)\nworkers=_ReadOnlyWorkersProxy()\nasync def create_named_worker(src,name,config=None,type='py'):\n\tB=config;A=js.document.createElement('script');A.type=type;A.src=src;A.setAttribute('worker','');A.setAttribute('name',name)\n\tif B:\n\t\tif isinstance(B,str):C=B\n\t\telse:C=json.dumps(B)\n\t\tA.setAttribute('config',C)\n\tjs.document.body.append(A);return await workers[name]"
|
|
18
18
|
}
|