Created sample application

This commit is contained in:
amitk 2014-11-16 01:09:52 +02:00
parent e5536fd07a
commit 576b3fcada
7 changed files with 327 additions and 0 deletions

96
sample/ImageSearch.js Normal file
View File

@ -0,0 +1,96 @@
define([
'lodash',
'jquery',
'react',
'ImageSearch.rt'
], function (_, $, React, template) {
'use strict';
var ImageSearch = React.createClass({
displayName: 'ImageSearch',
mixins: [React.addons.LinkedStateMixin],
seq: 0,
total: 0,
hasMore: true,
heights: [0, 0, 0],
realTerm: 'cats',
getInitialState: function () {
setTimeout(this.search, 0);
return {
searchTerm: this.realTerm,
items: [[], [], []]
};
},
search: function() {
this.state.items = [[], [], []];
this.total = 0;
this.heights = [0, 0, 0];
this.hasMore = true;
this.realTerm = this.state.searchTerm;
this.loadMore();
},
indexOfMin: function(array) {
var indexAndMin = _.reduce(array, function(accum, height, index) {
return (height < accum.min) ? { i: index, min: height } : accum;
}, {i: -1, min: Number.MAX_VALUE});
return indexAndMin.i;
},
loadMore: function(done) {
done = done || function() {};
if (!this.hasMore) {
done();
return;
}
var url = 'https://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8&start=' + this.total + '&q=' + this.realTerm + "&callback=?";
var self = this;
$.ajax({url: url, dataType: 'jsonp'})
.done(function(data){
if (!data.responseData) {
self.hasMore = false;
done();
return;
}
var results = data.responseData.results;
var items = _.cloneDeep(self.state.items);
for (var i = 0; i < results.length; i++) {
var result = data.responseData.results[i];
var minHeightIndex = self.indexOfMin(self.heights);
items[minHeightIndex].push({
id: self.seq + 1,
title: result.titleNoFormatting,
url: result.url,
ratio: result.width / result.height,
originalContext: result.originalContextUrl
});
var relativeHeight = result.height / result.width;
self.heights[minHeightIndex] = self.heights[minHeightIndex] + relativeHeight;
self.total++;
self.seq++;
}
self.setState({items: items});
done();
});
},
shouldComponentUpdate: function(nextProps, nextState) {
return !_.isEqual(this.state, nextState);
},
render: function () {
return template.apply(this);
}
});
return ImageSearch;
});

18
sample/ImageSearch.rt Normal file
View File

@ -0,0 +1,18 @@
<!doctype jsx InfiniteScroll="InfiniteScroll">
<div className="innerContainer">
<div className="searchbox">
<input type="text" valueLink="{this.linkState('searchTerm')}" onKeyDown="(e) => if (e.keyCode == 13) { this.search(); return false; }"></input>
<button onClick="() => this.search(); return false;">Search</button>
</div>
<InfiniteScroll className="fixed" onLoadMore="{this.loadMore}" threshold="{150}">
<div rt-repeat="row in [0, 1, 2]" key="{row}">
<a rt-repeat="i in this.state.items[row]" href="{i.originalContext}" target="blank" className="container fadeInDown" key="{i.id}">
<div style="padding-top: {Math.floor(100/i.ratio)}%; background-color: grey"></div>
<div className="imgContainer">
<img width="100%" src="{i.url}"/>
<div className="title">{i.title}</div>
</div>
</a>
</div>
</InfiniteScroll>
</div>

57
sample/ImageSearch.rt.js Normal file
View File

