svghmi/gen_index_xhtml.ysl2
author Edouard Tisserant
Thu, 10 Oct 2019 09:54:44 +0200
branchsvghmi
changeset 2795 c0cf62bb9aa7
parent 2794 c10069a02ed0
child 2796 c7a22ce8c156
permissions -rw-r--r--
SVGHMI compute default page
include yslt_noindent.yml2

// overrides yslt's output function to set CDATA
decl output(method, cdata-section-elements="script");

istylesheet
            /* From Inkscape */
            xmlns:dc="http://purl.org/dc/elements/1.1/"
            xmlns:cc="http://creativecommons.org/ns#"
            xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
            xmlns:svg="http://www.w3.org/2000/svg"
            xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
            xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"

            /* Our namespace to invoke python code */
            xmlns:ns="beremiz"
            extension-element-prefixes="ns func"
            exclude-result-prefixes="ns str regexp exsl func" {

    /* This retrieves geometry obtained through "inkscape -S"
     * already parsed by python and presented as a list of
     * <bbox x="0" y="0" w="42" h="42">
     */
    const "geometry", "ns:GetSVGGeometry()";
    const "hmitree", "ns:GetHMITree()";

    const "hmi_elements", "//*[starts-with(@inkscape:label, 'HMI:')]";
    const "hmi_geometry", "$geometry[@Id = $hmi_elements/@id]";

    const "hmi_pages", "$hmi_elements[func:parselabel(@inkscape:label)/widget/@type = 'Page']";

    const "default_page" choose {
        when "count($hmi_pages) > 1" {
            const "Home_page", 
                "$hmi_pages[func:parselabel(@inkscape:label)/widget/arg[1]/@value = 'Home']";
            choose {
                when "$Home_page" > Home
                otherwise {
                    error "No Home page defined!";
                }
            }
        }
        when "count($hmi_pages) = 0" {
            error "No page defined!";
        }
        otherwise > «func:parselabel($hmi_pages/@inkscape:label)/widget/arg[1]/@value»
    }

    const "_categories" {
        noindex > HMI_ROOT
        noindex > HMI_LABEL
        noindex > HMI_CLASS
        noindex > HMI_PLC_STATUS
        noindex > HMI_CURRENT_PAGE
    }
    const "categories", "exsl:node-set($_categories)";
    const "_indexed_hmitree" apply "$hmitree", mode="index";
    const "indexed_hmitree", "exsl:node-set($_indexed_hmitree)";

    template "*", mode="index" {
        param "index", "0";
        param "parentpath", "''";
        const "content" {
            const "path"
                choose {
                    when "local-name() = 'HMI_ROOT'" > «$parentpath»
                    otherwise > «$parentpath»/«@name»
                }
            choose {
                when "not(local-name() = $categories/noindex)" {
                    xsl:copy {
                        attrib "index" > «$index»
                        attrib "hmipath" > «$path»
                        foreach "@*" xsl:copy;
                    }
                    /* no node expected below value nodes */
                }
                otherwise {
                    apply "*[1]", mode="index"{
                        with "index", "$index";
                        with "parentpath" > «$path»
                    }
                }
            }
        }

        copy "$content";
        apply "following-sibling::*[1]", mode="index" {
            with "index", "$index + count(exsl:node-set($content)/*)";
            with "parentpath" > «$parentpath»
        }
    }

    /* Identity template :
     *  - copy every attributes 
     *  - copy every sub-elements
     */
    template "@* | node()", mode="identity_svg" {
      /* use real xsl:copy instead copy-of alias from yslt.yml2 */
      xsl:copy apply "@* | node()", mode="identity_svg";
    }

    /*const "mark" > =HMI=\n*/

    /* copy root node and add geometry as comment for a test */
    template "/" { 
        comment > Made with SVGHMI. https://beremiz.org
        html xmlns="http://www.w3.org/1999/xhtml" {
            head;
            body style="margin:0;" {
                xsl:copy {
                    comment {
                        apply "$hmi_geometry", mode="testgeo";
                    }
                    comment {
                        apply "$hmitree", mode="testtree";
                    }
                    comment {
                        apply "$indexed_hmitree", mode="testtree";
                    }
                    apply "@* | node()", mode="identity_svg";
                }
                script{
                    call "scripts";
                }
            }
        }
    }

    func:function name="func:parselabel" {
        param "label";
        const "description", "substring-after($label,'HMI:')";

        const "_args", "substring-before($description,'@')";
        const "args" choose {
            when "$_args" value "$_args";
            otherwise value "$description";
        }

        const "_type", "substring-before($args,':')";
        const "type" choose {
            when "$_type" value "$_type";
            otherwise value "$args";
        }

        const "ast" if "$type" widget {
            attrib "type" > «$type»
            foreach "str:split(substring-after($args, ':'), ':')" {
                arg {
                    attrib "value" > «.»
                }
            }
            const "paths", "substring-after($description,'@')";
            foreach "str:split($paths, '@')" {
                path {
                    attrib "value" > «.»
                }
            }
        }

        func:result select="exsl:node-set($ast)"
    }

    function "scripts"
    {
        /* TODO : paste hmitree hash stored in hmi tree root node */

        /* TODO re-enable
        ||
        function evaluate_js_from_descriptions() {
            var Page;
            var Input;
            var Display;
            var res = [];
        ||
        const "midmark" > \n«$mark»
        apply """//*[contains(child::svg:desc, $midmark) or \
                     starts-with(child::svg:desc, $mark)]""",2 
              mode="code_from_descs";
        ||
            return res;
        }
        ||
        */

        /*TODO add :
          - pages content
            + with ref to elt ?
          - widgets parameters
        */

        | var hmi_index = {

        const "svg","/"; /* foreach loses document root */
        foreach "$indexed_hmitree/*" {
            | «@index»: {
            |     name: "«@name»",
            |     hmipath: "«@hmipath»"
            |     ids: [
            const "hmipath","@hmipath";
            foreach "$svg//*[substring-after(@inkscape:label,'@') = $hmipath]" {
            |         "«@id»"`if "position()!=last()" > ,`
            }
            |     ]
            | }`if "position()!=last()" > ,`
        }

        | }
        |
        | var page_desc = {

        foreach "$hmi_pages" {
            const "desc", "func:parselabel(@inkscape:label)/widget";
            |     "«$desc/arg[1]/@value»": {
            |         id: "«@id»",
            |         widgets: [
            const "page", "."; 
            const "p", "$hmi_geometry[@Id = $page/@id]"; 
            foreach """$hmi_geometry[@Id != $page/@id and 
                       @x >= $p/@x and @y >= $p/@y and 
                       @w <= $p/@w and @h <= $p/@h]""" {
                |             "«@Id»"`if "position()!=last()" > ,`
            }
            |         ]
        }
        | }

        |
        | var default_page = "«$default_page»";

        include text svghmi.js
    }

    /*
        Parses:
        "HMI:WidgetType:param1:param2@path1@path2"

        Into:
        widget type="WidgetType" {
            arg value="param1";
            arg value="param2";
            path value="path1";
            path value="path2";
        }
    */

    template "*", mode="page_desc" {
    }

    template "*", mode="code_from_descs" {
        ||
        {
            var path, role, name, priv;
            var id = "«@id»";
        ||

        /* if label is used, use it as default name */
        if "@inkscape:label"
            |> name = "«@inkscape:label»";

        | /* -------------- */

        // this breaks indent, but fixing indent could break string literals
        value "substring-after(svg:desc, $mark)";
        // nobody reads generated code anyhow...

        ||

            /* -------------- */
            res.push({
                path:path,
                role:role,
                name:name,
                priv:priv
            })
        }
        ||
    }


    template "bbox", mode="testgeo"{
        | ID: «@Id» x: «@x» y: «@y» w: «@w» h: «@h»
    }

    template "*", mode="testtree"{
        param "indent", "''";
        > «$indent» «local-name()» 
        foreach "@*" > «local-name()»=«.» 
        > \n
        apply "*", mode="testtree" {
            with "indent" value "concat($indent,'>')"
        };
    }
}