improved UI, better samples

This commit is contained in:
ido 2014-12-30 10:42:31 +02:00
parent d2f459c505
commit bf3c5d550a
35 changed files with 706 additions and 292 deletions

View File

@ -61,7 +61,7 @@ module.exports = function (grunt) {
watch: {
rt: {
files: [
'playground/**/*.rt'
'playground/*.rt'
],
tasks: ['rt'],
options: {

View File

@ -9,6 +9,8 @@
<link rel="shortcut icon" href="https://facebook.github.io/react/favicon.ico">
<link href='http://fonts.googleapis.com/css?family=Lato:100,300,400,700' rel='stylesheet' type='text/css'>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<!-- Optional theme -->
@ -19,6 +21,7 @@
<link rel="stylesheet" href="playground/libs/codemirror-4.8/theme/solarized.css" />
<link rel="stylesheet" href="playground/libs/codemirror-4.8/addon/hint/show-hint.css">
<link rel="stylesheet" href="playground/libs/codemirror-4.8/addon/lint/lint.css">
<link rel="stylesheet" href="playground/css/playground.css"/>
<link rel="stylesheet" href="playground/css/fiddle.css"/>
</head>
<body>
@ -29,8 +32,12 @@
<!--<script src="https://cdn.firebase.com/js/client/2.0.5/firebase.js"></script>-->
<!--<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>-->
<!--<script src="playground/libs.browser.js"></script>-->
<script src="playground/rt-main.browser.js"></script>
<script src="playground/dist/rt-main.browser.js"></script>
<script data-main="playground/fiddle-main.js" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.js"></script>
<!--http://requirejs.org/docs/release/2.1.15/minified/require.js-->
<!--<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.min.js"></script>-->
<!--<script src="playground/dist/fiddle.min.js"></script>-->
<!--<script data-main="playground/dist/fiddle.min.js" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.js"></script>-->
</body>
</html>

View File

@ -10,6 +10,7 @@
<meta name="description" content="Light weight templates for React.">
<link rel="shortcut icon" href="https://facebook.github.io/react/favicon.ico">
<link href='http://fonts.googleapis.com/css?family=Lato:100,300,700' rel='stylesheet' type='text/css'>
<!--<link rel="alternate" type="application/rss+xml" title="React" href="http://facebook.github.io/react/feed.xml">-->
<!--<link rel="stylesheet" href="https://facebook.github.io/react/css/syntax.css">-->
@ -42,6 +43,7 @@
<link rel="stylesheet" href="playground/libs/codemirror-4.8/addon/hint/show-hint.css">
<link rel="stylesheet" href="playground/libs/codemirror-4.8/addon/lint/lint.css">
<link rel="stylesheet" href="playground/css/playground.css"/>
<link rel="stylesheet" href="playground/css/home.css"/>
</head>
<body>
@ -52,9 +54,10 @@
<div class="wrap">
<a class="nav-home" href="index.html">
<img class="nav-logo" src="https://wix.github.io/react-templates/img/logo-rt.svg" width="56" height="24">
React Templates
<span>React Templates</span>
</a>
<ul class="nav-site">
<li><a href="fiddle.html">Playground</a></li>
<li><a href="https://github.com/wix/react-templates">docs</a></li>
<!--<li><a href="https://github.com/wix/react-templates">support</a></li>-->
<li><a href="https://github.com/wix/react-templates">download</a></li>
@ -67,55 +70,33 @@
<div class="hero">
<div class="wrap">
<div class="text"><strong>React Templates</strong></div>
<div class="text">React Templates</div>
<div class="minitext">
Light weight templates for React
</div>
<div class="buttons-unit">
<a href="fiddle.html" class="button">RTFiddle</a>
<a href="fiddle.html" class="button">Checkout the Playground</a>
<!--<a href="/react/downloads.html" class="button">Download React v0.12.1</a>-->
</div>
</div>
</div>
<section class="content wrap">
<p><section class="light home-section">
<!--<div class="marketing-row">-->
<!--<div class="marketing-col">-->
<!--<h3>Just the UI</h3>-->
<!--<p>-->
<!--Lots of people use React as the V in MVC.-->
<!--Since React makes no assumptions about the rest of your technology stack,-->
<!--it&apos;s easy to try it out on a small feature in an existing project.-->
<!--</p>-->
<!--</div>-->
<!--<div class="marketing-col">-->
<!--<h3>Virtual DOM</h3>-->
<!--<p>-->
<!--React uses a <i>virtual DOM</i> diff implementation for ultra-high performance. It can also-->
<!--render on the server using Node.js &mdash; no heavy browser DOM required.-->
<!--</p>-->
<!--</div>-->
<!--<div class="marketing-col">-->
<!--<h3>Data flow</h3>-->
<!--<p>-->
<!--React implements one-way reactive data flow which reduces boilerplate and is-->
<!--easier to reason about than traditional data binding.-->
<!--</p>-->
<!--</div>-->
<!--</div>-->
<h3>Reasons that we love it:</h3>
<ul>
<section class="love-list">
<ul >
<li>No runtime libraries. No magic. Just simple pre-compilation to a clear React code</li>
<li>Super easy to write panels. By panels we mean components that have a lot of HTML code and non-reusable logic</li>
<li>Very good separation of presentation and logic. Almost no HTML within the component file</li>
<li>Declarative coding for presentation. HTML that you write and inspect look similar</li>
<li>Easy syntax. Similar to HTML. All IDEs recognize this format</li>
</ul>
</section>
<hr class="home-divider" />
<section id="home-section" class="home-section">
</section>
<div id="loading" style="/* padding-bottom: 40px; */

124
playground/CMLint.js Normal file
View File

@ -0,0 +1,124 @@
define(['react', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror'], function (React, _, $, CodeMirror) {
'use strict';
//var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
// lineNumbers: true,
// viewportMargin: Infinity,
// gutters: ['CodeMirror-linenumbers', 'GUTTER_ID']
//});
//
//editor.markText({line: 1, ch: 1}, {line: 1, ch: 10}, {className: 'editor-error'});
function annotationTooltip(ann) {
var severity = ann.severity;
if (!severity) {
severity = 'error';
}
var tip = document.createElement('div');
tip.className = 'CodeMirror-lint-message-' + severity;
tip.appendChild(document.createTextNode(ann.message));
return tip;
}
var GUTTER_ID = 'rt-annotations';
function annotate(editor, annot) {
if (annot.index) {
//posFromIndex
var pos = editor.findPosH({line: 0, ch: 0}, 25, 'char');
var range = editor.findWordAt(pos);
editor.markText(range.anchor, range.head, {className: 'editor-error'});
}
var tipLabel = /*state.hasGutter &&*/ document.createDocumentFragment();
var ann = {severity: 'error', message: annot.message};
tipLabel.appendChild(annotationTooltip(ann));
editor.setGutterMarker(Math.max(annot.line, 0), GUTTER_ID, makeMarker(tipLabel, 'error', false, 'state.options.tooltips'));
}
function clearMarks(cm) {
//var state = cm.state.lint;
//if (state.hasGutter) cm.clearGutter(GUTTER_ID);
//for (var i = 0; i < state.marked.length; ++i)
// state.marked[i].clear();
//state.marked.length = 0;
cm.clearGutter(GUTTER_ID);
}
function makeMarker(labels, severity, multiple, tooltips) {
var marker = document.createElement('div'), inner = marker;
marker.className = 'CodeMirror-lint-marker-' + severity;
if (multiple) {
inner = marker.appendChild(document.createElement('div'));
inner.className = 'CodeMirror-lint-marker-multiple';
}
if (tooltips !== false) {
CodeMirror.on(inner, 'mouseover', function(e) {
showTooltipFor(e, labels, inner);
});
}
return marker;
}
function showTooltip(e, content) {
var tt = document.createElement('div');
tt.className = 'CodeMirror-lint-tooltip';
tt.appendChild(content.cloneNode(true));
document.body.appendChild(tt);
function position(e) {
if (!tt.parentNode) {
return CodeMirror.off(document, 'mousemove', position);
}
tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + 'px';
tt.style.left = (e.clientX + 5) + 'px';
}
CodeMirror.on(document, 'mousemove', position);
position(e);
if (tt.style.opacity !== null) {
tt.style.opacity = 1;
}
return tt;
}
function rm(elt) {
if (elt.parentNode) {
elt.parentNode.removeChild(elt);
}
}
function hideTooltip(tt) {
if (!tt.parentNode) {
return;
}
if (tt.style.opacity == null) {
rm(tt);
}
tt.style.opacity = 0;
setTimeout(function() { rm(tt); }, 600);
}
function showTooltipFor(e, content, node) {
var tooltip = showTooltip(e, content);
function hide() {
CodeMirror.off(node, 'mouseout', hide);
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
}
var poll = setInterval(function() {
if (tooltip) {
for (var n = node;; n = n.parentNode) {
if (n == document.body) {
return;
}
if (!n) { hide(); break; }
}
}
if (!tooltip) {
return clearInterval(poll);
}
}, 400);
CodeMirror.on(node, 'mouseout', hide);
}
return {
GUTTER_ID: GUTTER_ID,
annotate: annotate,
clearMarks: clearMarks
};
});

View File

@ -1,4 +1,5 @@
define(['react', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror',
'./CMLint',
'./libs/codemirror-4.8/mode/javascript/javascript',
'./libs/codemirror-4.8/addon/hint/html-hint',
'./libs/codemirror-4.8/addon/hint/show-hint',
@ -9,7 +10,7 @@ define(['react', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror',
'./libs/codemirror-4.8/mode/css/css',
'./libs/codemirror-4.8/mode/htmlmixed/htmlmixed'
//'./libs/codemirror-4.8/addon/display/placeholder'
], function (React, _, $, CodeMirror) {
], function (React, _, $, CodeMirror, CMLint) {
'use strict';
//codeMirror: 'libs/codemirror-4.8/lib/codemirror',
//htmlmixed: 'libs/codemirror-4.8/mode/htmlmixed/htmlmixed',
@ -79,7 +80,7 @@ define(['react', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror',
var props = _.omit(this.props, ['ref', 'key', 'value', 'valueLink', 'onChange']);
props.id = this.props.id || this.state.editorId;
var value = this.props.valueLink ? this.props.valueLink() : this.props.value;
return React.DOM.textarea(props,value);
return React.DOM.textarea(props, value);
},
componentWillUpdate: function (nextProps/*, nextState*/) {
var value = nextProps.valueLink ? nextProps.valueLink() : nextProps.value;
@ -97,6 +98,7 @@ define(['react', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror',
value: value,
lineNumbers: true,
mode: 'javascript',
gutters: ['CodeMirror-linenumbers', 'rt-annotations'],
theme: 'solarized' //solarized_light solarized-light
};
@ -110,11 +112,11 @@ define(['react', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror',
'Ctrl-Space': 'autocomplete'
};
options.hintOptions = {schemaInfo: tags};
options.gutters = ['CodeMirror-lint-markers'];
//options.gutters = ['CodeMirror-lint-markers'];
options.lint = true;
} else {
options.mode = 'javascript';
options.gutters = ['CodeMirror-lint-markers'];
//options.gutters = ['CodeMirror-lint-markers'];
options.lint = true;
}
@ -131,13 +133,13 @@ define(['react', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror',
}
},
showMessage: function (msg) {
var anOption = document.createElement('div');
anOption.innerText = msg;
anOption.setAttribute('class', 'error-panel');
if (this.panel) {
this.panel.clear();
}
this.panel = this.editor.addPanel(anOption, {height: 22}); // {position: 'bottom'}
//var anOption = document.createElement('div');
//anOption.innerText = msg;
//anOption.setAttribute('class', 'error-panel');
//if (this.panel) {
// this.panel.clear();
//}
//this.panel = this.editor.addPanel(anOption, {height: 22}); // {position: 'bottom'}
},
clearMessage: function () {
if (this.panel) {
@ -145,6 +147,12 @@ define(['react', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror',
this.panel = null;
}
},
annotate: function (annot) {
CMLint.annotate(this.editor, annot);
},
clearAnnotations: function () {
CMLint.clearMarks(this.editor);
},
componentWillUnmount: function () {
this.editor.toTextArea();
}

View File

@ -4,7 +4,8 @@ html {
body {
/*padding: 20px;*/
font-family: "Helvetica", "Arial", "FreeSans", "Verdana", "Tahoma", "Lucida Sans", "Lucida Sans Unicode", "Luxi Sans", sans-serif;
font-family: 'Lato', sans-serif;
font-weight: 300;
/*background: #f6f6f6 url(../img/initializing.png) 50% 50% no-repeat;*/
/*overflow: hidden;*/
padding: 0;
@ -25,7 +26,7 @@ body {
bottom: 0;
left: 0;
right: 0;
background: #DFDFD5;
/*background: #DFDFD5;*/
}
#header {
@ -44,6 +45,13 @@ body {
display: inline-block;
}
.title-link{
float: left;
margin-top: -3px;
margin-right: 5px;
}
.title-link, .title-link:hover, .title-link:visited {
text-decoration: none;
color: #00d8ff;
@ -54,6 +62,10 @@ body {
display: inline-block;
}
#buttons-bar button{
font-weight:400;
}
#buttons-bar button, #buttons-bar div {
margin-right: 10px;
}
@ -66,6 +78,37 @@ body {
margin-right: 5px;
}
.nav-site{
position:absolute;
top:0;
right:0;
}
.nav-site li {
margin: 0;
display:inline-block;
}
.nav-site a {
padding: 0 8px;
text-transform: uppercase;
letter-spacing: 1px;
line-height: 50px;
display: inline-block;
height: 50px;
color: #aaa
}
.nav-site a:hover {
color: #fafafa
}
.nav-site a.active {
color: #fafafa;
border-bottom: 3px solid #cc7a6f;
background: #333
}
.fiddle {
height: 100%;
}
@ -81,17 +124,20 @@ body {
/*height: 300px;*/
/*display: block;*/
/*margin: 10px;*/
border: 1px solid #ddd;
border-radius: 4px 4px 4px 4px;
/*height: 400px;*/
/*min-height: 100px;*/
/*height: 100%;*/
/*margin: 10px;*/
}
.result-area {
width: 50%;
display: table-cell;
vertical-align: top;
padding: 5px;
}
.sample-view {
margin: 10px;
height:100%;
border: 1px solid #ddd;
background-color: #f8f8f5;
}
.sample-view button {
@ -103,26 +149,32 @@ body {
}
.playground {
display: table;
height: 100%;
width: 100%;
}
.fiddle-row {
display: table-row;
height: 50%;
.CodeMirror-wrap {
border:1px solid #ddd;
/*border-radius: 4px 4px 4px 4px;*/
/*height: 400px;*/
/*min-height: 100px;*/
/*height: 100%;*/
/*margin: 10px;*/
}
.fiddle-row{
overflow:hidden;
}
.code-area {
/*background-color: rgb(181, 181, 181);*/
width: 50%;
height: 50%;
/*height: 166px;*/
display: table-cell;
/*float: left;*/
/*margin: 2px;*/
/*padding: 10px;*/
padding: 1px;
float:left;
position:relative;
padding: 5px;
}
.result-area-form{
padding:5px;
}
.error-panel {
@ -134,4 +186,46 @@ body {
border-bottom: 1px solid #000;
}
/*position: relative; min-height: 100%;*/
.message {
position: absolute;
bottom: 500px;
left: 200px;
z-index: 30;
background-color: aliceblue;
opacity: 0.9;
}
/*position: relative; min-height: 100%;*/
.code-area::after{
content:'';
position:absolute;
top:5px;
right:5px;
font-size: 11px;
padding:2px 5px;
border:1px solid #ddd;
color: #b4b4b4;
background: rgba(255,255,255,0.5);
pointer-events:none;
transition: opacity 0.2s;
-webkit-transition: opacity 0.2s;
}
/*.code-area:hover::after{
opacity:0.2;
}*/
#area-rt::after{
content:'Template';
}
#area-code::after{
content:'Class';
}
#area-generated::after{
content:'Generated Code';
}
#area-result::after{
content:'Result';
}

View File

@ -1,8 +1,8 @@
html {
font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
font-family: proxima-nova, "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
body {
font-family: 'Lato', sans-serif;
font-weight: 300;
color: #484848;
line-height: 1.28
}
@ -464,31 +464,54 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
}
.hero {
height: 300px;
background: #2d2d2d;
padding-top: 50px;
color: #e9e9e9;
font-weight: 300
padding-bottom:60px;
background: #fff;
padding-top: 40px;
}
.hero .text {
font-size: 64px;
text-align: center
font-size: 110px;
text-align: center;
font-weight: 100;
color: #3899EC;
}
.hero .minitext {
font-size: 16px;
font-size: 24px;
text-align: center;
text-transform: uppercase
color: #444;
margin-top: 15px;
font-weight:300;
}
.hero strong {
color: #61dafb;
font-weight: 400
.love-list{
padding: 40px 0;
border: 1px solid #ddd;
border-width: 1px 0 1px 0;
}
.love-list ul{
margin:0;
padding:0;
}
.love-list li{
font-size: 18px;
line-height:1.7;
list-style-type: none;
}
.love-list li::before{
content: '';
display:inline-block;
width:14px;
height:14px;
border-radius:9px;
background: #3899EC;
margin-right:12px;
}
.buttons-unit {
margin-top: 60px;
margin-top: 40px;
text-align: center
}
@ -571,13 +594,14 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
}
.home-section {
margin: 50px 0
margin: 50px 0;
}
.home-divider {
border-top-color: #bbb;
margin: 0 auto;
width: 400px
width: 960px
}
.skinny-row:after {
@ -627,7 +651,7 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
margin-left: 0
}
#examples h3, .home-presentation h3 {
h3 {
color: #2d2d2d;
font-size: 24px;
font-weight: normal;
@ -1101,6 +1125,15 @@ div[data-twttr-id] iframe {
box-sizing:border-box;
}
.CodeMirror-wrap {
border:1px solid #ddd;
border-radius: 0 4px 4px 4px;
/*height: 400px;*/
/*min-height: 100px;*/
/*height: 100%;*/
/*margin: 10px;*/
}
.code-area.horizontal {
width: 70%;
float: left;

View File

@ -2,56 +2,66 @@
/*display: none;*/
/*}*/
body {
padding: 20px;
}
/*body {*/
/*padding: 20px;*/
/*}*/
.hiddenTab {
/*.hiddenTab {*/
/*width: 0;*/
/*height: 0;*/
}
/*}*/
.large-text-area {
height: 400px;
margin: 10px;
}
/*.large-text-area {*/
/*height: 400px;*/
/*margin: 10px;*/
/*}*/
.code-area.horizontal {
width: 50%;
/*.code-area.horizontal {*/
/*width: 50%;*/
/*height: 620px;*/
float: left;
}
/*float: left;*/
/*}*/
.code-area.vertical {
width: 100%;
/*.code-area.vertical {*/
/*width: 100%;*/
/*height: 620px;*/
float: none;
}
/*float: none;*/
/*}*/
.result-area.horizontal {
width: 50%;
float: left;
}
/*.result-area.horizontal {*/
/*width: 50%;*/
/*float: left;*/
/*}*/
.result-area.vertical {
width: 100%;
float: none;
}
/*.result-area.vertical {*/
/*width: 100%;*/
/*float: none;*/
/*}*/
.result-area {
width: 50%;
/*.result-area {*/
/*width: 50%;*/
/*height: 620px;*/
float: left;
/*float: left;*/
/*}*/
/*.sample-view {*/
/*margin: 10px;*/
/*}*/
/*.sample-view button {*/
/*margin: 5px;*/
/*}*/
/*.sample-view input[type=checkbox] {*/
/*margin-right: 5px;*/
/*}*/
.playground-error {
color: red;
}
.sample-view {
margin: 10px;
}
.sample-view button {
margin: 5px;
}
.sample-view input[type=checkbox] {
margin-right: 5px;
.cm-s-solarized .editor-error {
/*color: red;*/
/*text-decoration: underline;*/
background-color: #F0F079;
}

4
playground/dist/fiddle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -47681,9 +47681,18 @@ function generate(data, options) {
return templatePJSTemplate(data);
}
/**
* @param {string} name
* @return {string}
*/
function normalizeName(name) {
return name.replace(/-/g, '_');
}
module.exports = {
convertTemplateToReact: convertTemplateToReact,
RTCodeError: RTCodeError,
normalizeName: normalizeName,
_test: {}
};

File diff suppressed because one or more lines are too long

View File

@ -19,7 +19,7 @@ define(['lodash', 'react', './examples.rt',
// return {templateProps: tuple[0], templateHTML: tuple[1]};
//});
Object.keys(samples).forEach(function (k) {
samples[k] = {templateProps: samples[k][0], templateHTML: samples[k][1]};
samples[k] = {name: k, templateProps: samples[k][0], templateHTML: samples[k][1]};
});
var Examples = React.createClass({

View File

@ -1,3 +1,4 @@
<!--suppress CheckEmptyScriptTag -->
<rt-require dependency="./playground" as="playground"/>
<div id="examples">
<div class="example">
@ -5,7 +6,7 @@
<p>
Simple hello world html transformed into react javascript code
</p>
<playground id="helloExample" rt-props="this.state.samples.hello" direction="horizontal" codeVisible="{false}"></playground>
<playground id="helloExample" rt-props="this.state.samples.hello" direction="horizontal"></playground>
</div>
<div class="example">
<h3>This shows the use of rt-if</h3>

View File

@ -7,8 +7,7 @@ define([
return function () {
return React.createElement('div', { 'id': 'examples' }, React.createElement('div', { 'className': 'example' }, React.createElement('h3', {}, 'Hello world in react templates'), React.createElement('p', {}, '\n Simple hello world html transformed into react javascript code\n '), React.createElement(playground, _.merge({}, {
'id': 'helloExample',
'direction': 'horizontal',
'codeVisible': false
'direction': 'horizontal'
}, this.state.samples.hello))), React.createElement('div', { 'className': 'example' }, React.createElement('h3', {}, 'This shows the use of rt-if'), React.createElement('p', {}, '\n This shows the use of rt-if\n '), React.createElement(playground, _.merge({}, {
'id': 'ifExample',
'direction': 'horizontal'

View File

@ -4,7 +4,7 @@ requirejs.config({
lodash: 'http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min',
jquery: 'http://code.jquery.com/jquery-1.11.0.min',
firebase: 'https://cdn.firebase.com/js/client/2.0.5/firebase',
react: 'http://fb.me/react-with-addons-0.12.1.min',
react: 'http://fb.me/react-with-addons-0.12.2',
//ace: '../ace-builds-1.1.8/src-min/ace',
fiddle: './fiddle',
text: 'libs/requirejs-plugins/text',
@ -32,54 +32,21 @@ requirejs(['jquery', 'react', 'fiddle'], function ($, React, fiddle) {
'use strict';
window.fiddle = React.render(fiddle(), document.getElementById('container'));
$(function () {
$(window).resize(calcSize);
calcSize();
//$(window).resize(calcSize);
//calcSize();
});
function calcSize() {
var contentHeight = $(document).height() - 48;
//$('#container').height(contentHeight).width($(document).width());
//$('.code-area').each(function (i) {
// var h = (contentHeight / 2) - 10;
// var w = ($(document).width() / 2) - 10;
// $(this).height(h).width(w);
//});
//var h = (contentHeight / 2) - 10;
//var w = ($(document).width() / 2) - 10;
//var size = getWindowSize();
//$('#editor-rt').css({
// top: 50, left: 0, bottom: h, right: w, position: 'absolute'
//});
//$('#editor-code').css({
// top: 50, left: w, bottom: h, right: 0, position: 'absolute'
//});
//$('#editor-generated').css({
// top: 50 + h, left: 0, bottom: 0, right: w, position: 'absolute'
//});
//$('#result-area').css({
// top: 50 + h, left: w, bottom: 0, right: 0, position: 'absolute'
//});
//$('.code-area').each(function (i, k) {
// //var h = (contentHeight / 2) - 10;
// //var w = ($(document).width() / 2) - 10;
// //$(this).height(h).width(w);
// $(this).css({
// top: 50 + h, left: w, bottom: 0, right: 0, position: 'absolute'
// });
//});
$('.large-text-area').each(function (i, k) {
//var h = (contentHeight / 2) - 10;
//var w = ($(document).width() / 2) - 10;
var $this = $(this);
$this.height($this.parent().height() - 2).width($this.parent().width() - 2);
//$this.children().height($this.parent().height() - 2).width($this.parent().width() - 2);
var contentHeight = $(window).height() - $('#header').height();
var height = contentHeight / 2 - 10;
console.log(contentHeight, height);
$('.code-area').each(function (i, k) {
$(this).height(height);
console.log($(this).height());
});
var $result = $('#result-container');
$result.height($result.parent().height() - 2).width($result.parent().width() - 2);
window.editorCode.refresh();
window.editorRT.refresh();
window.editorGenerated.refresh();
}
});

View File

@ -1,3 +1,4 @@
<!--suppress CheckEmptyScriptTag -->
<rt-require dependency="./playground" as="playground"/>
<div class="fiddle">
<div id="header">
@ -5,7 +6,7 @@
<a href="index.html" class="title-link">
<img class="nav-logo" src="https://wix.github.io/react-templates/img/logo-rt.svg" width="56" height="24" />
</a>
RTFiddle
RT Playground
</div>
<div id="buttons-bar">
<button type="button" class="btn btn-default" onClick="(evt)=>evt.preventDefault();this.save()">
@ -29,14 +30,15 @@
</ul>
</div>
</div>
<ul class="nav-site">
<li><a href="https://github.com/wix/react-templates">docs</a></li>
<!--<li><a href="https://github.com/wix/react-templates">support</a></li>-->
<li><a href="https://github.com/wix/react-templates">download</a></li>
<!--<li><a href="https://github.com/wix/react-templates/">blog</a></li>-->
<li><a href="https://github.com/wix/react-templates">github</a>
</ul>
</div>
<!--<div>-->
<!--<h1>React Templates fiddle</h1>-->
<!--<h2>Play with react templates and save/share your results</h2>-->
<!--<button class="btn btn-lg btn-primary" onClick="(evt)=>evt.preventDefault();this.save()">Save fiddle</button>-->
<!--<br />-->
<div class="playground-container">
<playground ref="playground" direction="vertical" fiddle="{true}" />
</div>
<!--</div>-->
</div>

View File

@ -41,7 +41,7 @@ define([
'src': 'https://wix.github.io/react-templates/img/logo-rt.svg',
'width': '56',
'height': '24'
})), '\n RTFiddle\n '), React.createElement('div', { 'id': 'buttons-bar' }, React.createElement('button', {
})), '\n RT Playground\n '), React.createElement('div', { 'id': 'buttons-bar' }, React.createElement('button', {
'type': 'button',
'className': 'btn btn-default',
'onClick': onClick1.bind(this)
@ -90,14 +90,10 @@ define([
'tabIndex': '-1',
'href': '#',
'onClick': onClick7.bind(this)
}, 'Weather')))))) /* <div> */
/* <h1>React Templates fiddle</h1> */
/* <h2>Play with react templates and save/share your results</h2> */
/* <button class="btn btn-lg btn-primary" onClick="(evt)=>evt.preventDefault();this.save()">Save fiddle</button> */
/* <br /> */, React.createElement('div', { 'className': 'playground-container' }, React.createElement(playground, {
}, 'Weather'))))), React.createElement('ul', { 'className': 'nav-site' }, React.createElement('li', {}, React.createElement('a', { 'href': 'https://github.com/wix/react-templates' }, 'docs')) /* <li><a href="https://github.com/wix/react-templates">support</a></li> */, React.createElement('li', {}, React.createElement('a', { 'href': 'https://github.com/wix/react-templates' }, 'download')) /* <li><a href="https://github.com/wix/react-templates/">blog</a></li> */, React.createElement('li', {}, React.createElement('a', { 'href': 'https://github.com/wix/react-templates' }, 'github')))), React.createElement('div', { 'className': 'playground-container' }, React.createElement(playground, {
'ref': 'playground',
'direction': 'vertical',
'fiddle': true
})) /* </div> */);
})));
};
});

View File

@ -4,7 +4,7 @@ requirejs.config({
lodash: 'http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min',
jquery: 'http://code.jquery.com/jquery-1.11.0.min',
firebase: 'https://cdn.firebase.com/js/client/2.0.5/firebase',
react: 'http://fb.me/react-with-addons-0.12.1.min',
react: 'http://fb.me/react-with-addons-0.12.2',
text: 'libs/requirejs-plugins/text',
json: 'libs/requirejs-plugins/json'
//ace: '../ace-builds-1.1.8/src-min/ace',

View File

@ -1,36 +1,41 @@
<!--suppress CheckEmptyScriptTag -->
<rt-require dependency="./CodeMirrorEditor" as="CodeEditor"/>
<!--suppress ALL -->
<div class="playground">
<div class="fiddle-row">
<div class="code-area">
<CodeEditor ref="editorRT" id="editor-rt" class="large-text-area" style="border: {this.validHTML ? '1px solid black' : '2px solid red'};"
<div class="code-area" id="area-rt">
<!--style="border: {this.validHTML ? '' : '2px solid red'};"-->
<CodeEditor ref="editorRT" id="editor-rt" class="large-text-area"
value="{this.state.templateHTML}"
mode="html"
onChange="(evt) => this.setState({'templateHTML':evt.target.value})" />
</div>
<div class="code-area">
<CodeEditor ref="editorCode" id="editor-code" class="large-text-area" style="border: {this.validProps ? '1px solid black' : '2px solid red'};"
<div class="code-area" id="area-code">
<!--style="border: {this.validProps ? '' : '2px solid red'};"-->
<CodeEditor ref="editorCode" id="editor-code" class="large-text-area"
value="{this.state.templateProps}"
mode="javascript"
onChange="(evt) => this.setState({'templateProps':evt.target.value})" />
</div>
</div>
<div class="fiddle-row">
<div class="code-area">
<CodeEditor id="editor-generated" class="large-text-area" style="border:1px solid black;"
<div class="code-area" id="area-generated">
<!--style="border:0px none black;"-->
<CodeEditor id="editor-generated" class="large-text-area"
ref="editorGenerated"
value="{this.templateSource}"
mode="javascript"
readOnly="{true}" />
</div>
<div id="result-container" class="result-area">
<div id="result-area" key="result-area" class="well">
<h2>Preview:</h2>
<form class="sample-view" onSubmit="(e) => e.preventDefault();">
<this.sample key="sample">
</this.sample>
<div class="code-area" id="area-result">
<!--<div id="result-container" class="result-area">-->
<div id="result-area" key="result-area" class="sample-view">
<!--<h2>Preview:</h2>-->
<form class="result-area-form" ref="mount" onSubmit="(e) => e.preventDefault();">
<!--<this.sample key="sample">-->
<!--</this.sample>-->
</form>
</div>
</div>
</div>
<!--<br style="clear:both">-->
</div>

View File

@ -14,39 +14,48 @@ define([
e.preventDefault();
}
return function () {
return React.createElement('div', { 'className': 'playground' }, React.createElement('div', { 'className': 'fiddle-row' }, React.createElement('div', { 'className': 'code-area' }, React.createElement(CodeEditor, {
return React.createElement('div', { 'className': 'playground' }, React.createElement('div', { 'className': 'fiddle-row' }, React.createElement('div', {
'className': 'code-area',
'id': 'area-rt'
} /* style="border: {this.validHTML ? '' : '2px solid red'};" */, React.createElement(CodeEditor, {
'ref': 'editorRT',
'id': 'editor-rt',
'className': 'large-text-area',
'style': { border: this.validHTML ? '1px solid black' : '2px solid red' },
'value': this.state.templateHTML,
'mode': 'html',
'onChange': onChange1.bind(this)
})), React.createElement('div', { 'className': 'code-area' }, React.createElement(CodeEditor, {
})), React.createElement('div', {
'className': 'code-area',
'id': 'area-code'
} /* style="border: {this.validProps ? '' : '2px solid red'};" */, React.createElement(CodeEditor, {
'ref': 'editorCode',
'id': 'editor-code',
'className': 'large-text-area',
'style': { border: this.validProps ? '1px solid black' : '2px solid red' },
'value': this.state.templateProps,
'mode': 'javascript',
'onChange': onChange2.bind(this)
}))), React.createElement('div', { 'className': 'fiddle-row' }, React.createElement('div', { 'className': 'code-area' }, React.createElement(CodeEditor, {
}))), React.createElement('div', { 'className': 'fiddle-row' }, React.createElement('div', {
'className': 'code-area',
'id': 'area-generated'
} /* style="border:0px none black;" */, React.createElement(CodeEditor, {
'id': 'editor-generated',
'className': 'large-text-area',
'style': { border: '1px solid black' },
'ref': 'editorGenerated',
'value': this.templateSource,
'mode': 'javascript',
'readOnly': true
})), React.createElement('div', {
'id': 'result-container',
'className': 'result-area'
}, React.createElement('div', {
'className': 'code-area',
'id': 'area-result'
} /* <div id="result-container" class="result-area"> */, React.createElement('div', {
'id': 'result-area',
'key': 'result-area',
'className': 'well'
}, React.createElement('h2', {}, 'Preview:'), React.createElement('form', {
'className': 'sample-view',
'className': 'sample-view'
} /* <h2>Preview:</h2> */, React.createElement('form', {
'className': 'result-area-form',
'ref': 'mount',
'onSubmit': onSubmit3.bind(this)
}, React.createElement(this.sample, { 'key': 'sample' }))))) /* <br style="clear:both"> */);
} /* <this.sample key="sample"> */
/* </this.sample> */)))));
};
});

View File

@ -1,24 +1,32 @@
/*eslint-env browser*/
define(['react', 'lodash', './playground-fiddle.rt', './playground.rt'], function (React, _, pgFiddleTemplate, playgroundTemplate) {
define(['react', 'jquery', 'lodash', './playground-fiddle.rt', './playground.rt', './CMLint'], function (React, $, _, pgFiddleTemplate, playgroundTemplate, CMLint) {
'use strict';
function emptyFunc() {
return null;
}
function generateTemplateSource(html, editor) {
/**
* @param {string} html
* @param editor
* @param {string} name
* @return {string}
*/
function generateTemplateSource(html, editor, name) {
var code = null;
try {
code = window.reactTemplates.convertTemplateToReact(html.trim().replace(/\r/g, ''));
code = window.reactTemplates.convertTemplateToReact(html.trim().replace(/\r/g, ''), {modules: 'none', name: name});
clearMessage(editor);
} catch (e) {
var msg;
if (e.name === 'RTCodeError') {
//index: -1 line: -1 message: "Document should have a root element" name: "RTCodeError"
msg = e.message + ', line: ' + e.line;
editor.annotate({line: e.line, message: e.message, index: e.index});
} else {
msg = e.message;
editor.annotate({line: 1, message: e.message});
}
showMessage(editor, msg);
//showMessage(editor, msg);
console.log(e);
}
return code;
@ -26,13 +34,23 @@ define(['react', 'lodash', './playground-fiddle.rt', './playground.rt'], functio
function showMessage(editor, msg) {
if (editor && editor.showMessage) {
editor.showMessage(msg);
//editor.showMessage(msg);
editor.annotate({line: 1, message: msg});
//calcSize();
}
}
function calcSize() {
if (window.calcSize) {
window.calcSize();
}
}
function clearMessage(editor) {
if (editor && editor.clearMessage) {
editor.clearMessage();
//editor.clearMessage();
editor.clearAnnotations();
//calcSize();
}
}
@ -70,10 +88,24 @@ define(['react', 'lodash', './playground-fiddle.rt', './playground.rt'], functio
}
var templateHTML = '<div></div>';
var templateProps = '{}';
var templateProps = 'var template = React.createClass({\n' +
' render: function () {\n' +
' return templateRT.apply(this);\n' +
' }\n' +
'});';
var selfCleaningTimeout = {
componentDidUpdate: function() {
clearTimeout(this.timeoutID);
},
setTimeout: function() {
console.log('setTimeout');
clearTimeout(this.timeoutID);
this.timeoutID = setTimeout.apply(null, arguments);
}
};
var Playground = React.createClass({
displayName: 'Playground',
mixins: [React.addons.LinkedStateMixin],
propTypes: {
@ -81,6 +113,14 @@ define(['react', 'lodash', './playground-fiddle.rt', './playground.rt'], functio
codeVisible: React.PropTypes.bool,
fiddle: React.PropTypes.bool
},
templateSource: '',
validHTML: true,
validProps: true,
setTimeout: function() {
console.log('setTimeout');
clearTimeout(this.timeoutID);
this.timeoutID = setTimeout.apply(null, arguments);
},
getDefaultProps: function () {
return {
direction: 'horizontal', //vertical
@ -88,34 +128,83 @@ define(['react', 'lodash', './playground-fiddle.rt', './playground.rt'], functio
fiddle: false
};
},
getLayoutClass: function () {
return (this.props.direction === 'horizontal' && 'horizontal') || 'vertical';
},
//executeCode: function() {
// var mountNode = this.refs.mount.getDOMNode();
//
// try {
// React.unmountComponentAtNode(mountNode);
// } catch (e) { }
//
// try {
// var compiledCode = this.compileCode();
// if (this.props.renderCode) {
// React.render(
// React.createElement(CodeMirrorEditor, {codeText: compiledCode, readOnly: true}),
// mountNode
// );
// } else {
// eval(compiledCode);
// }
// } catch (err) {
// this.setTimeout(function() {
// React.render(
// React.createElement('div', {className: 'playgroundError'}, err.toString()),
// mountNode
// );
// }, 500);
// }
//},
getTabs: function () {
if (this.props.codeVisible) {
return [['templateHTML','Template'],['templateProps','Class'],['templateSource','Generated code']];
return [['templateHTML', 'Template'], ['templateProps', 'Class'], ['templateSource', 'Generated code']];
} else {
return [['templateHTML','Template'],['templateSource','Generated code']];
return [['templateHTML', 'Template'], ['templateSource', 'Generated code']];
}
},
updateSample: function (state) {
this.templateSource = generateTemplateSource(state.templateHTML, this.refs.editorRT);
this.sampleFunc = generateTemplateFunction(this.templateSource);
this.validHTML = this.sampleFunc !== emptyFunc;
var mountNode = this.refs.mount.getDOMNode();
//try {
// React.unmountComponentAtNode(mountNode);
//} catch (e) { }
this.generateCode();
//this.sampleFunc = generateTemplateFunction(this.templateSource);
//this.validHTML = this.sampleFunc !== emptyFunc;
this.validHTML = true;
this.sampleRender = generateRenderFunc(this.sampleFunc);
var classBase = {};
//var classBase = {};
try {
this.validProps = true;
console.log(state.templateProps);
classBase = eval('(' + state.templateProps + ')');
if (!_.isObject(classBase)) {
throw 'failed to eval';
//classBase = eval(this.templateSource + '\n' + state.templateProps);
//if (!_.isObject(classBase)) {
// throw 'failed to eval';
//}
this.sample = eval('(function () {' + this.templateSource + '\n' + state.templateProps + '\n return React.createElement(' + state.name + ');})()');
if (this.sample) {
React.render(this.sample, mountNode);
}
clearMessage(this.refs.editorCode);
} catch (e) {
classBase = {};
//classBase = {};
this.rtMessage = e.toString();
this.validProps = false;
showMessage(this.refs.editorCode, e.message);
var editor = this.refs.editorCode;
this.setTimeout(function() {
showMessage(editor, e.message);
console.log('setTimeout playgroundError');
React.render(
React.createElement('div', {className: 'playground-error'}, e.toString()),
mountNode
);
}, 500);
}
classBase.render = this.sampleRender;
this.sample = React.createFactory(React.createClass(classBase));
//classBase.render = this.sampleRender;
//this.sample = React.createFactory(React.createClass(classBase));
},
clear: function () {
//console.log('clear');
@ -130,20 +219,48 @@ define(['react', 'lodash', './playground-fiddle.rt', './playground.rt'], functio
var currentState = {
templateHTML: this.props.templateHTML || templateHTML,
templateProps: this.props.templateProps || templateProps,
name: this.props.name || 'template',
currentTab: 'templateHTML'
};
this.updateSample(currentState);
//this.updateSample(currentState);
return currentState;
},
componentDidMount: function() {
if (this.props.fiddle) {
window.addEventListener('resize', this.calcSize);
this.calcSize();
}
this.updateSample(this.state);
},
componentWillUnmount: function(){
window.removeEventListener('resize', this.calcSize);
},
calcSize: function() {
var contentHeight = $(window).height() - $('#header').height();
var height = contentHeight / 2 - 10;
$('.code-area').each(function (i, k) {
$(this).height(height);
console.log($(this).height());
});
this.refs.editorCode.editor.refresh();
this.refs.editorRT.editor.refresh();
this.refs.editorGenerated.editor.refresh();
},
componentWillUpdate: function (nextProps, nextState) {
if (nextState.templateHTML !== this.state.templateHTML || nextState.templateProps !== this.state.templateProps) {
this.updateSample(nextState);
}
},
render: function () {
this.generateCode();
var template = this.props.fiddle ? pgFiddleTemplate : playgroundTemplate;
return template.apply(this);
},
generateCode: function () {
this.templateSource = generateTemplateSource(this.state.templateHTML, this.refs.editorRT, window.reactTemplates.normalizeName(this.state.name) + 'RT');
}
});

View File

@ -2,15 +2,13 @@
<!--suppress CheckEmptyScriptTag -->
<rt-require dependency="./CodeMirrorEditor" as="CodeEditor"/>
<div class="playground">
<div id="{this.props.id}-myTab" class="code-area {(this.props.direction === 'horizontal' && 'horizontal') ||'vertical'}">
<div id="{this.props.id}-myTab" class="code-area {this.getLayoutClass()}">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li rt-repeat="tab in this.getTabs()" role="presentation"
rt-class="{active:this.state.currentTab === tab[0]}"
onClick="(evt)=> evt.preventDefault();this.setState({'currentTab':tab[0]});">
<a aria-controls="{tab[1]}"
>{tab[1]}</a>
<a aria-controls="{tab[1]}">{tab[1]}</a>
</li>
</ul>
<!-- Tab panes -->
@ -19,13 +17,13 @@
<CodeEditor ref="editorRT" class="large-text-area" style="border: {this.validHTML? '':'2px solid red'};"
value="{this.state.templateHTML}"
mode="html"
onChange="(evt) => this.setState({'templateHTML':evt.target.value})" />
onChange="(evt) => this.setState({templateHTML:evt.target.value})" />
</div>
<div rt-if="this.state.currentTab === 'templateProps'" class="tab-pane active">
<CodeEditor ref="editorCode" class="large-text-area" style="border: {this.validProps? '':'2px solid red'};"
value="{this.state.templateProps}"
mode="javascript"
onChange="(evt) => this.setState({'templateProps':evt.target.value})" />
onChange="(evt) => this.setState({templateProps:evt.target.value})" />
</div>
<div rt-if="this.state.currentTab === 'templateSource'" class="tab-pane active">
<CodeEditor class="large-text-area"
@ -36,11 +34,11 @@
</div>
</div>
<div key="result-area" class="result-area {(this.props.direction === 'horizontal' && 'horizontal') ||'vertical'}">
<div key="result-area" class="result-area {this.getLayoutClass()}">
<span class="preview-title">{'\u00A0'}</span>
<form class="sample-view" onSubmit="(e) => e.preventDefault();">
<this.sample key="sample">
</this.sample>
<form ref="mount" class="sample-view" onSubmit="(e) => e.preventDefault();">
<!--<this.sample key="sample">-->
<!--</this.sample>-->
</form>
</div>
<br style="clear:both">

View File

@ -16,10 +16,10 @@ define([
}, React.createElement('a', { 'aria-controls': tab[1] }, tab[1]));
}
function onChange3(evt) {
this.setState({ 'templateHTML': evt.target.value });
this.setState({ templateHTML: evt.target.value });
}
function onChange4(evt) {
this.setState({ 'templateProps': evt.target.value });
this.setState({ templateProps: evt.target.value });
}
function onSubmit5(e) {
e.preventDefault();
@ -27,7 +27,7 @@ define([
return function () {
return React.createElement('div', { 'className': 'playground' }, React.createElement('div', {
'id': this.props.id + '-myTab',
'className': 'code-area ' + (this.props.direction === 'horizontal' && 'horizontal' || 'vertical')
'className': 'code-area ' + this.getLayoutClass()
} /* Nav tabs */, React.createElement.apply(this, _.flatten([
'ul',
{
@ -56,10 +56,12 @@ define([
'readOnly': true
})) : null)), React.createElement('div', {
'key': 'result-area',
'className': 'result-area ' + (this.props.direction === 'horizontal' && 'horizontal' || 'vertical')
'className': 'result-area ' + this.getLayoutClass()
}, React.createElement('span', { 'className': 'preview-title' }, '\xA0'), React.createElement('form', {
'ref': 'mount',
'className': 'sample-view',
'onSubmit': onSubmit5.bind(this)
}, React.createElement(this.sample, { 'key': 'sample' }))), React.createElement('br', { 'style': { clear: 'both' } }));
} /* <this.sample key="sample"> */
/* </this.sample> */)), React.createElement('br', { 'style': { clear: 'both' } }));
};
});

View File

@ -1 +1,5 @@
{}
var hello = React.createClass({
render: function () {
return helloRT.apply(this);
}
});

View File

@ -1,8 +1,11 @@
{
var rtIf = React.createClass({
getInitialState: function () {
return {open: false};
},
toggle: function() {
this.setState({open: !this.state.open});
},
render: function () {
return rtIfRT.apply(this);
}
}
});

View File

@ -1,9 +1,18 @@
{
var props = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getProps: function() {
return _.omit(this.props, ['onClick', 'eventId']);
getInitialState: function() {
return { key: 'color', val: 'blue' };
},
reportClick: function(child) {
alert((this.props.eventId || -1) + ':' + child.innerText);
getProps: function() {
var ret = { style: {
color: 'black',
backgroundColor: 'white',
borderColor: 'black'
}};
ret.style[this.state.key] = this.state.val;
return ret;
},
render: function () {
return propsRT.apply(this);
}
}
});

View File

@ -1,5 +1,16 @@
<div onClick="(evt)=>this.reportClick(evt.target)"
rt-props="this.getProps()">
All kinds of stuff,
<span>some inner child, </span> and a sibling
<div>
Style:
<select valueLink="{this.linkState('key')}">
<option value="color">Color</option>
<option value="backgroundColor">Background color</option>
<option value="borderColor">Border color</option>
</select><br/>
Value:
<select valueLink="{this.linkState('val')}">
<option value="blue">Blue</option>
<option value="red">Red</option>
<option value="yellow">Yellow</option>
</select><br/><br/>
<div style="padding:5px;text-align:center;border:1px solid"
rt-props="this.getProps()">Sample</div>
</div>

View File

@ -1,12 +1,10 @@
{
mixins: [React.addons.LinkedStateMixin],
var repeat = React.createClass({
getInitialState: function () {
return {
items: [
'One',
'Two',
'Three'
]
items: ['One', 'Two', 'Three']
};
},
render: function () {
return repeatRT.apply(this);
}
}
});

View File

@ -1,5 +1,5 @@
<div>
<ul rt-repeat="item in this.state.items">
<li>{item}</li>
<ul>
<li rt-repeat="item in this.state.items">{item}</li>
</ul>
</div>

View File

@ -1,12 +1,12 @@
{
var todo = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function () {
return {edited: '', todos: [], counter: 0};
},
add: function () {
if (this.state.edited.trim().length === 0) {
return;
}
if (this.state.edited.trim().length === 0) {
return;
}
var newTodo = {value: this.state.edited, done: false, key: this.state.counter};
this.setState({todos: this.state.todos.concat(newTodo), edited: '', counter: this.state.counter + 1});
},
@ -20,5 +20,8 @@
},
clearDone: function () {
this.setState({todos: _.filter(this.state.todos, {done: false})});
},
render: function () {
return todoRT.apply(this);
}
}
});

View File

@ -1,13 +1,21 @@
<div>
<strong>{_.filter(this.state.todos, {done:true}).length}</strong> done,
<strong>{_.filter(this.state.todos, {done:false}).length}</strong> pending
<strong>{_.filter(this.state.todos, {done:true}).length}</strong>
done,
<strong>{_.filter(this.state.todos, {done:false}).length}</strong>
pending
<br/>
<div rt-repeat="todo in this.state.todos" key="{todo.key}">
<button onClick="()=>this.remove(todo)" title="Remove Todo">x</button>
<input type="checkbox" checked="{todo.done}" onChange="()=>this.toggleChecked(todoIndex)"/>
<img src="img/samples/delete.png"
onClick="()=>this.remove(todo)"
title="Remove Todo"
style="cursor:pointer"/>
<input type="checkbox" checked="{todo.done}"
onChange="()=>this.toggleChecked(todoIndex)"/>
<span style="text-decoration: {todo.done ? 'line-through': 'none'}">{todo.value}</span>
</div>
<input key="myinput" type="text" onKeyDown="(e) => if (e.keyCode == 13) { e.preventDefault(); this.add(); }" valueLink="{this.linkState('edited')}"/>
<input key="myinput" style="width:130px" type="text"
onKeyDown="(e) => if (e.keyCode == 13) { e.preventDefault(); this.add(); }"
valueLink="{this.linkState('edited')}"/>
<button onClick="()=>this.add()">Add</button><br/>
<button onClick="()=>this.clearDone()">Clear done</button>
</div>

View File

@ -1,4 +1,4 @@
{
var weather = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
this.cityIds = [5391959,293397,2643743];
@ -16,8 +16,7 @@
if (result.id && !_.contains(this.cityIds, result.id)) {
this.cityIds.unshift(result.id);
this.fetchWeather();
}
else {
} else {
this.setState({ loading: false });
}
},
@ -30,5 +29,8 @@
},
fetchWeatherCallback: function(result) {
this.setState({ loading:false, info: result.list });
},
render: function () {
return weatherRT.apply(this);
}
}
});

View File

@ -1,6 +1,7 @@
<div>
<h4>Cities weather report</h4>
<input placeholder="Type a city to add"
style="width:130px"
valueLink="{this.linkState('cityToAdd')}"
onKeyDown="(e)=>if (e.keyCode === 13) { e.preventDefault(); this.addCity(); }"/>
<button onClick="{this.addCity}">Add</button>
@ -12,7 +13,7 @@
<img rt-repeat="weather in city.weather"
src="http://openweathermap.org/img/w/{weather.icon}.png"
title="{weather.description}"/>
{city.name}, {city.sys.country}
<span style="white-space:nowrap">{city.name}, {city.sys.country}</span>
</div>
<button onClick="{this.refresh}">Refresh</button>
</div>

View File

@ -27,7 +27,7 @@ function convertFile(source, target, options, context) {
var html = fs.readFileSync(source).toString();
if (!options.name) {
options.name = path.basename(source, path.extname(source)) + 'RT';
options.name = reactTemplates.normalizeName(path.basename(source, path.extname(source))) + 'RT';
}
var js = convertTemplateToReact(html, options);
if (!options.dryRun) {

View File

@ -403,8 +403,17 @@ function generate(data, options) {
return templatePJSTemplate(data);
}
/**
* @param {string} name
* @return {string}
*/
function normalizeName(name) {
return name.replace(/-/g, '_');
}
module.exports = {
convertTemplateToReact: convertTemplateToReact,
RTCodeError: RTCodeError,
normalizeName: normalizeName,
_test: {}
};