Complete virtual environment added to git. Updated all changes to file in frontend directory
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
from ._version import __version__
|
||||
version = __version__
|
||||
|
||||
from .document import document
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
__version__ = '2.6.0'
|
||||
@@ -0,0 +1,75 @@
|
||||
__license__ = '''
|
||||
This file is part of Dominate.
|
||||
|
||||
Dominate is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Dominate is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with Dominate. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
from . import tags
|
||||
|
||||
try:
|
||||
basestring = basestring
|
||||
except NameError: # py3
|
||||
basestring = str
|
||||
unicode = str
|
||||
|
||||
class document(tags.html):
|
||||
tagname = 'html'
|
||||
def __init__(self, title='Dominate', doctype='<!DOCTYPE html>', request=None):
|
||||
'''
|
||||
Creates a new document instance. Accepts `title`, `doctype`, and `request` keyword arguments.
|
||||
'''
|
||||
super(document, self).__init__()
|
||||
self.doctype = doctype
|
||||
self.head = super(document, self).add(tags.head())
|
||||
self.body = super(document, self).add(tags.body())
|
||||
self.title_node = self.head.add(tags.title(title))
|
||||
self._entry = self.body
|
||||
|
||||
def get_title(self):
|
||||
return self.title_node.text
|
||||
|
||||
def set_title(self, title):
|
||||
if isinstance(title, basestring):
|
||||
self.title_node.text = title
|
||||
else:
|
||||
self.head.remove(self.title_node)
|
||||
self.head.add(title)
|
||||
self.title_node = title
|
||||
|
||||
title = property(get_title, set_title)
|
||||
|
||||
def add(self, *args):
|
||||
'''
|
||||
Adding tags to a document appends them to the <body>.
|
||||
'''
|
||||
return self._entry.add(*args)
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
'''
|
||||
Creates a <title> tag if not present and renders the DOCTYPE and tag tree.
|
||||
'''
|
||||
r = []
|
||||
|
||||
#Validates the tag tree and adds the doctype if one was set
|
||||
if self.doctype:
|
||||
r.append(self.doctype)
|
||||
r.append('\n')
|
||||
r.append(super(document, self).render(*args, **kwargs))
|
||||
|
||||
return u''.join(r)
|
||||
__str__ = __unicode__ = render
|
||||
|
||||
def __repr__(self):
|
||||
return '<dominate.document "%s">' % self.title
|
||||
@@ -0,0 +1,68 @@
|
||||
__license__ = '''
|
||||
This file is part of Dominate.
|
||||
|
||||
Dominate is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Dominate is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with Dominate. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
try:
|
||||
basestring = basestring
|
||||
except NameError: # py3
|
||||
basestring = str
|
||||
unicode = str
|
||||
|
||||
|
||||
class dom1core(object):
|
||||
'''
|
||||
Implements the Document Object Model (Core) Level 1
|
||||
|
||||
http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/
|
||||
http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/level-one-core.html
|
||||
'''
|
||||
@property
|
||||
def parentNode(self):
|
||||
'''
|
||||
DOM API: Returns the parent tag of the current element.
|
||||
'''
|
||||
return self.parent
|
||||
|
||||
def getElementById(self, id):
|
||||
'''
|
||||
DOM API: Returns single element with matching id value.
|
||||
'''
|
||||
results = self.get(id=id)
|
||||
if len(results) > 1:
|
||||
raise ValueError('Multiple tags with id "%s".' % id)
|
||||
elif results:
|
||||
return results[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
def getElementsByTagName(self, name):
|
||||
'''
|
||||
DOM API: Returns all tags that match name.
|
||||
'''
|
||||
if isinstance(name, basestring):
|
||||
return self.get(name.lower())
|
||||
else:
|
||||
return None
|
||||
|
||||
def appendChild(self, obj):
|
||||
'''
|
||||
DOM API: Add an item to the end of the children list.
|
||||
'''
|
||||
self.add(obj)
|
||||
return self
|
||||
|
||||
|
||||
@@ -0,0 +1,486 @@
|
||||
__license__ = '''
|
||||
This file is part of Dominate.
|
||||
|
||||
Dominate is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Dominate is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with Dominate. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
# pylint: disable=bad-indentation, bad-whitespace, missing-docstring
|
||||
|
||||
import copy
|
||||
import numbers
|
||||
from collections import defaultdict, namedtuple
|
||||
from functools import wraps
|
||||
import threading
|
||||
|
||||
try:
|
||||
# Python 3
|
||||
from collections.abc import Callable
|
||||
except ImportError:
|
||||
# Python 2.7
|
||||
from collections import Callable
|
||||
|
||||
try:
|
||||
basestring = basestring
|
||||
except NameError: # py3
|
||||
basestring = str
|
||||
unicode = str
|
||||
|
||||
|
||||
try:
|
||||
import greenlet
|
||||
except ImportError:
|
||||
greenlet = None
|
||||
|
||||
|
||||
def _get_thread_context():
|
||||
context = [threading.current_thread()]
|
||||
if greenlet:
|
||||
context.append(greenlet.getcurrent())
|
||||
return hash(tuple(context))
|
||||
|
||||
|
||||
class dom_tag(object):
|
||||
is_single = False # Tag does not require matching end tag (ex. <hr/>)
|
||||
is_pretty = True # Text inside the tag should be left as-is (ex. <pre>)
|
||||
# otherwise, text will be escaped() and whitespace may be
|
||||
# modified
|
||||
is_inline = False
|
||||
|
||||
|
||||
def __new__(_cls, *args, **kwargs):
|
||||
'''
|
||||
Check if bare tag is being used a a decorator
|
||||
(called with a single function arg).
|
||||
decorate the function and return
|
||||
'''
|
||||
if len(args) == 1 and isinstance(args[0], Callable) \
|
||||
and not isinstance(args[0], dom_tag) and not kwargs:
|
||||
wrapped = args[0]
|
||||
|
||||
@wraps(wrapped)
|
||||
def f(*args, **kwargs):
|
||||
with _cls() as _tag:
|
||||
return wrapped(*args, **kwargs) or _tag
|
||||
return f
|
||||
return object.__new__(_cls)
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
'''
|
||||
Creates a new tag. Child tags should be passed as arguments and attributes
|
||||
should be passed as keyword arguments.
|
||||
|
||||
There is a non-rendering attribute which controls how the tag renders:
|
||||
|
||||
* `__inline` - Boolean value. If True renders all children tags on the same
|
||||
line.
|
||||
'''
|
||||
|
||||
self.attributes = {}
|
||||
self.children = []
|
||||
self.parent = None
|
||||
self.document = None
|
||||
|
||||
# Does not insert newlines on all children if True (recursive attribute)
|
||||
self.is_inline = kwargs.pop('__inline', self.is_inline)
|
||||
self.is_pretty = kwargs.pop('__pretty', self.is_pretty)
|
||||
|
||||
#Add child elements
|
||||
if args:
|
||||
self.add(*args)
|
||||
|
||||
for attr, value in kwargs.items():
|
||||
self.set_attribute(*type(self).clean_pair(attr, value))
|
||||
|
||||
self._ctx = None
|
||||
self._add_to_ctx()
|
||||
|
||||
|
||||
# context manager
|
||||
frame = namedtuple('frame', ['tag', 'items', 'used'])
|
||||
# stack of frames
|
||||
_with_contexts = defaultdict(list)
|
||||
|
||||
def _add_to_ctx(self):
|
||||
stack = dom_tag._with_contexts.get(_get_thread_context())
|
||||
if stack:
|
||||
self._ctx = stack[-1]
|
||||
stack[-1].items.append(self)
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
stack = dom_tag._with_contexts[_get_thread_context()]
|
||||
stack.append(dom_tag.frame(self, [], set()))
|
||||
return self
|
||||
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
thread_id = _get_thread_context()
|
||||
stack = dom_tag._with_contexts[thread_id]
|
||||
frame = stack.pop()
|
||||
for item in frame.items:
|
||||
if item in frame.used: continue
|
||||
self.add(item)
|
||||
if not stack:
|
||||
del dom_tag._with_contexts[thread_id]
|
||||
|
||||
|
||||
def __call__(self, func):
|
||||
'''
|
||||
tag instance is being used as a decorator.
|
||||
wrap func to make a copy of this tag
|
||||
'''
|
||||
# remove decorator from its context so it doesn't
|
||||
# get added in where it was defined
|
||||
if self._ctx:
|
||||
self._ctx.used.add(self)
|
||||
|
||||
@wraps(func)
|
||||
def f(*args, **kwargs):
|
||||
tag = copy.deepcopy(self)
|
||||
tag._add_to_ctx()
|
||||
with tag:
|
||||
return func(*args, **kwargs) or tag
|
||||
return f
|
||||
|
||||
|
||||
def set_attribute(self, key, value):
|
||||
'''
|
||||
Add or update the value of an attribute.
|
||||
'''
|
||||
if isinstance(key, int):
|
||||
self.children[key] = value
|
||||
elif isinstance(key, basestring):
|
||||
self.attributes[key] = value
|
||||
else:
|
||||
raise TypeError('Only integer and string types are valid for assigning '
|
||||
'child tags and attributes, respectively.')
|
||||
__setitem__ = set_attribute
|
||||
|
||||
def delete_attribute(self, key):
|
||||
if isinstance(key, int):
|
||||
del self.children[key:key+1]
|
||||
else:
|
||||
del self.attributes[key]
|
||||
__delitem__ = delete_attribute
|
||||
|
||||
def setdocument(self, doc):
|
||||
'''
|
||||
Creates a reference to the parent document to allow for partial-tree
|
||||
validation.
|
||||
'''
|
||||
# assume that a document is correct in the subtree
|
||||
if self.document != doc:
|
||||
self.document = doc
|
||||
for i in self.children:
|
||||
if not isinstance(i, dom_tag): return
|
||||
i.setdocument(doc)
|
||||
|
||||
|
||||
def add(self, *args):
|
||||
'''
|
||||
Add new child tags.
|
||||
'''
|
||||
for obj in args:
|
||||
if isinstance(obj, numbers.Number):
|
||||
# Convert to string so we fall into next if block
|
||||
obj = str(obj)
|
||||
|
||||
if isinstance(obj, basestring):
|
||||
obj = escape(obj)
|
||||
self.children.append(obj)
|
||||
|
||||
elif isinstance(obj, dom_tag):
|
||||
stack = dom_tag._with_contexts.get(_get_thread_context())
|
||||
if stack:
|
||||
stack[-1].used.add(obj)
|
||||
self.children.append(obj)
|
||||
obj.parent = self
|
||||
obj.setdocument(self.document)
|
||||
|
||||
elif isinstance(obj, dict):
|
||||
for attr, value in obj.items():
|
||||
self.set_attribute(*dom_tag.clean_pair(attr, value))
|
||||
|
||||
elif hasattr(obj, '__iter__'):
|
||||
for subobj in obj:
|
||||
self.add(subobj)
|
||||
|
||||
else: # wtf is it?
|
||||
raise ValueError('%r not a tag or string.' % obj)
|
||||
|
||||
if len(args) == 1:
|
||||
return args[0]
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def add_raw_string(self, s):
|
||||
self.children.append(s)
|
||||
|
||||
|
||||
def remove(self, obj):
|
||||
self.children.remove(obj)
|
||||
|
||||
|
||||
def clear(self):
|
||||
for i in self.children:
|
||||
if isinstance(i, dom_tag) and i.parent is self:
|
||||
i.parent = None
|
||||
self.children = []
|
||||
|
||||
|
||||
def get(self, tag=None, **kwargs):
|
||||
'''
|
||||
Recursively searches children for tags of a certain
|
||||
type with matching attributes.
|
||||
'''
|
||||
# Stupid workaround since we can not use dom_tag in the method declaration
|
||||
if tag is None: tag = dom_tag
|
||||
|
||||
attrs = [(dom_tag.clean_attribute(attr), value)
|
||||
for attr, value in kwargs.items()]
|
||||
|
||||
results = []
|
||||
for child in self.children:
|
||||
if (isinstance(tag, basestring) and type(child).__name__ == tag) or \
|
||||
(not isinstance(tag, basestring) and isinstance(child, tag)):
|
||||
|
||||
if all(child.attributes.get(attribute) == value
|
||||
for attribute, value in attrs):
|
||||
# If the child is of correct type and has all attributes and values
|
||||
# in kwargs add as a result
|
||||
results.append(child)
|
||||
if isinstance(child, dom_tag):
|
||||
# If the child is a dom_tag extend the search down through its children
|
||||
results.extend(child.get(tag, **kwargs))
|
||||
return results
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
'''
|
||||
Returns the stored value of the specified attribute or child
|
||||
(if it exists).
|
||||
'''
|
||||
if isinstance(key, int):
|
||||
# Children are accessed using integers
|
||||
try:
|
||||
return object.__getattribute__(self, 'children')[key]
|
||||
except KeyError:
|
||||
raise IndexError('Child with index "%s" does not exist.' % key)
|
||||
elif isinstance(key, basestring):
|
||||
# Attributes are accessed using strings
|
||||
try:
|
||||
return object.__getattribute__(self, 'attributes')[key]
|
||||
except KeyError:
|
||||
raise AttributeError('Attribute "%s" does not exist.' % key)
|
||||
else:
|
||||
raise TypeError('Only integer and string types are valid for accessing '
|
||||
'child tags and attributes, respectively.')
|
||||
__getattr__ = __getitem__
|
||||
|
||||
|
||||
def __len__(self):
|
||||
'''
|
||||
Number of child elements.
|
||||
'''
|
||||
return len(self.children)
|
||||
|
||||
|
||||
def __bool__(self):
|
||||
'''
|
||||
Hack for "if x" and __len__
|
||||
'''
|
||||
return True
|
||||
__nonzero__ = __bool__
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
'''
|
||||
Iterates over child elements.
|
||||
'''
|
||||
return self.children.__iter__()
|
||||
|
||||
|
||||
def __contains__(self, item):
|
||||
'''
|
||||
Checks recursively if item is in children tree.
|
||||
Accepts both a string and a class.
|
||||
'''
|
||||
return bool(self.get(item))
|
||||
|
||||
|
||||
def __iadd__(self, obj):
|
||||
'''
|
||||
Reflexive binary addition simply adds tag as a child.
|
||||
'''
|
||||
self.add(obj)
|
||||
return self
|
||||
|
||||
# String and unicode representations are the same as render()
|
||||
def __unicode__(self):
|
||||
return self.render()
|
||||
__str__ = __unicode__
|
||||
|
||||
|
||||
def render(self, indent=' ', pretty=True, xhtml=False):
|
||||
data = self._render([], 0, indent, pretty, xhtml)
|
||||
return u''.join(data)
|
||||
|
||||
|
||||
def _render(self, sb, indent_level, indent_str, pretty, xhtml):
|
||||
pretty = pretty and self.is_pretty
|
||||
|
||||
name = getattr(self, 'tagname', type(self).__name__)
|
||||
|
||||
# Workaround for python keywords and standard classes/methods
|
||||
# (del, object, input)
|
||||
if name[-1] == '_':
|
||||
name = name[:-1]
|
||||
|
||||
# open tag
|
||||
sb.append('<')
|
||||
sb.append(name)
|
||||
|
||||
for attribute, value in sorted(self.attributes.items()):
|
||||
if value is not False: # False values must be omitted completely
|
||||
sb.append(' %s="%s"' % (attribute, escape(unicode(value), True)))
|
||||
|
||||
sb.append(' />' if self.is_single and xhtml else '>')
|
||||
|
||||
if not self.is_single:
|
||||
inline = self._render_children(sb, indent_level + 1, indent_str, pretty, xhtml)
|
||||
|
||||
if pretty and not inline:
|
||||
sb.append('\n')
|
||||
sb.append(indent_str * indent_level)
|
||||
|
||||
# close tag
|
||||
sb.append('</')
|
||||
sb.append(name)
|
||||
sb.append('>')
|
||||
|
||||
return sb
|
||||
|
||||
def _render_children(self, sb, indent_level, indent_str, pretty, xhtml):
|
||||
inline = True
|
||||
for child in self.children:
|
||||
if isinstance(child, dom_tag):
|
||||
if pretty and not child.is_inline:
|
||||
inline = False
|
||||
sb.append('\n')
|
||||
sb.append(indent_str * indent_level)
|
||||
child._render(sb, indent_level, indent_str, pretty, xhtml)
|
||||
else:
|
||||
sb.append(unicode(child))
|
||||
|
||||
return inline
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
name = '%s.%s' % (self.__module__, type(self).__name__)
|
||||
|
||||
attributes_len = len(self.attributes)
|
||||
attributes = '%s attribute' % attributes_len
|
||||
if attributes_len != 1: attributes += 's'
|
||||
|
||||
children_len = len(self.children)
|
||||
children = '%s child' % children_len
|
||||
if children_len != 1: children += 'ren'
|
||||
|
||||
return '<%s at %x: %s, %s>' % (name, id(self), attributes, children)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def clean_attribute(attribute):
|
||||
'''
|
||||
Normalize attribute names for shorthand and work arounds for limitations
|
||||
in Python's syntax
|
||||
'''
|
||||
|
||||
# Shorthand
|
||||
attribute = {
|
||||
'cls': 'class',
|
||||
'className': 'class',
|
||||
'class_name': 'class',
|
||||
'fr': 'for',
|
||||
'html_for': 'for',
|
||||
'htmlFor': 'for',
|
||||
}.get(attribute, attribute)
|
||||
|
||||
# Workaround for Python's reserved words
|
||||
if attribute[0] == '_':
|
||||
attribute = attribute[1:]
|
||||
|
||||
# Workaround for dash
|
||||
special_prefix = any([attribute.startswith(x) for x in ('data_', 'aria_')])
|
||||
if attribute in set(['http_equiv']) or special_prefix:
|
||||
attribute = attribute.replace('_', '-').lower()
|
||||
|
||||
# Workaround for colon
|
||||
if attribute.split('_')[0] in ('xlink', 'xml', 'xmlns'):
|
||||
attribute = attribute.replace('_', ':', 1).lower()
|
||||
|
||||
return attribute
|
||||
|
||||
|
||||
@classmethod
|
||||
def clean_pair(cls, attribute, value):
|
||||
'''
|
||||
This will call `clean_attribute` on the attribute and also allows for the
|
||||
creation of boolean attributes.
|
||||
|
||||
Ex. input(selected=True) is equivalent to input(selected="selected")
|
||||
'''
|
||||
attribute = cls.clean_attribute(attribute)
|
||||
|
||||
# Check for boolean attributes
|
||||
# (i.e. selected=True becomes selected="selected")
|
||||
if value is True:
|
||||
value = attribute
|
||||
|
||||
# Ignore `if value is False`: this is filtered out in render()
|
||||
|
||||
return (attribute, value)
|
||||
|
||||
|
||||
_get_current_none = object()
|
||||
def get_current(default=_get_current_none):
|
||||
'''
|
||||
get the current tag being used as a with context or decorated function.
|
||||
if no context is active, raises ValueError, or returns the default, if provided
|
||||
'''
|
||||
h = _get_thread_context()
|
||||
ctx = dom_tag._with_contexts.get(h, None)
|
||||
if ctx:
|
||||
return ctx[-1].tag
|
||||
if default is _get_current_none:
|
||||
raise ValueError('no current context')
|
||||
return default
|
||||
|
||||
|
||||
def attr(*args, **kwargs):
|
||||
'''
|
||||
Set attributes on the current active tag context
|
||||
'''
|
||||
c = get_current()
|
||||
dicts = args + (kwargs,)
|
||||
for d in dicts:
|
||||
for attr, value in d.items():
|
||||
c.set_attribute(*dom_tag.clean_pair(attr, value))
|
||||
|
||||
|
||||
# escape() is used in render
|
||||
from .util import escape
|
||||
@@ -0,0 +1,370 @@
|
||||
'''
|
||||
This module consists of classes specific to HTML5-SVG Elements. In general this module does not include
|
||||
- Elements that are not specific to SVG (eg. <a>)
|
||||
- Elements that are deprecated
|
||||
'''
|
||||
from dominate.tags import html_tag
|
||||
from dominate.dom_tag import dom_tag
|
||||
import numbers
|
||||
|
||||
|
||||
__license__ = '''
|
||||
This file is part of Dominate.
|
||||
|
||||
Dominate is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Dominate is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with Dominate. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
# Tag attributes
|
||||
_ATTR_GLOBAL = set([
|
||||
'accesskey', 'class', 'class', 'contenteditable', 'contextmenu', 'dir',
|
||||
'draggable', 'id', 'item', 'hidden', 'lang', 'itemprop', 'spellcheck',
|
||||
'style', 'subject', 'tabindex', 'title'
|
||||
])
|
||||
|
||||
# https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Events#Attributes
|
||||
_ATTR_EVENTS = set([
|
||||
'onbegin', 'onend', 'onrepeat',
|
||||
'onabort', 'onerror', 'onresize', 'onscroll', 'onunload',
|
||||
'oncopy', 'oncut', 'onpaste',
|
||||
'oncancel', 'oncanplay', 'oncanplaythrough', 'onchange', 'onclick', 'onclose', 'oncuechange', 'ondblclick',
|
||||
'ondrag', 'ondragend', 'ondragenter', 'ondragexit', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop',
|
||||
'ondurationchange', 'onemptied', 'onended', 'onerror', 'onfocus', 'oninput', 'oninvalid', 'onkeydown', 'onkeypress',
|
||||
'onkeyup', 'onload', 'onloadeddata', 'onloadedmetadata','onloadstart', 'onmousedown', 'onmouseenter',
|
||||
'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onpause', 'onplay',
|
||||
'onplaying', 'onprogress', 'onratechange', 'onreset', 'onresize', 'onscroll', 'onseeked', 'onseeking', 'onselect',
|
||||
'onshow', 'onstalled', 'onsubmit', 'onsuspend', 'ontimeupdate', 'ontoggle', 'onvolumechange', 'onwaiting'
|
||||
])
|
||||
|
||||
DASHED_ATTRIBUTES = set([
|
||||
'accent', 'alignment', 'arabic', 'baseline', 'cap', 'clip', 'color', 'dominant', 'enable', 'fill', 'flood',
|
||||
'font', 'glyph', 'horiz', 'image', 'letter', 'lighting', 'marker', 'overline', 'paint', 'panose', 'pointer',
|
||||
'rendering', 'shape', 'stop', 'strikethrough', 'stroke', 'text', 'underline', 'unicode', 'units', 'v', 'vector',
|
||||
'vert', 'word', 'writing', 'x'
|
||||
])
|
||||
|
||||
|
||||
# https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
|
||||
class svg_tag(html_tag):
|
||||
@staticmethod
|
||||
def clean_attribute(attribute):
|
||||
attribute = html_tag.clean_attribute(attribute)
|
||||
words = attribute.split('_')
|
||||
if words[0] in DASHED_ATTRIBUTES:
|
||||
return attribute.replace('_', '-')
|
||||
return attribute
|
||||
|
||||
|
||||
class svg(svg_tag):
|
||||
pass
|
||||
|
||||
|
||||
class animate(svg_tag):
|
||||
'''
|
||||
The animate SVG element is used to animate an attribute or property of an element over time.
|
||||
It's normally inserted inside the element or referenced by the href attribute of the target element.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class animateMotion(svg_tag):
|
||||
'''
|
||||
The <animateMotion> element causes a referenced element to move along a motion path.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class animateTransform(svg_tag):
|
||||
'''
|
||||
The animateTransform element animates a transformation attribute on its target element, thereby allowing
|
||||
animations to control translation, scaling, rotation, and/or skewing.
|
||||
'''
|
||||
is_single = True
|
||||
|
||||
|
||||
class circle(svg_tag):
|
||||
'''
|
||||
The <circle> SVG element is an SVG basic shape, used to draw circles based on a center point and a radius.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class clipPath(svg_tag):
|
||||
'''
|
||||
The <clipPath> SVG element defines a clipping path, to be used used by the clip-path property.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class defs(svg_tag):
|
||||
'''
|
||||
The <defs> element is used to store graphical objects that will be used at a later time. Objects created inside a
|
||||
<defs> element are not rendered directly. To display them you have to reference them
|
||||
(with a <use> element for example).
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class desc(svg_tag):
|
||||
'''
|
||||
The <desc> element provides an accessible, long-text description of any SVG container element or graphics element.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class ellipse(svg_tag):
|
||||
'''
|
||||
An ellipse element for svg containers
|
||||
'''
|
||||
pass
|
||||
|
||||
# (Note, filters are at the bottom of this file)
|
||||
|
||||
class g(svg_tag):
|
||||
'''
|
||||
The <g> SVG element is a container used to group other SVG elements.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class image(svg_tag):
|
||||
'''
|
||||
The <image> SVG element includes images inside SVG documents. It can display raster image files or other SVG files.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class line(svg_tag):
|
||||
'''
|
||||
The <line> element is an SVG basic shape used to create a line connecting two points.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class linearGradient(svg_tag):
|
||||
'''
|
||||
The <linearGradient> element lets authors define linear gradients that can be applied to fill or
|
||||
stroke of graphical elements.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class marker(svg_tag):
|
||||
'''
|
||||
The <marker> element defines the graphic that is to be used for drawing arrowheads or polymarkers on a given <path>, <line>, <polyline> or <polygon> element.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class mask(svg_tag):
|
||||
'''
|
||||
The <mask> element defines an alpha mask for compositing the current object into the background.
|
||||
A mask is used/referenced using the mask property.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class mpath(svg_tag):
|
||||
'''
|
||||
The <mpath> sub-element for the <animateMotion> element provides the ability to reference an
|
||||
external <path> element as the definition of a motion path.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class pattern(svg_tag):
|
||||
'''
|
||||
The <pattern> element defines a graphics object which can be redrawn at repeated x and y-coordinate
|
||||
intervals ("tiled") to cover an area.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class polygon(svg_tag):
|
||||
'''
|
||||
A polygon element for svg containers
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class polyline(svg_tag):
|
||||
'''
|
||||
A polyline element for svg containers
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class radialGradient(svg_tag):
|
||||
'''
|
||||
The <radialGradient> element lets authors define radial gradients that can be applied to fill
|
||||
or stroke of graphical elements.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class tspan(svg_tag):
|
||||
'''
|
||||
The SVG <tspan> element define a subtext within a <text> element or another <tspan> element.
|
||||
It allows to adjust the style and/or position of that subtext as needed.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class path(svg_tag):
|
||||
'''
|
||||
A path element for svg containers
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class rect(svg_tag):
|
||||
'''
|
||||
A rectangle element for svg containers
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class stop(svg_tag):
|
||||
'''
|
||||
The SVG <stop> element defines a color and its position to use on a gradient.
|
||||
This element is always a child of a <linearGradient> or <radialGradient> element.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class switch(svg_tag):
|
||||
'''
|
||||
The <switch> SVG element evaluates any requiredFeatures, requiredExtensions and systemLanguage attributes
|
||||
on its direct child elements in order, and then renders the first child where these attributes evaluate to true.
|
||||
Other direct children will be bypassed and therefore not rendered. If a child element is a container element,
|
||||
like <g>, then its subtree is also processed/rendered or bypassed/not rendered.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class symbol(svg_tag):
|
||||
'''
|
||||
The use of symbol elements for graphics that are used multiple times in the same document adds structure and
|
||||
semantics. Documents that are rich in structure may be rendered graphically, as speech, or as Braille,
|
||||
and thus promote accessibility.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class text(svg_tag):
|
||||
'''
|
||||
The SVG <text> element draws a graphics element consisting of text. It's possible to apply a gradient,
|
||||
pattern, clipping path, mask, or filter to <text>, like any other SVG graphics element.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class textPath(svg_tag):
|
||||
'''
|
||||
To render text along the shape of a <path>, enclose the text in a <textPath> element that has an href
|
||||
attribute with a reference to the <path> element.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class title(svg_tag):
|
||||
'''
|
||||
The <title> element provides an accessible, short-text description of any SVG container
|
||||
element or graphics element.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class tspan(svg_tag):
|
||||
'''
|
||||
The SVG <tspan> element define a subtext within a <text> element or another <tspan> element.
|
||||
It allows to adjust the style and/or position of that subtext as needed.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class use(svg_tag):
|
||||
'''
|
||||
The <use> element takes nodes from within the SVG document, and duplicates them somewhere else.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class view(svg_tag):
|
||||
'''
|
||||
A view is a defined way to view the image, like a zoom level or a detail view.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
# FILTERS
|
||||
class filter(svg_tag):
|
||||
pass
|
||||
|
||||
class feBlend(svg_tag):
|
||||
pass
|
||||
|
||||
class feColorMatrix(svg_tag):
|
||||
pass
|
||||
|
||||
class feComponentTransfer(svg_tag):
|
||||
pass
|
||||
|
||||
class feComposite(svg_tag):
|
||||
pass
|
||||
|
||||
class feConvolveMatrix(svg_tag):
|
||||
pass
|
||||
|
||||
class feDiffuseLighting(svg_tag):
|
||||
pass
|
||||
|
||||
class feDisplacementMap(svg_tag):
|
||||
pass
|
||||
|
||||
class feFlood(svg_tag):
|
||||
pass
|
||||
|
||||
class feGaussianBlur(svg_tag):
|
||||
pass
|
||||
|
||||
class feImage(svg_tag):
|
||||
pass
|
||||
|
||||
class feMerge(svg_tag):
|
||||
pass
|
||||
|
||||
class feMorphology(svg_tag):
|
||||
pass
|
||||
|
||||
class feOffset(svg_tag):
|
||||
pass
|
||||
|
||||
class feSpecularLighting(svg_tag):
|
||||
pass
|
||||
|
||||
class feTile(svg_tag):
|
||||
pass
|
||||
|
||||
class feTurbulence(svg_tag):
|
||||
pass
|
||||
|
||||
class feDistantLight(svg_tag):
|
||||
pass
|
||||
|
||||
class fePointLight(svg_tag):
|
||||
pass
|
||||
|
||||
class feSpotLight(svg_tag):
|
||||
pass
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,173 @@
|
||||
'''
|
||||
Utility classes for creating dynamic html documents
|
||||
'''
|
||||
|
||||
__license__ = '''
|
||||
This file is part of Dominate.
|
||||
|
||||
Dominate is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Dominate is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with Dominate. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
import re
|
||||
|
||||
from .dom_tag import dom_tag
|
||||
|
||||
try:
|
||||
basestring = basestring
|
||||
except NameError:
|
||||
basestring = str
|
||||
unichr = chr
|
||||
|
||||
|
||||
def include(f):
|
||||
'''
|
||||
includes the contents of a file on disk.
|
||||
takes a filename
|
||||
'''
|
||||
fl = open(f, 'r')
|
||||
data = fl.read()
|
||||
fl.close()
|
||||
return raw(data)
|
||||
|
||||
|
||||
def system(cmd, data=None):
|
||||
'''
|
||||
pipes the output of a program
|
||||
'''
|
||||
import subprocess
|
||||
s = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||
out, err = s.communicate(data)
|
||||
return out.decode('utf8')
|
||||
|
||||
|
||||
def escape(data, quote=True): # stolen from std lib cgi
|
||||
'''
|
||||
Escapes special characters into their html entities
|
||||
Replace special characters "&", "<" and ">" to HTML-safe sequences.
|
||||
If the optional flag quote is true, the quotation mark character (")
|
||||
is also translated.
|
||||
|
||||
This is used to escape content that appears in the body of an HTML document
|
||||
'''
|
||||
data = data.replace("&", "&") # Must be done first!
|
||||
data = data.replace("<", "<")
|
||||
data = data.replace(">", ">")
|
||||
if quote:
|
||||
data = data.replace('"', """)
|
||||
return data
|
||||
|
||||
|
||||
_unescape = {
|
||||
'quot': 34,
|
||||
'amp': 38,
|
||||
'lt': 60,
|
||||
'gt': 62,
|
||||
'nbsp': 32,
|
||||
# more here
|
||||
# http://www.w3.org/TR/html4/sgml/entities.html
|
||||
'yuml': 255,
|
||||
}
|
||||
str_escape = escape
|
||||
|
||||
|
||||
def unescape(data):
|
||||
'''
|
||||
unescapes html entities. the opposite of escape.
|
||||
'''
|
||||
cc = re.compile(r'&(?:(?:#(\d+))|([^;]+));')
|
||||
|
||||
result = []
|
||||
m = cc.search(data)
|
||||
while m:
|
||||
result.append(data[0:m.start()])
|
||||
d = m.group(1)
|
||||
if d:
|
||||
d = int(d)
|
||||
result.append(unichr(d))
|
||||
else:
|
||||
d = _unescape.get(m.group(2), ord('?'))
|
||||
result.append(unichr(d))
|
||||
|
||||
data = data[m.end():]
|
||||
m = cc.search(data)
|
||||
|
||||
result.append(data)
|
||||
return ''.join(result)
|
||||
|
||||
|
||||
_reserved = ";/?:@&=+$, "
|
||||
_replace_map = dict((c, '%%%2X' % ord(c)) for c in _reserved)
|
||||
|
||||
|
||||
def url_escape(data):
|
||||
return ''.join(_replace_map.get(c, c) for c in data)
|
||||
|
||||
|
||||
def url_unescape(data):
|
||||
return re.sub('%([0-9a-fA-F]{2})',
|
||||
lambda m: unichr(int(m.group(1), 16)), data)
|
||||
|
||||
|
||||
class lazy(dom_tag):
|
||||
'''
|
||||
delays function execution until rendered
|
||||
'''
|
||||
def __new__(_cls, *args, **kwargs):
|
||||
'''
|
||||
Need to reset this special method or else
|
||||
dom_tag will think it's being used as a dectorator.
|
||||
|
||||
This means lazy() can't be used as a dectorator, but
|
||||
thinking about when you might want that just confuses me.
|
||||
'''
|
||||
return object.__new__(_cls)
|
||||
|
||||
def __init__(self, func, *args, **kwargs):
|
||||
super(lazy, self).__init__()
|
||||
self.func = func
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
|
||||
def _render(self, sb, *a, **kw):
|
||||
r = self.func(*self.args, **self.kwargs)
|
||||
sb.append(str(r))
|
||||
|
||||
|
||||
# TODO rename this to raw?
|
||||
class text(dom_tag):
|
||||
'''
|
||||
Just a string. useful for inside context managers
|
||||
'''
|
||||
is_pretty = False
|
||||
is_inline = True
|
||||
|
||||
def __init__(self, _text, escape=True):
|
||||
super(text, self).__init__()
|
||||
if escape:
|
||||
self.text = str_escape(_text)
|
||||
else:
|
||||
self.text = _text
|
||||
|
||||
def _render(self, sb, *a, **kw):
|
||||
sb.append(self.text)
|
||||
return sb
|
||||
|
||||
|
||||
def raw(s):
|
||||
'''
|
||||
Inserts a raw string into the DOM. Unsafe.
|
||||
'''
|
||||
return text(s, escape=False)
|
||||
Reference in New Issue
Block a user