From edbc8fac9b78381b6269d59b9b07f4671f09552b Mon Sep 17 00:00:00 2001 From: amitk Date: Sat, 29 Nov 2014 23:32:00 +0200 Subject: [PATCH] Added rt-props --- README.md | 29 +++++++++++++++++++++++++++++ src/reactTemplates.js | 5 +++++ test/data/props.rt | 2 ++ test/data/props.rt.html | 1 + test/src/test.js | 4 ++-- 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 test/data/props.rt create mode 100644 test/data/props.rt.html diff --git a/README.md b/README.md index e9869a0..b4f070b 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ http://wix.github.io/react-templates/ * rt-if * rt-repeat * rt-scope +* rt-props * rt-class * style * event handlers @@ -140,6 +141,34 @@ define([ }); ``` +## rt-props +This directive is used to inject properties to an element programmatically. It will merge the properties with the properties received in the template. This option allows the code writer to build properties based on some app logic and pass them to the template. It is also useful when passing properties set on the component to an element within the template. The expected value of this attribute is an expression returning an object. The keys will be the properties and the values will be the property values. + +###### Sample: +```html + +``` +###### Compiled: +```javascript +define([ + 'react', + 'lodash' +], function (React, _) { + 'use strict'; + return function () { + return React.DOM.input(_.merge({}, { + 'style': { + height: '10px', + width: '3px' + } + }, { + style: { width: '5px' }, + type: 'text' + })); + }; +}); +``` + ## rt-class In order to reduce the boiler-plate code when programatically setting class names, you can use the rt-class directive. It expectes to get a JSON object with keys as class names, and a value of true or false as the value. If the value is true, the class name will be included. Please note the following: 1. In react templates, you can use the "class" attribute the same as you'd do in html. If you like, you can even have execution context within diff --git a/src/reactTemplates.js b/src/reactTemplates.js index 7482ec0..e30af05 100644 --- a/src/reactTemplates.js +++ b/src/reactTemplates.js @@ -11,6 +11,7 @@ var stringUtils = require('./stringUtils'); var repeatTemplate = _.template('_.map(<%= collection %>,<%= repeatFunction %>.bind(<%= repeatBinds %>))'); var ifTemplate = _.template('((<%= condition %>)?(<%= body %>):null)'); +var propsTemplate = _.template('_.merge({}, <%= generatedProps %>, <%= rtProps %>)'); var classSetTemplate = _.template('React.addons.classSet(<%= classSet %>)'); var simpleTagTemplate = _.template('<%= name %>(<%= props %><%= children %>)'); var tagTemplate = _.template('<%= name %>.apply(this,_.flatten([<%= props %><%= children %>]))'); @@ -22,6 +23,7 @@ var templateProp = 'rt-repeat'; var ifProp = 'rt-if'; var classSetProp = 'rt-class'; var scopeProp = 'rt-scope'; +var propsProp = 'rt-props'; var reactSupportedAttributes = ['accept', 'acceptCharset', 'accessKey', 'action', 'allowFullScreen', 'allowTransparency', 'alt', 'async', 'autoComplete', 'autoPlay', 'cellPadding', 'cellSpacing', 'charSet', 'checked', 'classID', 'className', 'cols', 'colSpan', 'content', 'contentEditable', 'contextMenu', 'controls', 'coords', 'crossOrigin', 'data', 'dateTime', 'defer', 'dir', 'disabled', 'download', 'draggable', 'encType', 'form', 'formNoValidate', 'frameBorder', 'height', 'hidden', 'href', 'hrefLang', 'htmlFor', 'httpEquiv', 'icon', 'id', 'label', 'lang', 'list', 'loop', 'manifest', 'max', 'maxLength', 'media', 'mediaGroup', 'method', 'min', 'multiple', 'muted', 'name', 'noValidate', 'open', 'pattern', 'placeholder', 'poster', 'preload', 'radioGroup', 'readOnly', 'rel', 'required', 'role', 'rows', 'rowSpan', 'sandbox', 'scope', 'scrolling', 'seamless', 'selected', 'shape', 'size', 'sizes', 'span', 'spellCheck', 'src', 'srcDoc', 'srcSet', 'start', 'step', 'style', 'tabIndex', 'target', 'title', 'type', 'useMap', 'value', 'width', 'wmode']; var attributesMapping = {'class': 'className', 'rt-class': 'className'}; @@ -261,6 +263,9 @@ function convertHtmlToReact(node, context) { stringUtils.addIfNotThere(context.boundParams, data.item + 'Index'); } data.props = generateProps(node, context); + if (node.attribs[propsProp]) { + data.props = propsTemplate({generatedProps: data.props, rtProps: node.attribs[propsProp]}); + } if (node.attribs[ifProp]) { data.condition = node.attribs[ifProp].trim(); } diff --git a/test/data/props.rt b/test/data/props.rt new file mode 100644 index 0000000..1e3504b --- /dev/null +++ b/test/data/props.rt @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/data/props.rt.html b/test/data/props.rt.html new file mode 100644 index 0000000..5aa998c --- /dev/null +++ b/test/data/props.rt.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/src/test.js b/test/src/test.js index 0e639c3..2a23719 100644 --- a/test/src/test.js +++ b/test/src/test.js @@ -36,7 +36,7 @@ function normalizeHtml(html) { } test('html tests', function (t) { - var files = ['scope.rt', 'lambda.rt','eval.rt']; + var files = ['scope.rt', 'lambda.rt','eval.rt', 'props.rt']; t.plan(files.length); files.forEach(check); @@ -81,7 +81,7 @@ test('util.isStale', function (t) { var mtime2 = new Date(1995, 11, 17, 3, 24, 1); fs.utimesSync(b, mtime2, mtime2); - var util = require('../../src/fsUtil'); + var fsUtil = require('../../src/fsUtil'); var actual = fsUtil.isStale(a, b); t.equal(actual, false); actual = fsUtil.isStale(b, a);