All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.dist.module.compile.js Maven / Gradle / Ivy


import { Template, TemplateDOM } from "./type.js";
import { idl_attributes } from "./factory.js";

const event_types = {

    tap: 1,
    change: 1,
    click: 1,
    dblclick: 1,
    input: 1,
    keydown: 1,
    keypress: 1,
    keyup: 1,
    mousedown: 1,
    //"mouseenter": 1, // non-bubbling
    mouseover: 1,
    //"mouseleave": 1, // non-bubbling
    mouseout: 1,
    mousemove: 1,
    mouseup: 1,
    mousewheel: 1,
    touchstart: 1,
    touchmove: 1,
    touchend: 1,
    touchcancel: 1,
    reset: 1,
    select: 1,
    submit: 1,
    toggle: 1,
    //"focus": 1, // non-bubbling
    focusin: 1,
    //"blur": 1, // non-bubbling
    focusout: 1,
    resize: 1,
    scroll: 1,

    // non-bubbling events
    error: 1,
    load: 1
},
      event_bubble = {

    blur: "focusout",
    focus: "focusin",
    mouseleave: "mouseout",
    mouseenter: "mouseover"
};


// function escape_single_quotes(str){
//
//     return str.replace(/\\([\s\S])|(')/ig, "\\$1$2");
// }
//
// function escape_single_quotes_expression(str){
//
//     //console.log(str.replace(/{{(.*)?(\\)?([\s\S])|(')([^}]+)?/ig, "{{$1$2$3$4$5"))
//
//     return str.replace(/{{(.*)?(\\)?([\s\S])|(')(.*)?(}})/ig, "{{$1$2$3$4$5$6");
// }

function replaceComments(str) {

    return str.replace(//g, "");
}

function strip(str) {

    return str.replace(/({{|}})/g, "").trim();
}

let message = 0,
    counter = 0;


/**
 * @param {!string|HTMLTemplateElement|Element|Node} node
 * @param {boolean|Function=} callback
 * @param {Array|Function>=} _inc
 * @param {Array|Object=} _fn
 * @param {Object=} _index
 * @param {boolean|number=} _recursive
 * @return {Template|TemplateDOM|Promise}
 */

export default function compile(node, callback, _inc, _fn, _index, _recursive) {

    if (callback) {

        return new Promise(function (resolve) {

            const tpl = compile(node);
            if ("function" == typeof callback) callback(tpl);
            resolve(tpl);
        });
    }

    if (!_index) {

        _fn = /** @type {Object} */[];
        _inc = [_fn];
        _fn.index = _index = {

            // the actual index of element p[i]
            current: -1,

            // counts every index change (next element, style, text node)
            count: 0,

            // the value of the last index counter to identify if counter has increased
            // and current index should also be increased by 1
            last: -1,

            // the actual index of inc[i]
            inc: 0,

            // a state to identify if one of the 3 include types was applied
            included: !1

            // a cache to identify repeating template structures
            // not supported by the inline compiler
            //cache: {}
        };
    }

    const template = _recursive ? /** @type {TemplateDOM} */{} : /** @type {Template} */{
        tpl: /** @type {TemplateDOM} */{}
    },
          tpl = _recursive ? template : template.tpl;


    if (!_recursive) {

        if ("string" == typeof node) {

            if (/<.*>/.test(node)) {

                const tmp = document.createElement("div");
                tmp.innerHTML = node;
                node = tmp.firstElementChild;
            } else {

                template.name = node;
                node = document.getElementById(node);
            }
        }

        node = /** @type {HTMLTemplateElement} */node;

        if (node.content) {

            if (!template.name) {

                template.name = node.id || node.getAttribute("name");
            }

            node = node.content.firstElementChild;
        }
    }

    const tagName = node.tagName;

    if (!tagName || "SCRIPT" === tagName) {

        // a text node or inline code has no tag

        let value;

        if (value = (tagName ? node.firstChild : node).nodeValue) {

            if (value && value.trim()) {

                if (value.includes("{{@")) {

                    let js = value.replace(/{{@([\s\S]+)}}/g, "$1").trim();
                    value = /{{[\s\S]+}}/.test(js) ? js.replace(/{{([\s\S]+)}}/g, "{{$1}}") : "";
                    js && (js = js.replace(/{{([\s\S]+)}}/g, ""));
                    js && _fn.push(js);

                    // using the script tag allows the runtime compiler
                    // to place code to a specific place

                    if ("SCRIPT" === tagName) {

                        if (value.trim()) {

                            tpl.text = value;
                            tpl.tag = tagName;
                        }

                        return tpl;
                    }
                }

                if (value && value.trim()) {

                    //if(/{{[!?]?#/.test(value)){
                    if (value.includes("{{#")) {

                        handle_value(tpl, "html", value, !1, null, _index, _inc, _fn);
                    } else {

                        _index.count++;

                        handle_value(tpl, "text", value, !1, null, _index, _inc, _fn);
                    }
                }
            }
        }

        if (!tagName) {

            return (/*tpl.js ||*/value && value.trim() ? tpl : null
            );
        }
    }

    if (tagName) {

        tpl.tag = tagName;
    }

    let attributes = node.attributes;

    if (attributes && attributes.length) {

        const tmp = {};

        // collect and normalize attributes

        for (let i = 0; i < attributes.length; i++) {
            let attr_name = attributes[i].nodeName,
                attr_value = node.getAttribute(attr_name);


            // the foreach needs to be handled in the switch below,
            // otherwise it could collide with native "for" attribute

            // if(attr_name === "foreach") attr_name = "for";
            if ("include" === attr_name) attr_name = "inc";

            tmp[attr_name] = attr_value;
        }

        attributes = /** @type {TemplateDOM} */tmp;

        for (let attr_name in attributes) {
            let attr_value = attributes[attr_name],
                handler,
                attr;


            switch (attr_name) {

                case "class":
                case "style":

                    handler = attr_name;
                    break;

                case "include":

                    attr_name = "inc";
                // fallthrough

                case "inc":

                    handler = attr_name;
                    break;

                case "if":

                    handler = attr_name;
                    break;

                case "foreach":

                    attr_name = "for";
                    handler = attr_name;
                    break;

                case "js":

                    // is already pushed to fn stack
                    break;

                case "key":

                    template.key = strip(attr_value).replace("data.", "");
                    break;

                case "cache":

                    break;

                default:

                    if (event_bubble[attr_name]) {

                        attr = tpl.event || (tpl.event = {});

                        attr_name = event_bubble[attr_name];
                    } else if (event_types[attr_name]) {

                        attr = tpl.event || (tpl.event = {});
                    } else {

                        // derive template name from outer element when it is not a template
                        // skip, when it is an expression

                        if (!_recursive && ("id" === attr_name || "name" === attr_name) && !template.name) {

                            if (!/{{[\s\S]+}}/.test(attr_value)) {

                                template.name = attr_value;
                            }
                        }

                        attr = tpl.attr || (tpl.attr = {});
                    }

                    handler = attr_name;
            }

            if (handler) {

                handle_value(attr || tpl, handler, attr_value, !!attr, attributes, _index, _inc, _fn);
            }
        }
    }

    // from here all attributes was processed by handle_value()

    // process