bayrell / BayLang

BayLang compiler source code
https://bayrell.org/ru/docs/baylang
Apache License 2.0
4 stars 0 forks source link

BayLang шаблоны #159

Open ildar-ceo opened 2 months ago

ildar-ceo commented 2 months ago

Необходимо поменять шаблонизатор. Шаблонизатор должен генерировать псевдокод HTML кода с параметром builder. Это нужно чтобы использовать один и тот же скомпилированный код шаблона в разных целях не меняя при этом транслятор.

Builder бывают разных типов:

VirtualDom может быть использован:

Пример:

/**
 * Returns default template
 */
static void getDefaultTemplate() =>
    <class>
        <use name='Runtime.Widget.Image' component='true' />
        <use name='Runtime.Widget.Text' component='true' />
        <template>
            <slot name='image'>
                <Image />
            </slot>
            <slot name='text'>
                <Text />
            </slot>
        </template>
    </class>
;

Это открывает путь для использования в разных целей. В том числе использовать HTML шаблоны вне компонентах, а например в моделях, когда нужно сделать генерацию кастомных полей в таблице.

ildar-ceo commented 2 months ago

Класс VirtualDom

class VirtualDom extends BaseStruct
{
    string name = "";
    Dict<var> attrs = {};
    Collection<var> items = [];

    /**
     * Create
     */
    VirtualDom create(string name, Dict<var> attrs = {}, Collection<var> items) =>
        new VirtualDom{
            "name": name,
            "attrs": attrs,
            "items": items,
        }
    ;
}

Интерфейс BuilderInterface

interface BuilderInterface
{
    /**
     * Create virtual node
     */
    BuilderInterface h(string name, Dict<var> attrs = {}, Collection<var> items);
}

Класс DocumentBuilder

class DocumentBuilder implements BuilderInterface
{
    VirtualDom node;

    /**
     * Create virtual node
     */
    DocumentBuilder h(string name, Dict<var> attrs = {}, Collection<var> items)
    {
        DocumentBuilder item = new DocumentBuilder();
        item.node = new VirtualDom{
            "name": name,
            "attrs": attrs,
            "items": items,
        };
        this.node.items.push(item.node);
        return item;
    }

    /**
     * Create element
     */
    var create()
    {
        if (this.node instanceof string) return this.createText(this.node);
        if (this.node instanceof VirtualDom) return this.createElement(this.node);
        return null;
    }

    /**
     * Create text element
     */
    var createText(string content)
    {
        return document.createTextNode(content);
    }

    /**
     * Create element
     */
    var createElement()
    {
        var elem = document.createElement(this.node.name);

        /* Set attributes */
        this.setAttrs(elem);

        /* Create items */
        this.createItems(elem);

        return elem;
    }

    /**
     * Set attributes
     */
    void setAttrs(var elem)
    {
        if (not this.node.attrs) return;

        this.node.attrs.each(void (var value, string key) use (elem){
            if (value instanceof primitive)
            {
                elem.setAttribute(key, value);
            }
        });
    }

    /**
     * Create items
     */
    void createItems(var elem)
    {
        if (not this.node.items) return;

        for (int i=0; i<this.node.items.count(); i++)
        {
            elem.appendChild(this.create(this.node.items.get(i)));
        }
    }

    /**
     * Patch HTML Element
     */
    var patchElement(var element)
    {
        element.replaceWith(this.create());
    }
}

Рендер функция

void render(BuilderInterface root)
{
    BuilderInterface container = root.h("div", {"class": "container"});
    container.h("h1", {"class": "title"}, ["Hello, World!"]);
    container.h("p", {}, ["Text content"]);
}

Создание HTML элементов

DocumentBuilder builder = new DocumentBuilder();
builder.node = new VirtualDom::create("div", {"class": "root"});

/* Patch VirtualDom by builder */
render(builder);

/* Create HTML Element root */
var root_elem = builder.create();

Патч HTML элементов

render(builder);
builder.patch(root_elem);

Преобразование VirtualDom в строку

StringBuilder string_builder = new StringBuilder();
string_builder.node = new VirtualDom::create("div", {"class": "root"});

/* Patch VirtualDom */
render(string_builder);

/* Generate HTML String */
Collection items = [];
string_builder.createItems(items);
print(string_builder.join(items));