@ -0,0 +1,57 @@
define([
'react',
'lodash',
'InfiniteScroll'
], function (React, _, InfiniteScroll) {
'use strict';
function onKeyDown1(e) {
if (e.keyCode == 13) {
this.search();
return false;
}
}
function onClick2() {
this.search();
return false;
}
function repeatI3(row, rowIndex, i, iIndex) {
return React.DOM.a({
'href': i.originalContext,
'target': 'blank',
'className': 'container fadeInDown',
'key': i.id
}, React.DOM.div({
'style': {
paddingTop: Math.floor(100 / i.ratio) + '%',
backgroundColor: 'grey'
}
}), React.DOM.div({ 'className': 'imgContainer' }, React.DOM.img({
'width': '100%',
'src': i.url
}), React.DOM.div({ 'className': 'title' }, i.title)));
}
function repeatRow4(row, rowIndex) {
return React.DOM.div.apply(this, _.flatten([
{ 'key': row },
_.map(this.state.items[row], repeatI3.bind(this, row, rowIndex))
]));
}
return function () {
return React.DOM.div({ 'className': 'innerContainer' }, React.DOM.div({ 'className': 'searchbox' }, React.DOM.input({
'type': 'text',
'valueLink': this.linkState('searchTerm'),
'onKeyDown': onKeyDown1.bind(this)
}), React.DOM.button({ 'onClick': onClick2.bind(this) }, 'Search')), InfiniteScroll.apply(this, _.flatten([
{
'className': 'fixed',
'onLoadMore': this.loadMore,
'threshold': 150
},
_.map([
0,
1,
2
], repeatRow4.bind(this))
])));
};
});

37
sample/InfiniteScroll.js Normal file
View File

@ -0,0 +1,37 @@
define([
'lodash',
'jquery',
'react'
], function (_, $, React) {
'use strict';
var InfiniteScroll = React.createClass({
displayName: 'InfiniteScroll',
gettingMore: false,
onLoadMoreFinished: function() {
this.gettingMore = false;
},
onScroll: function(evt) {
if (!this.props.onLoadMore || this.gettingMore) {
return;
}
var threshold = this.props.threshold || 0;
var raw = evt.target;
if (raw.scrollTop + raw.offsetHeight + threshold >= raw.scrollHeight) {
this.gettingMore = true;
this.props.onLoadMore(this.onLoadMoreFinished);
}
},
render: function () {
var passedProps = _.omit(this.props, ['onLoadMore', 'threshold', 'children', 'onScroll']);
passedProps.onScroll = this.onScroll;
return React.DOM.div(passedProps, this.props.children);
}
});
return InfiniteScroll;
});

16
sample/index.html Normal file
View File

@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>React templates - Image Search Sample</title>
<link rel="stylesheet" href="sample.css"/>
</head>
<body>
<form id="main" style="padding:20px 150px;">
<!-- the lists panel -->
<div id="preloader" style="text-align: center;">Loading...</div>
</form>
<script data-main="main.js" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.js"></script>
</body>
</html>

20
sample/main.js Normal file
View File

@ -0,0 +1,20 @@
'use strict';
requirejs.config({
// baseUrl: '/',
paths: {
lodash: 'http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash',
jquery: 'http://code.jquery.com/jquery-1.11.0.min',
react: 'http://fb.me/react-with-addons-0.12.0'
},
shim: {
lodash: { exports: '_' },
jquery: { exports: '$' },
react: { exports: 'React' }
}
});
requirejs(['jquery', 'react', 'ImageSearch'], function ($, React, ImageSearch) {
React.renderComponent(ImageSearch(), $('#main').get(0));
});

83
sample/sample.css Normal file
View File

@ -0,0 +1,83 @@
.imgContainer {
position:absolute;
top:0;
bottom:0;
left:0;
right:0;
}
.fixed {
height: calc(553px - 53px);
overflow-y: auto;
overflow-x: hidden;
}
.fixed > div {
width: 33%;
display: inline-block;
vertical-align: top;
}
.searchbox {
text-align:center;
height: 53px;
}
.container {
display: block;
background-color: gray;
position: relative;
margin: 0 10px 10px 0;
}
@-webkit-keyframes fadeInDown{
0%{
opacity:0;
-webkit-transform:translate3d(0,-50%,0);
transform:translate3d(0,-50%,0)
}
100%{
opacity:1;
-webkit-transform:none;
transform:none
}
}
@keyframes fadeInDown{
0%{
opacity:0;
-webkit-transform:translate3d(0,-50%,0);
-ms-transform:translate3d(0,-50%,0);
transform:translate3d(0,-50%,0)
}
100%{
opacity:1;
-webkit-transform:none;
-ms-transform:none;
transform:none
}
}
.fadeInDown{
-webkit-animation:fadeInDown 1s;
animation:fadeInDown 1s;
}
.title {
color: white;
background-color: black;
font-family: Arial, Helvetica, sans-serif;
font-size: 9pt;
opacity: 0;
position: absolute;
bottom:0;
}
.container:hover .title {
opacity: 1;
transition: opacity 0.75s;
}