Source code for wdom.window

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Window and CustomElementsRegistry classes."""

from typing import Any, Dict, Type, TYPE_CHECKING

from wdom import server
from wdom.element import Element
from wdom.event import WebEventTarget
from wdom.node import Node
from wdom.tag import Tag, default_classes

if TYPE_CHECKING:
    from typing import Optional  # noqa: F401


class CustomElementsRegistry(dict):
    """Registry of registered custom elements.

    Keep custom elements by name (custom-tag or is-attr) and extended-tag
    (or None) pair.
    """

    def _upgrage_to_tag_class(self, elm: Node) -> None:
        if elm.type_ and 'type' not in elm.attributes:
            elm.setAttribute('type', elm.type_)
        if elm.is_ and 'is' not in elm.attributes:
            elm.setAttribute('is', elm.is_)

    def _upgrade_by_tag(self, name: str, constructor: type) -> None:
        for elm in Element._element_buffer:
            if not elm._registered and elm.tag == name:
                elm.__class__ = constructor
                elm._registered = True
                if isinstance(elm, Tag):
                    self._upgrage_to_tag_class(elm)

    def _upgrade_by_is(self, name: str, constructor: type, extends: str
                       ) -> None:
        for elm in Element._element_buffer:
            if (not elm._registered and elm.tag == extends and
                    elm.getAttribute('is') == name):
                elm.__class__ = constructor
                elm._registered = True
                if isinstance(elm, Tag):
                    self._upgrage_to_tag_class(elm)

    def _define(self, name: str, constructor: type,
                options: Dict[str, str] = None) -> None:
        extends = None  # Optional[str]
        if options:
            extends = options['extends'].lower()
        self[(name, extends)] = constructor
        if extends:
            self._upgrade_by_is(name, constructor, extends)
        else:
            self._upgrade_by_tag(name, constructor)

    def _define_orig(self, name: str, constructor: Type[Tag],
                     options: dict = None
                     ) -> None:
        self._define(name.lower(), constructor, options)

    def _define_class(self, constructor: Type[Tag]) -> None:
        is_ = getattr(constructor, 'is_', getattr(constructor, 'is', None))
        if is_:
            name = is_.lower()
            options = {'extends': constructor.tag}
        else:
            name = constructor.tag.lower()
            options = {}
        self._define(name, constructor, options)

    def define(self, *args: Any, **kwargs: Any) -> None:
        """Add new custom element."""
        if isinstance(args[0], str):
            self._define_orig(*args, **kwargs)
        elif isinstance(args[0], type):
            self._define_class(*args, **kwargs)
        else:
            raise TypeError(
                'Invalid argument for define: {}, {}'.format(args, kwargs))

    def _define_default(self) -> None:
        for cls in default_classes:
            self.define(cls)

    def reset(self) -> None:
        """Clear all registered custom elements."""
        self.clear()
        self._define_default()


customElements = CustomElementsRegistry()
customElements._define_default()


[docs]class Window(WebEventTarget): """Window base class.""" @property def document(self) -> Node: """Return document object of this window.""" return self._document @property def ownerDocument(self) -> Node: """Need for connection check.""" return self.document @property def customElements(self) -> CustomElementsRegistry: """Return customElementsRegistry object.""" return self._custom_elements @property def wdom_id(self) -> str: # noqa: D102 return 'window' @property def connected(self) -> bool: # noqa: D102 return server.is_connected() def __init__(self, document: Node) -> None: """Make new window object. :arg Document document: root document of the window. """ super().__init__() self._document = document self._custom_elements = customElements self.addEventListener('mount', self._on_mount)