0
votes

I need a component that would;

  1. Work within a web page to allow a nontechnical user to create and edit templates for customized reports.
  2. Allow the user to easily place a set of pre-defined template data tokens in the report that conforms to the templating engine syntax without the user needing to know how to write the syntax themselves.
  3. Support the ability to change and update data items that can be used in the report without extensive rewriting of the code or creating a new plugin.

The goal is for end users to create their own personalized templates for a specific set of JSON data. The ability to create templates would be available on a web page and the templates would be stored for later use. Storing and using the templates is not a problem, but an easy to use editor for the templates is.

I have been using jsRender for a templating engine and like it but I am open to other engines if what I need is easier to support.

My goal is to have an online editor, similar to MCE or CKEditor, that would have the ability to place a preset list of data tokens into a custom template the user creates. These templates would be used for auto-generated content based on the data supplied to the template engine.

The solution needs to be fairly simple on the user side. The user skills could range from "Not Ignorant" up to "Almost Programmer". I would like to avoid anything that involves the user actually having to learn to hand write HTML, understand jsRender or other template library syntax. A drop down list of insertable data would be ideal.

I don't see much need for any complex logic syntax. My need is basic data token replacement, not any complex logic.

1
Explain that you want to make a text editor like CKEditor? Why? You can embed CKEditorin your project. - Codd Wrench
@CoddWrench No, I am looking for an editor such as CKEditor that could be used in a website to allow a user (non-programmer) to create their own templates. It would need to have some understanding of how the template engines work and allow the placement of data within the template. These templates would be used to generate output at a later time. - drobertson

1 Answers

0
votes

You can use jsviews + inner jsrender.

Create custom tag:

$.views.tags({
    render : {
        isUpdate : false,
        init : function (tagCtx, linkCtx) {
            var tag = this;
            tag._template = tagCtx.args[0];
            tag._data = tagCtx.args[1];
            tag.template = "<div class='content'></div>";
        },
        _render : function () {
            var tag = this;
            var template = $.templates(tag._template.text);
            tag.linkedElem.html(template.render(tag._data));
        },
        onUpdateTemplate : function () {
            this._render();
        },
        onUpdateData : function () {
            this._render();
        },
        onAfterLink : function (tagCtx, linkCtx) {
            var tag = this;
            tag._template = tagCtx.args[0];
            tag._data = tagCtx.args[1];

            if (tag._.unlinked) {
                if (!tag.linkedElem) {
                    tag.linkedElem = tag._.inline ? tag.contents("*").first() : $(linkCtx.elem);
                }
                $.observable(tag._template).observeAll($.proxy(tag.onUpdateTemplate, tag));
                $.observable(tag._data).observeAll($.proxy(tag.onUpdateData, tag));
            } else {

                $.observable(tag._template).unobserveAll($.proxy(tag.onUpdateTemplate, tag));
                $.observable(tag._data).unobserveAll($.proxy(tag.onUpdateData, tag));
                $.observable(tag._template).observeAll($.proxy(tag.onUpdateTemplate, tag));
                $.observable(tag._data).observeAll($.proxy(tag.onUpdateData, tag));
            }

            tag._render();
        },
        onDispose : function () {
            debugger;
            var tag = this;
            $.observable(tag._template).unobserveAll($.proxy(tag.onUpdateTemplate, tag));
            $.observable(tag._data).unobserveAll($.proxy(tag.onUpdateData, tag));
        },
        onUpdate : function () {
            return false;
        },
        dataBoundOnly : true
    }
});

Create html:

<div id="page"></div>

<script id="templateEditor" type="text/x-jsrender">
    <select data-link="selectedTemplate">
        <option value="-">Please select</option>
        {^{for templates}}
            <option data-link="value{:#index} {:name} selected{:#index == ~root.selectedTemplate}"></option>
        {{/for}}
    </select>

    <button data-link="{on addNew}">Add</button>

    <br/>
    <br/>

    {^{if selectedTemplate!=="-"}}
        template Name:<input data-link="templates[selectedTemplate].name" />
        <br/>
        <br/>
        <textarea name="template" cols="40" rows="5" data-link="templates[selectedTemplate].text trigger=true"></textarea>
    {{/if}}

    <br/>
    <br/>

    {^{if selectedTemplate!=="-"}}
        {^{render templates[selectedTemplate] data/}}
    {{/if}}
</script>

And add app code:

var app = {
    data : {
        value : "test"
    },
    templates : [{
            name : "Main",
            text : "<span>{{:value}}</span>"
        }
    ],
    selectedTemplate : 0,
    addNew : function () {
        $.observable(this.templates).insert({
            name : "new",
            text : ""
        });

    }
};

$([app.templates]).on("arrayChange", function (o, e) {
    if (e.change === "insert") {
        $.observable(app).setProperty("selectedTemplate", e.index);
    }
});
var templateEditor = $.templates("#templateEditor");
templateEditor.link("#page", app);

see live example on jsfiddle

Update 1:

I don't see much need for any complex logic syntax. My need is basic data token replacement, not any complex logic.

If you do not want to use jsRender use this code:

function template(str, data) {
    return str.replace(/%(\w*)%/g, function (m, key) {
        return data.hasOwnProperty(key) ? data[key] : "";
    });
}

example on jsfiddle