import json from enum import Enum from typing import Any, Dict, Optional, Union from webview.util import css_to_camel, escape_string class DOMPropType(Enum): Style = 1 Attribute = 2 class PropsDict: def __init__(self, element, type: DOMPropType, props: Optional[Dict[str, Any]] = None): self.__element = element self.__type = type if not props: return if type == DOMPropType.Style: converted_style = json.dumps({css_to_camel(key): value for key, value in props.items()}) self.__element._window.evaluate_js(f""" {self.__element._query_command}; var styles = JSON.parse('{escape_string(converted_style)}'); for (var key in styles) {{ element.style[key] = styles[key]; }} """) elif type == DOMPropType.Attribute: converted_attributes = json.dumps( {escape_string(key): escape_string(value) for key, value in props.items()} ) self.__element._window.evaluate_js(f""" {self.__element._query_command}; var attributes = JSON.parse('{converted_attributes}'); for (var key in attributes) {{ if (key === 'data-pywebview-id') {{ continue; }} else if (attributes[key] === null || attributes[key] === undefined) {{ element.removeAttribute(key); }} else {{ element.setAttribute(key, attributes[key]); }} }}; """) def __getitem__(self, key): data = self.__get_data() return data.get(key) def __setitem__(self, key, value): if self.__type == DOMPropType.Style: self.__set_style({key: value}) elif self.__type == DOMPropType.Attribute: self.__set_attribute({key: value}) def __delitem__(self, key): if self.__type == DOMPropType.Style: self.__set_style({key: ''}) elif self.__type == DOMPropType.Attribute: self.__set_attribute({key: None}) def __contains__(self, key): data = self.__get_data() return key in data def keys(self): data = self.__get_data() return data.keys() def values(self): data = self.__get_data() return data.values() def items(self): data = self.__get_data() return data.items() def get(self, key, default=None): data = self.__get_data() return data.get(key, default) def clear(self): data = self.__get_data() for key in data.keys(): data[key] = '' if self.__type == DOMPropType.Style else None if self.__type == DOMPropType.Style: self.__set_style(data) elif self.__type == DOMPropType.Attribute: self.__set_attribute(data) def copy(self): return self.__get_data() def update(self, other_dict: Dict[str, Union[str, int, float, None]]): if self.__type == DOMPropType.Style: self.__set_style(other_dict) elif self.__type == DOMPropType.Attribute: self.__set_attribute(other_dict) def pop(self, key, default=None): data = self.__get_data() return data.pop(key, default) def popitem(self): data = self.__get_data() return data.popitem() def __str__(self): data = self.__get_data() return str(data) def __repr__(self): data = self.__get_data() return repr(data) def __get_data(self) -> Dict[str, Any]: if self.__type == DOMPropType.Style: return self.__get_style() elif self.__type == DOMPropType.Attribute: return self.__get_attributes() def __get_attributes(self) -> Dict[str, Any]: return self.__element._window.evaluate_js(f""" {self.__element._query_command}; var attributes = element.attributes; var result = {{}}; for (var i = 0; i < attributes.length; i++) {{ if (attributes[i].name === 'data-pywebview-id') {{ continue; }} result[attributes[i].name] = attributes[i].value; }} result """) def __set_attribute(self, props: Dict[str, Any]): self.__element._window.evaluate_js(f""" {self.__element._query_command}; var values = JSON.parse('{escape_string(json.dumps(props))}'); for (var key in values) {{ var value = values[key]; if (value === null || value === undefined) {{ element.removeAttribute(key); }} else {{ element.setAttribute(key, value); }} }} """) def __get_style(self) -> Dict[str, Any]: return self.__element._window.evaluate_js(f""" {self.__element._query_command}; var styles = window.getComputedStyle(element); var computedStyles = {{}}; for (var i = 0; i < styles.length; i++) {{ var propertyName = styles[i]; var propertyValue = styles.getPropertyValue(propertyName); if (propertyValue !== '') {{ computedStyles[propertyName] = propertyValue; }} }} computedStyles; """) def __set_style(self, style: Dict[str, Any]): converted_style = json.dumps({css_to_camel(key): value for key, value in style.items()}) self.__element._window.evaluate_js(f""" {self.__element._query_command}; var styles = JSON.parse('{escape_string(converted_style)}'); for (var key in styles) {{ var value = styles[key]; element.style[key] = value; }} """)