From ec34e42b87ed39ccb5d4f5b278be0ac73a77a55e Mon Sep 17 00:00:00 2001 From: Asko Nõmm Date: Tue, 31 Dec 2024 00:50:26 +0200 Subject: bump --- README.md | 391 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 390 insertions(+), 1 deletion(-) (limited to 'README.md') diff --git a/README.md b/README.md index 0d94bda..f6c31b7 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,393 @@ HTMTL (HyperText Markup _Templating_ Language) is a templating language that uses HTML attributes for its rendering logic. It is both a subset and superset of HTML, meaning that valid HTML is also valid HTMTL and valid HTMTL is also valid HTML, allowing -you to use any editor without needing any additional plugins. \ No newline at end of file +you to use any editor without needing any additional editor extensions. + +## Features + +- **Interpolation**: You can interpolate data from a data dictionary into your templates. +- **Modifiers**: You can modify the interpolated values using modifiers. +- **Conditionals**: You can show or hide blocks using expressions. +- **Partials**: You can include other templates inside your templates. +- **Loops**: You can loop over iterable data. +- **Extendable**: You can implement custom attribute parsers and expression modifiers. +- +## Example syntax + +```html + + + + + + +

+ +
+
+

+ +

+
+
+
+
+ + +``` + +## Installation + +``` +pip install htmtl +``` + +## Usage + +A simple example of how to use HTMTL with default configuration looks like this: + +```python +from htmtl import Htmtl + +htmtl = Htmtl('

', {'who': 'World'}) +html = htmtl.html() # returns:

Hello World

+``` + +## Attributes + +HTMTL works by parsing attributes in the template. + +### `inner-text` + +Sets the inner text of the element to the value of the attribute. + +HTMTL template where `title` key is `Hello, World!`: + +```html +

+``` + +Results in: + +```html +

Hello, World!

+``` + +### `inner-html` + +Sets the inner HTML of the element to the value of the attribute. + +HTMTL template where `content` key is `

Hello, World!

`: + +```html +
+``` + +Results in: + +```html +
+

Hello, World!

+
+``` + +### `inner-partial` + +Sets the inner HTML of the element to the value of the parsed HTMTL template. Inherits all the same data +as the parent template. + +HTMTL template with data such as: + +```python +data = { + 'title': 'My Web Portal Thing', + 'header': '

' +} +``` + +And where the template is: + +```html +
+``` + +Results in: + +```html +
+
+

My Web Portal Thing

+
+
+``` + +### `outer-text` + +Sets the outer text of the element to the value of the attribute. + +HTMTL template where `title` key is `Hello, World!`: + +```html +

+``` + +Results in: + +```html +Hello, World! +``` + +### `outer-html` + +Sets the outer HTML of the element to the value of the attribute. + +HTMTL template where `content` key is `

Hello, World!

`: + +```html +
+``` + +Results in: + +```html +

Hello, World!

+``` + +### `outer-partial` + +Sets the outer HTML of the element to the value of the parsed Toretto template. Inherits all the same data +as the parent template. + +HTMTL template with data such as: + +```python +data = { + 'title': 'My Web Portal Thing', + 'header': '

' +} +``` + +And where the template is: + +```html +
+``` + +Results in: + +```html +
+

My Web Portal Thing

+
+``` + +### `if` + +Removes the element if the attribute is false-y. + +HTMTL template where `show` key is `False`: + +```html +
Hello, World!
+``` + +Results in: + +```html + +``` + +### `unless` + +Removes the element if the attribute is truthy. + +HTMTL template where `hide` key is `True`: + +```html +
Hello, World!
+``` + +Results in: + +```html + +``` + +### `foreach` + +Loops anything iterable. + +For example, to loop over a collection of `posts` and then use `post` as the variable of each iteration, you can do something +like this: + +```php +
+

+
+``` + +If you do not care about using any of the iteration data, you can also entirely omit `as ...` from the expression, +like so: + +```php +
+ ... +
+``` + +And, you can also assign the key of the iteration to a variable, like so: + +```php +
+

+
+``` + +This would add the key of the iteration to as `post.index` variable, but you can name it whatever you want. + +### `:*` (Generic Value Attributes) + +You can use the `:*` attribute to set any attribute on an element to the interpolated value of the generic value attribute. + +For example, to set the `href` attribute of an element, you can use the `:href` attribute: + +```html +Hello, World! +``` + +Results in: + +```html +Hello, World! +``` + +If the `slug` key is `hello-world`. + +## Modifiers + +All interpolated values in expressions can be modified using modifiers. Modifiers are applied to the value of the attribute, and they can be chained, like so: + +```html +

+``` + +Note that if you have nothing other than the interpolated variable in the attribute, then you can omit the curly brackets, and so +this would also work: + +```html +

+``` + +### `date` + +Parses the value into a formatted date string. + +```html +

+``` + +### `truncate` + +Truncates the value to the specified length. + +```html +

+``` + +This also works on collections, so you can use `truncate` to limit items in an array as well. + +## Extending + +### Attribute Parsers + +You can add (or replace) attribute parsers in HTMTL when creating a new instance of the `Htmtl` class, like so: + +```python +from htmtl import Htmtl +from htmtl.attribute_parsers import InnerText + +htmtl = Htmtl('

', {'who': 'World'}) +htmtl.set_attribute_parsers([ + InnerText, +]) + +html = htmtl.html() # returns:

Hello World

+``` + +Attribute parsers must extend the `AttributeParser` class, like so: + +```python +from typing import Optional +from dompa.nodes import Node, TextNode +from htmtl import AttributeParser + + +class InnerText(AttributeParser): + def traverse(self, node: Node) -> Optional[Node]: + if "inner-text" in node.attributes: + node.children = [TextNode(value=self.expression(node.attributes["inner-text"]))] + node.attributes.pop("inner-text") + + return node +``` + +All attribute parsers traverse the entire DOM tree to do whatever DOM manipulation they want. It's important to know that +an attribute parser must have the `traverse` method, and it must return a `Node`, or `None` if you want to remove the `Node`. + +HTMTL is built upon the [Dompa](https://github.com/askonomm/dompa) HTML parser, so check that out for more granular info on things. + +#### List of built-in attribute parsers + +- `htmtl.attribute_parsers.GenericValue` - Parser the `:*` attributes. (**soon**) +- `htmtl.attribute_parsers.If` - Parser the `if` attributes. (**soon**) +- `htmtl.attribute_parsers.Unless` - Parser the `unless` attributes. (**soon**) +- `htmtl.attribute_parsers.InnerPartial` - Parser the `inner-partial` attributes. (**soon**) +- `htmtl.attribute_parsers.InnerHtml` - Parser the `inner-html` attributes. (**soon**) +- `htmtl.attribute_parsers.InnerText` - Parser the `inner-text` attributes. +- `htmtl.attribute_parsers.OuterPartial` - Parser the `outer-partial` attributes. (**soon**) +- `htmtl.attribute_parsers.OuterHtml` - Parser the `outer-html` attributes. (**soon**) +- `htmtl.attribute_parsers.OuterText` - Parser the `outer-text` attributes. +- `htmtl.attribute_parsers.Foreach` - Parses the `foreach` attributes. (**soon**) + +### Expression Modifiers + +You can add (or replace) expression modifiers in HTMTL when creating a new instance of the `Htmtl` class, like so: + +```python +from htmtl import Htmtl +from htmtl.expression_modifiers import Truncate + +htmtl = Htmtl('

', {'who': 'World'}) +htmtl.set_expression_modifiers([ + Truncate, +]) + +html = htmtl.html() # returns:

Hello World

+``` + +Expression modifiers must implement the `ExpressionModifier` class, like so: + +```python +from typing import Any +from htmtl import ExpressionModifier, modifier + + +@modifier("truncate") +class Truncate(ExpressionModifier): + def modify(self, value: Any, opts: list[Any]) -> Any: + if isinstance(value, str) and len(opts) > 0: + if all([x in "1234567890" for x in opts[0]]): + char_limit = int(opts[0]) + + if len(value) > char_limit: + return f"{value[:char_limit - 3]}..." + + return value +``` + +All expression modifiers need to have a name (that you will use in your templates), and you can name your modifier +with the `modifier` decorator. + +#### List of built-in expression modifiers + +- `htmtl.expression_modifiers.Truncate` - Truncates the value (both strings and collections). -- cgit v1.2.3