Browse Source

new folder structure

master
Julian Steinwachs 10 years ago
parent
commit
a0adb2b78a
  1. 231
      build-buffer/.module-cache/1481637775089844184af71820625492ebd04146.js
  2. 71
      build-buffer/.module-cache/20db71076a525ed87d3d9dfbd98c8b31be8c6896.js
  3. 60
      build-buffer/.module-cache/242ec183241b4b53f4ddae69b8afb6b60426ec42.js
  4. 80
      build-buffer/.module-cache/299f979899a857c45bf2f5de63a5ca750da60433.js
  5. 183
      build-buffer/.module-cache/38e3cc72af24ddb96884506416d1a140d84277fe.js
  6. 77
      build-buffer/.module-cache/7b5f4f98c79393354f44412127d1b1b4768c7ae2.js
  7. 84
      build-buffer/.module-cache/9dff733c4585512f6ed2deca306255214765bbe7.js
  8. 12
      build-buffer/.module-cache/9fc14ade32e04296d9f74634da69458d5595110f.js
  9. 95
      build-buffer/.module-cache/bb5e20b0dfe1177cc608549060d0883ef58e156b.js
  10. 51
      build-buffer/.module-cache/bd19abac2e2e24498b933499d1eff7ae0825111d.js
  11. 42
      build-buffer/.module-cache/d33e863ad34154f54a43fa2e43e161c04d397c4c.js
  12. 107
      build-buffer/.module-cache/d7e8646c084253b7cfd0f981f734a2b391aa60a5.js
  13. 11
      build-buffer/.module-cache/dea17f9cee8acb42aaea8c4b65723338c5d1feb2.js
  14. 62
      build-buffer/.module-cache/e2700f3eddcf47a0235b40f1879c236d04edfb9f.js
  15. 34
      build-buffer/.module-cache/e394633e8498d5a50e1a34cd73f803421446d4f3.js
  16. 1
      build-buffer/.module-cache/manifest/1481637775089844184af71820625492ebd04146.json
  17. 1
      build-buffer/.module-cache/manifest/20db71076a525ed87d3d9dfbd98c8b31be8c6896.json
  18. 1
      build-buffer/.module-cache/manifest/242ec183241b4b53f4ddae69b8afb6b60426ec42.json
  19. 1
      build-buffer/.module-cache/manifest/299f979899a857c45bf2f5de63a5ca750da60433.json
  20. 1
      build-buffer/.module-cache/manifest/38e3cc72af24ddb96884506416d1a140d84277fe.json
  21. 1
      build-buffer/.module-cache/manifest/7b5f4f98c79393354f44412127d1b1b4768c7ae2.json
  22. 1
      build-buffer/.module-cache/manifest/9dff733c4585512f6ed2deca306255214765bbe7.json
  23. 1
      build-buffer/.module-cache/manifest/9fc14ade32e04296d9f74634da69458d5595110f.json
  24. 1
      build-buffer/.module-cache/manifest/bb5e20b0dfe1177cc608549060d0883ef58e156b.json
  25. 1
      build-buffer/.module-cache/manifest/bd19abac2e2e24498b933499d1eff7ae0825111d.json
  26. 1
      build-buffer/.module-cache/manifest/d33e863ad34154f54a43fa2e43e161c04d397c4c.json
  27. 1
      build-buffer/.module-cache/manifest/d7e8646c084253b7cfd0f981f734a2b391aa60a5.json
  28. 1
      build-buffer/.module-cache/manifest/dea17f9cee8acb42aaea8c4b65723338c5d1feb2.json
  29. 1
      build-buffer/.module-cache/manifest/e2700f3eddcf47a0235b40f1879c236d04edfb9f.json
  30. 1
      build-buffer/.module-cache/manifest/e394633e8498d5a50e1a34cd73f803421446d4f3.json
  31. 231
      build-buffer/App.js
  32. 12
      build-buffer/common/EventListenerMixin.js
  33. 42
      build-buffer/common/MiniProfile.js
  34. 107
      build-buffer/common/Post.js
  35. 34
      build-buffer/common/Postboard.js
  36. 71
      build-buffer/common/ProfileMixin.js
  37. 62
      build-buffer/common/SafeStateChangeMixin.js
  38. 11
      build-buffer/common/SetIntervalMixin.js
  39. 60
      build-buffer/common/StreamMixin.js
  40. 183
      build-buffer/home/Home.js
  41. 77
      build-buffer/home/NewPostModalButton.js
  42. 84
      build-buffer/profile/Followings.js
  43. 51
      build-buffer/profile/Mentions.js
  44. 80
      build-buffer/profile/Profile.js
  45. 95
      build-buffer/profile/Timeline.js
  46. 12
      jsx/common/EventListenerMixin.js
  47. 42
      jsx/common/MiniProfile.js
  48. 107
      jsx/common/Post.js
  49. 34
      jsx/common/Postboard.js
  50. 71
      jsx/common/ProfileMixin.js
  51. 62
      jsx/common/SafeStateChangeMixin.js
  52. 11
      jsx/common/SetIntervalMixin.js
  53. 60
      jsx/common/StreamMixin.js
  54. 183
      jsx/home/Home.js
  55. 77
      jsx/home/NewPostModalButton.js
  56. 84
      jsx/profile/Followings.js
  57. 51
      jsx/profile/Mentions.js
  58. 80
      jsx/profile/Profile.js
  59. 95
      jsx/profile/Timeline.js

231
build-buffer/.module-cache/1481637775089844184af71820625492ebd04146.js vendored

@ -0,0 +1,231 @@
/*
var Router = require('react-router')
, RouteHandler = Router.RouteHandler
, Route = Router.Route;
var ReactRouterBootstrap = require('react-router-bootstrap')
, NavItemLink = ReactRouterBootstrap.NavItemLink
, ButtonLink = ReactRouterBootstrap.ButtonLink
, ListGroupItemLink = ReactRouterBootstrap.ListGroupItemLink;
*/
var ReactBootstrap = require('react-bootstrap')
, DropdownButton = ReactBootstrap.DropdownButton
, MenuItem = ReactBootstrap.MenuItem
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, OverlayTrigger = ReactBootstrap.OverlayTrigger
, Popover = ReactBootstrap.Popover
, Glyphicon = ReactBootstrap.Glyphicon
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
var React = require('react');
var Router = require('react-router');
var { Route, DefaultRoute, RouteHandler, Link } = Router;
var Home = require("./home/Home.js");
var Profile = require("./profile/Profile.js");
var SetIntervalMixin = require("./common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('./common/SafeStateChangeMixin.js');
var Timeline = require('./profile/Timeline.js');
var Followings = require('./profile/Followings.js');
var Mentions = require('./profile/Mentions.js');
App = React.createClass({displayName: "App",
mixins: [SetIntervalMixin,SafeStateChangeMixin],
contextTypes: {
router: React.PropTypes.func
},
getHandlerKey: function () {
var childDepth = 1; // assuming App is top-level route
var { router } = this.context;
//console.log(router.getCurrentParams())
if ( router.getCurrentRoutes()[childDepth] ) {
var key = router.getCurrentRoutes()[childDepth].name;
if (key=="home" || key=="profile-active" || key=="accountProfileMore") {key=key+"/"+this.state.activeAccount;}
var id = JSON.stringify(router.getCurrentParams());
if (id) { key += id; }
console.log(key);
return key;
} else {return "none"}
},
clearCache: function () {
localStorage.setItem("twister-cache", null);
},
saveCache: function () {
localStorage.setItem("twister-cache", JSON.stringify(Twister.serializeCache()))
},
switchAccount: function (newaccoutname) {
console.log(newaccoutname);
var thisComponent = this;
Twister.getAccount(newaccoutname).activateTorrents(function(){
thisComponent.setStateSafe({activeAccount: newaccoutname},function(){
localStorage.setItem("twister-react-activeAccount", newaccoutname);
});
});
},
getInitialState: function () {
Twister.deserializeCache(JSON.parse(localStorage.getItem("twister-cache")));
//this.clearCache();
var state={};
state.activeAccount = localStorage.getItem("twister-react-activeAccount")
state.pollInterval = 60;
state.pollIntervalProfile = 60*60;
state.accounts = Twister.getAccounts();
//console.log(state);
return state;
},
componentDidMount: function () {
var thisComponent = this;
if (this.state.accounts.length==0) {
Twister.init({
host: 'http://user:pwd@localhost:28332',
logfunc: function(log){console.log(log)}
});
Twister.loadServerAccounts(function(){
thisComponent.setStateSafe(function(state){
state.accounts = Twister.getAccounts();
//console.log(state.accounts);
state.activeAccount = state.accounts[0];
return state;
},function(){
thisComponent.switchAccount(thisComponent.state.activeAccount);
});
});
} else {
this.switchAccount(this.state.activeAccount);
}
this.setInterval(this.saveCache,300000);
},
render: function() {
var firstroute = this.context.router.getCurrentRoutes()[1].name;
//console.log(firstroute);
var userbuttons = [];
for (var i in this.state.accounts) {
userbuttons.push(
React.createElement(MenuItem, {
key: this.state.accounts[i],
bsStyle: this.state.accounts[i]==this.state.activeAccount ? 'primary' : 'default',
onClick: this.switchAccount.bind(this,this.state.accounts[i]),
href: "javascript:void(0);"
}, this.state.accounts[i])
);
}
return (
React.createElement(Grid, null,
React.createElement(Row, null,
React.createElement(Col, {xs: 12, sm: 10, smOffset: 1, md: 8, mdOffset: 2, lg: 6, lgOffset: 3},
React.createElement(ButtonGroup, {justified: true},
React.createElement(Button, {
href: "#",
bsStyle: firstroute=="home" ? 'primary' : 'default'
}, React.createElement(Glyphicon, {glyph: "home"})),
React.createElement(Button, {
href: "#/profile",
bsStyle: firstroute=="profile-active" ? 'primary' : 'default'
}, React.createElement(Glyphicon, {glyph: "user"})),
React.createElement(Button, {href: "#/directmessages"}, React.createElement(Glyphicon, {glyph: "transfer"})),
React.createElement(DropdownButton, {title: this.state.activeAccount},
userbuttons
),
React.createElement(DropdownButton, {title: React.createElement(Glyphicon, {glyph: "menu-hamburger"})},
React.createElement(MenuItem, {
onClick: this.clearCache,
href: "javascript:void(0);"
}, "Clear Cache"),
React.createElement(MenuItem, {href: "#/search"}, "Search"),
React.createElement(MenuItem, {href: "#/settings"}, "Settings"),
React.createElement(MenuItem, {href: "#/howtofollow"}, "How to Follow"),
React.createElement(MenuItem, {href: "#/trendinghashtags"}, "Trending Hashtags")
)
),
React.createElement("br", null),
React.createElement(RouteHandler, {
pollInterval: this.state.pollInterval,
pollIntervalProfile: this.state.pollIntervalProfile,
activeAccount: this.state.activeAccount,
key: this.getHandlerKey()}
)
)
)
)
);
}
});
var routes = (
React.createElement(Route, {handler: App, path: "/"},
React.createElement(Route, {name: "profile-active", path: "/profile", handler: Profile},
React.createElement(Route, {name: "profile-active-timeline", path: "timeline", handler: Timeline}),
React.createElement(Route, {name: "profile-active-followings", path: "followings", handler: Followings}),
React.createElement(Route, {name: "profile-active-mentions", path: "mentions", handler: Mentions}),
React.createElement(DefaultRoute, {name: "profile-active-timeline-default", handler: Timeline})
),
React.createElement(Route, {name: "profile", path: "/profile/:username", handler: Profile},
React.createElement(Route, {name: "profile-timeline", path: "timeline", handler: Timeline}),
React.createElement(Route, {name: "profile-followings", path: "followings", handler: Followings}),
React.createElement(Route, {name: "profile-mentions", path: "mentions", handler: Mentions}),
React.createElement(DefaultRoute, {name: "profile-timeline-default", handler: Timeline})
),
React.createElement(DefaultRoute, {name: "home", handler: Home})
)
);
Router.run(routes, function (Handler) {
React.render(React.createElement(Handler, null), document.getElementById('content'));
});
////// INIT EVENTLISTENERS ON WINDOW
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 50) {
var event = new Event('scrolledtobottom');
//alert("scrolled to bottom")
window.dispatchEvent(event);
}
};

71
build-buffer/.module-cache/20db71076a525ed87d3d9dfbd98c8b31be8c6896.js vendored

@ -0,0 +1,71 @@
module.exports = ProfileMixin = {
getInitialState: function() {
var username = this.props.username;
if (!username) {
username = (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount);
}
var state = {
username: username,
avatar: "img/genericPerson.png",
fullname: "",
bio: "",
location: "",
url: ""
};
var profile = Twister.getUser(username).getProfile();
if (profile.inCache()) {
state.fullname = profile.getField("fullname");
state.bio = profile.getField("bio");
state.location = profile.getField("location");
state.url = profile.getField("url");
}
var avatar = Twister.getUser(username).getAvatar();
if (avatar.inCache()) {
state.avatar = avatar.getUrl();
}
return state;
},
updateProfile: function () {
var thisComponent = this;
Twister.getUser(this.state.username).doAvatar(function(avatar){
if (avatar.getUrl()) {
thisComponent.setStateSafe({avatar: avatar.getUrl()});
}
});
Twister.getUser(this.state.username).doProfile(function(profile){
thisComponent.setStateSafe({
fullname: profile.getField("fullname"),
bio: profile.getField("bio"),
location: profile.getField("location"),
url: profile.getField("url"),
});
});
},
componentDidMount: function () {
this.updateProfile();
this.setInterval(this.updateProfile,this.props.pollIntervalProfile*1000);
}
};

60
build-buffer/.module-cache/242ec183241b4b53f4ddae69b8afb6b60426ec42.js vendored

@ -0,0 +1,60 @@
module.exports = StreamMixin = {
addPost: function(post) {
var postid = post.getUsername() + ":post" + post.getId();
if (!this.state.postIdentifiers[postid]) {
this.setStateSafe(function(previousState, currentProps) {
previousState.postIdentifiers[postid] = true;
if (post.isRetwist()){
var postdata = {
username: post.getRetwistedUser(),
retwistingUser: post.getUsername(),
content: post.getRetwistedContent(),
id: post.getRetwistedId(),
timestamp: post.getTimestamp(),
postid: postid,
isRetwist: true
}
} else {
var postdata = {
username: post.getUsername(),
content: post.getContent(),
id: post.getId(),
timestamp: post.getTimestamp(),
postid: postid,
isRetwist: false
}
}
previousState.data.push(postdata)
var compare = function (a,b) {
if (a.timestamp < b.timestamp)
return 1;
if (a.timestamp > b.timestamp)
return -1;
return 0;
}
previousState.data.sort(compare);
return {data: previousState.data, postIdentifiers: previousState.postIdentifiers };
});
} else {
}
}
}

80
build-buffer/.module-cache/299f979899a857c45bf2f5de63a5ca750da60433.js vendored

@ -0,0 +1,80 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
, ListGroup = ReactBootstrap.ListGroup
, Nav = ReactBootstrap.Nav
, NavItem = ReactBootstrap.NavItem
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
var React = require('react');
var Router = require('react-router');
var { Route, DefaultRoute, RouteHandler, Link } = Router;
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var ProfileMixin = require('../common/ProfileMixin.js');
module.exports = Post = React.createClass({displayName: "Post",
mixins: [SetIntervalMixin,SafeStateChangeMixin,ProfileMixin],
contextTypes: {
router: React.PropTypes.func
},
getHandlerKey: function () {
var childDepth = 2; // assuming App is top-level route
var { router } = this.context;
//console.log(router.getCurrentParams())
if ( router.getCurrentRoutes()[childDepth] ) {
var key = router.getCurrentRoutes()[childDepth].name;
if (key.indexOf("active")>-1) {key+="/"+this.props.activeAccount;}
var id = JSON.stringify(router.getCurrentParams());
if (id) { key += id; }
console.log(key);
return key;
} else {return "none"}
},
render: function() {
var routeprefix = "#/profile/"+(this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username+"/" : "")
var subroute = this.context.router.getCurrentRoutes()[2].name
console.log(this.context.router.getCurrentRoutes());
return (
React.createElement(ListGroup, {fill: true},
React.createElement(ListGroupItem, null,
React.createElement(Row, {className: "nomargin"},
React.createElement(Col, {xs: 3, md: 3, className: "fullytight"},
React.createElement("img", {className: "img-responsive", src: this.state.avatar})
),
React.createElement(Col, {xs: 8, md: 8},
React.createElement("h4", {className: "nomargin-top"}, this.state.fullname, React.createElement("small", null, "   ", '@'+this.state.username)),
React.createElement("p", {className: "text-center"}, this.state.location),
React.createElement("p", {className: "text-center"}, this.state.bio),
React.createElement("p", {className: "text-center"}, React.createElement("a", {href: this.state.url}, this.state.url))
),
React.createElement(Col, {xs: 1, md: 1, className: "fullytight text-align-right"})
)
),
React.createElement(ListGroupItem, {className: "fullytight_all"},
React.createElement(ButtonGroup, {justified: true},
React.createElement(Button, {href: routeprefix+"timeline", bsStyle: subroute.indexOf("timeline")>-1 ? "primary" : "default"}, React.createElement(Glyphicon, {glyph: "list"})),
React.createElement(Button, {href: routeprefix+"followings", bsStyle: subroute.indexOf("followings")>-1 ? "primary" : "default"}, React.createElement(Glyphicon, {glyph: "eye-open"})),
React.createElement(Button, {href: routeprefix+"mentions", bsStyle: subroute.indexOf("mentions")>-1 ? "primary" : "default"}, React.createElement(Glyphicon, {glyph: "comment"}))
)
),
React.createElement(RouteHandler, {
pollInterval: this.props.pollInterval,
pollIntervalProfile: this.props.pollIntervalProfile,
activeAccount: this.props.activeAccount,
key: this.getHandlerKey()}
)
)
);
}
});

183
build-buffer/.module-cache/38e3cc72af24ddb96884506416d1a140d84277fe.js vendored

@ -0,0 +1,183 @@
var React = require('react');
var Postboard = require("../common/Postboard.js");
var NewPostModalButton = require("../home/NewPostModalButton.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Home = React.createClass({displayName: "Home",
mixins: [
StreamMixin,
SetIntervalMixin,
SafeStateChangeMixin,
EventListenerMixin('scrolledtobottom'),
EventListenerMixin('newpostbyuser')
],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
data: [],
postIdentifiers: {},
usernames: [],
postrange: ( Date.now()/1000 - 12*60*60 ),
min_posts: 30
};
},
addUser: function(username) {
var thisComponent = this;
this.setStateSafe(function(previousState, currentProps){
previousState.usernames.push(username);
return previousState;
},function(){
Twister.getUser(username).doLatestPostsUntil(function(post){
if (post!==null) {
if(post.getTimestamp()<thisComponent.state.postrange) {
return false;
} else {
thisComponent.addPost(post);
//console.log("adding post",post.getUsername(),post.getId())
}
} else {
thisComponent.removeUser(thisUsername);
return false;
}
},{outdatedLimit: 2*thisComponent.props.pollInterval});
});
},
removeUser: function(username) {
this.setStateSafe(function(previousState, currentProps){
var newusers = [];
for (var i = 0; i<previousState.usernames.length; i++) {
if (previousState.usernames[i]!=username) {
newusers.push(previousState.usernames[i]);
}
}
previousState.usernames = newusers;
var newdata = [];
for (var i = 0; i<previousState.data.length; i++) {
if (previousState.data[i].username!=username) {
newusers.push(previousState.data[i]);
} else {
previousState.postIdentifiers[previousState.data[i].postid]=false;
}
}
previousState.data = newdata;
return previousState;
});
},
updatePosts: function(outdatedLimit) {
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
for (var i = 0; i<this.state.usernames.length; i++) {
var thisComponent = this;
var thisUsername = this.state.usernames[i];
Twister.getUser(thisUsername).doLatestPostsUntil(function(post){
if (post!==null) {
if(post.getTimestamp()<thisComponent.state.postrange) {
return false;
} else {
thisComponent.addPost(post);
//console.log("adding post",post.getUsername(),post.getId())
}
} else {
thisComponent.removeUser(thisUsername);
return false;
}
},{outdatedLimit: outdatedLimit});
}
},
componentDidMount: function() {
if (this.props.activeAccount) {
console.log("active account is "+this.props.activeAccount)
var thisComponent = this;
var username=this.props.activeAccount;
thisComponent.addUser(username);
Twister.getUser(username).doFollowings(function(followings){
for(var i in followings){
thisComponent.addUser(followings[i].getUsername());
//console.log(followings[i].getUsername())
}
//thisComponent.updatePosts(thisComponent.props.pollInterval);
});
this.setInterval(this.updatePosts, this.props.pollInterval*1000);
} else {console.log("active account is null")}
},
onscrolledtobottom: function () {
this.setStateSafe(function(previousState, currentProps){
previousState.postrange -= 6*60*60;
return previousState;
},function(){
this.updatePosts(2*this.props.pollInterval);
});
},
onnewpostbyuser: function (event) {
for (var i in this.state.usernames) {
if(this.state.usernames[i]==event.detail.getUsername()) {
this.addPost(event.detail);
}
}
},
render: function() {
return (
React.createElement(Postboard, {data: this.state.data, header:
React.createElement(ListGroupItem, null,
"Home",
React.createElement(NewPostModalButton, {activeAccount: this.props.activeAccount})
)
})
);
}
});

77
build-buffer/.module-cache/7b5f4f98c79393354f44412127d1b1b4768c7ae2.js vendored

@ -0,0 +1,77 @@
var ReactBootstrap = require('react-bootstrap')
, OverlayMixin = ReactBootstrap.OverlayMixin
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
, Modal = ReactBootstrap.Modal
, Input = ReactBootstrap.Input
var React = require('react');
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
module.exports = NewPostModalButton = React.createClass({displayName: "NewPostModalButton",
mixins: [OverlayMixin],
getInitialState: function () {
return {
isModalOpen: false
};
},
handleToggle: function () {
this.setState({
isModalOpen: !this.state.isModalOpen
});
},
handleNewPost: function (e) {
e.preventDefault();
//console.log(e)
var msg = JSON.parse(JSON.stringify(e.target[0].value));
if (!msg) {
console.log("empty post was passed as new post")
return;
}
Twister.getAccount(this.props.activeAccount).post(msg,function(post){
var event = new CustomEvent('newpostbyuser',{detail: post});
//alert("scrolled to bottom")
window.dispatchEvent(event);
});
e.target[0].value = "";
this.handleToggle();
//React.findDOMNode(this.refs.msg).value = '';
return;
},
render: function() {
return (
React.createElement(Button, {onClick: this.handleToggle, className: "link-button-gray pull-right fullytight_all", bsStyle: "link"},
React.createElement(Glyphicon, {glyph: "pencil"})
)
);
},
renderOverlay: function() {
if (!this.state.isModalOpen) {
return React.createElement("span", null);
}
return (
React.createElement(Modal, {bsStyle: "primary", title: React.createElement(Glyphicon, {glyph: "pencil"}), onRequestHide: this.handleToggle},
React.createElement("div", {className: "modal-body"},
React.createElement("form", {onSubmit: this.handleNewPost},
React.createElement(Input, {type: "textarea", label: "Text Area", placeholder: "textarea"}),
React.createElement(Input, {type: "submit", value: "Submit button", "data-dismiss": "modal"})
)
)
)
);
}
});

84
build-buffer/.module-cache/9dff733c4585512f6ed2deca306255214765bbe7.js vendored

@ -0,0 +1,84 @@
var React = require('react/addons');
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var MiniProfile = require("../common/MiniProfile.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Home = React.createClass({displayName: "Home",
mixins: [SetIntervalMixin,SafeStateChangeMixin],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
followings: []
};
},
updateFollowings: function(outdatedLimit) {
thisComponent=this;
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
Twister.getUser(this.state.username).doFollowings(function(followings){
thisComponent.setStateSafe(function(state){
var newfollowings = [];
for(var i in followings){
newfollowings.push(followings[i].getUsername());
}
state.followings = newfollowings;
return state;
});
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updateFollowings(this.props.pollInterval*2);
this.setInterval(this.updateFollowings, this.props.pollInterval*1000);
},
render: function() {
var thisComponent = this;
var profiles = this.state.followings.map(function(username, index) {
return (
React.createElement(MiniProfile, {username: username, key: "miniprofile:"+username, pollIntervalProfile: thisComponent.props.pollIntervalProfile})
);
});
return (
React.createElement(ListGroup, {fill: true},
React.createElement(ReactCSSTransitionGroup, {transitionName: "item"},
profiles
)
)
);
}
});

12
build-buffer/.module-cache/9fc14ade32e04296d9f74634da69458d5595110f.js vendored

@ -0,0 +1,12 @@
module.exports = EventListenerMixin = function (eventtype) {
return {
componentDidMount: function() {
window.addEventListener(eventtype, this["on"+eventtype]);
},
componentWillUnmount: function() {
window.removeEventListener(eventtype, this["on"+eventtype]);
}
}
}

95
build-buffer/.module-cache/bb5e20b0dfe1177cc608549060d0883ef58e156b.js vendored

@ -0,0 +1,95 @@
var React = require('react');
var Postboard = require("../common/Postboard.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Timeline = React.createClass({displayName: "Timeline",
mixins:[
StreamMixin,
SetIntervalMixin,
SafeStateChangeMixin,
EventListenerMixin('scrolledtobottom'),
EventListenerMixin('newpostbyuser')
],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
data: [],
postIdentifiers: {},
postCount: 30
};
},
updatePosts: function(outdatedLimit) {
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
var thisComponent = this;
var thisUsername = this.state.username;
var count = 0;
Twister.getUser(this.state.username).doLatestPostsUntil(function(post){
//console.log(count)
if (post!==null) {
if(count++>=thisComponent.state.postCount) {
return false;
} else {
thisComponent.addPost(post);
}
} else {
return false;
}
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updatePosts(2*this.props.pollInterval);
this.setInterval(this.updatePosts, this.props.pollInterval*1000);
console.log(this.props.pollInterval)
},
onscrolledtobottom: function () {
this.setStateSafe(function(previousState, currentProps){
previousState.postrange += 10;
return previousState;
},function(){
this.updatePosts(2*this.props.pollInterval);
});
},
onnewpostbyuser: function (event) {
//alert("got event")
if(this.state.username==event.post.getUsername()) {
this.addPost(event.post);
}
},
render: function() {
return (
React.createElement(Postboard, {data: this.state.data, header: ""})
);
}
});

51
build-buffer/.module-cache/bd19abac2e2e24498b933499d1eff7ae0825111d.js vendored

@ -0,0 +1,51 @@
var React = require('react');
var MiniProfile = require("../common/MiniProfile.js");
var Postboard = require("../common/Postboard.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
module.exports = Home = React.createClass({displayName: "Home",
mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
data: [],
postIdentifiers: {}
};
},
updateMentions: function(outdatedLimit) {
thisComponent=this;
if (outdatedLimit===undefined) {outdatedLimit=this.props.pollInterval/2;}
Twister.getUser(this.state.username).doMentions(function(mentions){
for(var i in mentions){
thisComponent.addPost(mentions[i]);
}
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updateMentions(this.props.pollInterval*2);
this.setInterval(this.updateMentions, this.props.pollInterval*1000);
},
render: function() {
return (
React.createElement(Postboard, {data: this.state.data, header: ""})
);
}
});

42
build-buffer/.module-cache/d33e863ad34154f54a43fa2e43e161c04d397c4c.js vendored

@ -0,0 +1,42 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
, ListGroup = ReactBootstrap.ListGroup
, Nav = ReactBootstrap.Nav
, NavItem = ReactBootstrap.NavItem
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
var React = require('react');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var ProfileMixin = require('../common/ProfileMixin.js');
module.exports = MiniProfile = React.createClass({displayName: "MiniProfile",
mixins: [SetIntervalMixin,SafeStateChangeMixin,ProfileMixin],
render: function() {
return (
React.createElement(ListGroupItem, null,
React.createElement(Row, {className: "nomargin"},
React.createElement(Col, {xs: 2, md: 2, className: "fullytight"},
React.createElement("a", {href: "#/profile/"+this.props.username},
React.createElement("img", {className: "img-responsive", src: this.state.avatar})
)
),
React.createElement(Col, {xs: 9, md: 9},
React.createElement("h5", {className: "nomargin-top"},
this.state.fullname, React.createElement("small", null, "   ", '@'+this.props.username)
),
React.createElement("p", null, this.state.bio)
),
React.createElement(Col, {xs: 1, md: 1, className: "fullytight text-align-right"})
)
)
);
}
});

107
build-buffer/.module-cache/d7e8646c084253b7cfd0f981f734a2b391aa60a5.js vendored

@ -0,0 +1,107 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
var React = require('react');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
module.exports = Post = React.createClass({displayName: "Post",
mixins: [SetIntervalMixin,SafeStateChangeMixin],
getInitialState: function() {
return {
avatar: "img/genericPerson.png",
fullname: "",
retwistingUser: this.props.post.retwistingUser,
timeAgo: ""
};
},
updateTimeAgo: function() {
var secondsAgo = Date.now()/1000-this.props.post.timestamp;
var newTimeAgo = "";
if (secondsAgo<45) {newTimeAgo="1m"}
else if (secondsAgo<45*60) {newTimeAgo=Math.round(secondsAgo/60)+"m"}
else if (secondsAgo<18*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"}
else if (secondsAgo<26*24*60*60) {newTimeAgo=Math.round(secondsAgo/24/60/60)+"d"}
else if (secondsAgo<9*30.5*24*60*60) {newTimeAgo=Math.round(secondsAgo/30.5/24/60/60)+"mo"}
else {newTimeAgo=Math.round(secondsAgo/365/24/60/60)+"y"}
this.setStateSafe({timeAgo: newTimeAgo});
},
componentDidMount: function () {
var thisComponent = this;
//console.log(this.props.post.username+":post"+this.props.post.id);
Twister.getUser(this.props.post.username).doAvatar(function(avatar){
if (avatar.getUrl()) {
thisComponent.setStateSafe({avatar: avatar.getUrl()});
}
});
Twister.getUser(this.props.post.username).doProfile(function(profile){
thisComponent.setStateSafe({fullname: profile.getField("fullname")});
});
if (this.props.post.isRetwist) {
Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){
thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")});
});
}
this.updateTimeAgo();
this.setInterval(this.updateTimeAgo,60000);
},
render: function() {
var post = this.props.post;
return (
React.createElement(ListGroupItem, null,
React.createElement(Row, {className: "nomargin"},
React.createElement(Col, {xs: 2, md: 2, className: "fullytight"},
React.createElement("a", {href: "#/profile/"+this.props.post.username},
React.createElement("img", {className: "img-responsive", src: this.state.avatar})
)
),
React.createElement(Col, {xs: 9, md: 9},
React.createElement("strong", null, this.state.fullname), " ",
post.content
),
React.createElement(Col, {xs: 1, md: 1, className: "fullytight text-align-right"}, this.state.timeAgo)
),
React.createElement(Row, {className: "nomargin"},
React.createElement(Col, {xs: 6, md: 6, className: "fullytight"},
post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser))
),
React.createElement(Col, {xs: 6, md: 6, className: "fullytight text-align-right"}, React.createElement("small", null, React.createElement("em", null, "test")))
)
)
);
}
});
/*
<div className="post-avatar">
<img src={this.state.avatar}/>
</div>
<div className="post-bulk">
<div className="post-username">
<span className="post-fullname">{this.state.fullname} </span>
@{post.username} - {post.id}
</div>
<div className="post-timestamp">{post.timestamp}</div>
<div className="post-content">{post.content}</div>
</div>
<hr/>
*/

11
build-buffer/.module-cache/dea17f9cee8acb42aaea8c4b65723338c5d1feb2.js vendored

@ -0,0 +1,11 @@
module.exports = SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.map(clearInterval);
}
};

62
build-buffer/.module-cache/e2700f3eddcf47a0235b40f1879c236d04edfb9f.js vendored

@ -0,0 +1,62 @@
function isValidLifeCycleForReplaceState(instance) {
// See function validateLifeCycleOnReplaceState(instance) in
// ReactCompositeComponent.js
var result = true;
//result &= ReactCurrentOwner.current == null;
//result &= __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || __REACT_DEVTOOLS_GLOBAL_HOOK__._reactRuntime.CurrentOwner.current == null;
result &= instance.isMounted();
return result;
}
var safeStateChangeMixin = {
/**
* Calls setState with the provided parameters if it is safe to do so.
*
* Safe means it will try to do the same checks as setState does
* without throwing an exception.
* See function validateLifeCycleOnReplaceState(instance) in
* ReactCompositeComponent.js
*
* @param {object} partialState Next partial state to be merged with state.
* @param {?function} callback Called after state is updated.
* @return {boolean} Whether or not setState is called.
* @final
* @protected
*/
setStateSafe: function (partialState, callback) {
if (isValidLifeCycleForReplaceState(this)) {
this.setState(partialState, callback);
return true;
}
return false;
},
/**
* Calls replaceState with the provided parameters if it safe to do so.
*
* Safe means it will try to do the same checks as replaceState does
* without throwing an exception.
* See function validateLifeCycleOnReplaceState(instance) in
* ReactCompositeComponent.js
*
* @param {object} completeState Next state.
* @param {?function} callback Called after state is updated.
* @return {boolean} Whether or not setState is called.
* @final
* @protected
*/
replaceStateSafe: function(completeState, callback) {
if (isValidLifeCycleForReplaceState(this)) {
this.replaceState(completeState, callback);
return true;
}
return false;
}
};
module.exports = safeStateChangeMixin;

34
build-buffer/.module-cache/e394633e8498d5a50e1a34cd73f803421446d4f3.js vendored

@ -0,0 +1,34 @@
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
var React = require('react/addons');
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var Post = require("../common/Post.js");
module.exports = Postboard = React.createClass({displayName: "Postboard",
render: function() {
var posts = this.props.data.map(function(post, index) {
return (
React.createElement(Post, {post: post, key: post.postid})
);
});
return (
React.createElement(ListGroup, {fill: true},
this.props.header,
React.createElement(ReactCSSTransitionGroup, {transitionName: "item"},
posts
)
)
);
}
});

1
build-buffer/.module-cache/manifest/1481637775089844184af71820625492ebd04146.json vendored

@ -0,0 +1 @@
{".js":"1481637775089844184af71820625492ebd04146.js"}

1
build-buffer/.module-cache/manifest/20db71076a525ed87d3d9dfbd98c8b31be8c6896.json vendored

@ -0,0 +1 @@
{".js":"20db71076a525ed87d3d9dfbd98c8b31be8c6896.js"}

1
build-buffer/.module-cache/manifest/242ec183241b4b53f4ddae69b8afb6b60426ec42.json vendored

@ -0,0 +1 @@
{".js":"242ec183241b4b53f4ddae69b8afb6b60426ec42.js"}

1
build-buffer/.module-cache/manifest/299f979899a857c45bf2f5de63a5ca750da60433.json vendored

@ -0,0 +1 @@
{".js":"299f979899a857c45bf2f5de63a5ca750da60433.js"}

1
build-buffer/.module-cache/manifest/38e3cc72af24ddb96884506416d1a140d84277fe.json vendored

@ -0,0 +1 @@
{".js":"38e3cc72af24ddb96884506416d1a140d84277fe.js"}

1
build-buffer/.module-cache/manifest/7b5f4f98c79393354f44412127d1b1b4768c7ae2.json vendored

@ -0,0 +1 @@
{".js":"7b5f4f98c79393354f44412127d1b1b4768c7ae2.js"}

1
build-buffer/.module-cache/manifest/9dff733c4585512f6ed2deca306255214765bbe7.json vendored

@ -0,0 +1 @@
{".js":"9dff733c4585512f6ed2deca306255214765bbe7.js"}

1
build-buffer/.module-cache/manifest/9fc14ade32e04296d9f74634da69458d5595110f.json vendored

@ -0,0 +1 @@
{".js":"9fc14ade32e04296d9f74634da69458d5595110f.js"}

1
build-buffer/.module-cache/manifest/bb5e20b0dfe1177cc608549060d0883ef58e156b.json vendored

@ -0,0 +1 @@
{".js":"bb5e20b0dfe1177cc608549060d0883ef58e156b.js"}

1
build-buffer/.module-cache/manifest/bd19abac2e2e24498b933499d1eff7ae0825111d.json vendored

@ -0,0 +1 @@
{".js":"bd19abac2e2e24498b933499d1eff7ae0825111d.js"}

1
build-buffer/.module-cache/manifest/d33e863ad34154f54a43fa2e43e161c04d397c4c.json vendored

@ -0,0 +1 @@
{".js":"d33e863ad34154f54a43fa2e43e161c04d397c4c.js"}

1
build-buffer/.module-cache/manifest/d7e8646c084253b7cfd0f981f734a2b391aa60a5.json vendored

@ -0,0 +1 @@
{".js":"d7e8646c084253b7cfd0f981f734a2b391aa60a5.js"}

1
build-buffer/.module-cache/manifest/dea17f9cee8acb42aaea8c4b65723338c5d1feb2.json vendored

@ -0,0 +1 @@
{".js":"dea17f9cee8acb42aaea8c4b65723338c5d1feb2.js"}

1
build-buffer/.module-cache/manifest/e2700f3eddcf47a0235b40f1879c236d04edfb9f.json vendored

@ -0,0 +1 @@
{".js":"e2700f3eddcf47a0235b40f1879c236d04edfb9f.js"}

1
build-buffer/.module-cache/manifest/e394633e8498d5a50e1a34cd73f803421446d4f3.json vendored

@ -0,0 +1 @@
{".js":"e394633e8498d5a50e1a34cd73f803421446d4f3.js"}

231
build-buffer/App.js

@ -0,0 +1,231 @@
/*
var Router = require('react-router')
, RouteHandler = Router.RouteHandler
, Route = Router.Route;
var ReactRouterBootstrap = require('react-router-bootstrap')
, NavItemLink = ReactRouterBootstrap.NavItemLink
, ButtonLink = ReactRouterBootstrap.ButtonLink
, ListGroupItemLink = ReactRouterBootstrap.ListGroupItemLink;
*/
var ReactBootstrap = require('react-bootstrap')
, DropdownButton = ReactBootstrap.DropdownButton
, MenuItem = ReactBootstrap.MenuItem
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, OverlayTrigger = ReactBootstrap.OverlayTrigger
, Popover = ReactBootstrap.Popover
, Glyphicon = ReactBootstrap.Glyphicon
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
var React = require('react');
var Router = require('react-router');
var { Route, DefaultRoute, RouteHandler, Link } = Router;
var Home = require("./home/Home.js");
var Profile = require("./profile/Profile.js");
var SetIntervalMixin = require("./common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('./common/SafeStateChangeMixin.js');
var Timeline = require('./profile/Timeline.js');
var Followings = require('./profile/Followings.js');
var Mentions = require('./profile/Mentions.js');
App = React.createClass({displayName: "App",
mixins: [SetIntervalMixin,SafeStateChangeMixin],
contextTypes: {
router: React.PropTypes.func
},
getHandlerKey: function () {
var childDepth = 1; // assuming App is top-level route
var { router } = this.context;
//console.log(router.getCurrentParams())
if ( router.getCurrentRoutes()[childDepth] ) {
var key = router.getCurrentRoutes()[childDepth].name;
if (key=="home" || key=="profile-active" || key=="accountProfileMore") {key=key+"/"+this.state.activeAccount;}
var id = JSON.stringify(router.getCurrentParams());
if (id) { key += id; }
console.log(key);
return key;
} else {return "none"}
},
clearCache: function () {
localStorage.setItem("twister-cache", null);
},
saveCache: function () {
localStorage.setItem("twister-cache", JSON.stringify(Twister.serializeCache()))
},
switchAccount: function (newaccoutname) {
console.log(newaccoutname);
var thisComponent = this;
Twister.getAccount(newaccoutname).activateTorrents(function(){
thisComponent.setStateSafe({activeAccount: newaccoutname},function(){
localStorage.setItem("twister-react-activeAccount", newaccoutname);
});
});
},
getInitialState: function () {
Twister.deserializeCache(JSON.parse(localStorage.getItem("twister-cache")));
//this.clearCache();
var state={};
state.activeAccount = localStorage.getItem("twister-react-activeAccount")
state.pollInterval = 60;
state.pollIntervalProfile = 60*60;
state.accounts = Twister.getAccounts();
//console.log(state);
return state;
},
componentDidMount: function () {
var thisComponent = this;
if (this.state.accounts.length==0) {
Twister.init({
host: 'http://user:pwd@localhost:28332',
logfunc: function(log){console.log(log)}
});
Twister.loadServerAccounts(function(){
thisComponent.setStateSafe(function(state){
state.accounts = Twister.getAccounts();
//console.log(state.accounts);
state.activeAccount = state.accounts[0];
return state;
},function(){
thisComponent.switchAccount(thisComponent.state.activeAccount);
});
});
} else {
this.switchAccount(this.state.activeAccount);
}
this.setInterval(this.saveCache,300000);
},
render: function() {
var firstroute = this.context.router.getCurrentRoutes()[1].name;
//console.log(firstroute);
var userbuttons = [];
for (var i in this.state.accounts) {
userbuttons.push(
React.createElement(MenuItem, {
key: this.state.accounts[i],
bsStyle: this.state.accounts[i]==this.state.activeAccount ? 'primary' : 'default',
onClick: this.switchAccount.bind(this,this.state.accounts[i]),
href: "javascript:void(0);"
}, this.state.accounts[i])
);
}
return (
React.createElement(Grid, null,
React.createElement(Row, null,
React.createElement(Col, {xs: 12, sm: 10, smOffset: 1, md: 8, mdOffset: 2, lg: 6, lgOffset: 3},
React.createElement(ButtonGroup, {justified: true},
React.createElement(Button, {
href: "#",
bsStyle: firstroute=="home" ? 'primary' : 'default'
}, React.createElement(Glyphicon, {glyph: "home"})),
React.createElement(Button, {
href: "#/profile",
bsStyle: firstroute=="profile-active" ? 'primary' : 'default'
}, React.createElement(Glyphicon, {glyph: "user"})),
React.createElement(Button, {href: "#/directmessages"}, React.createElement(Glyphicon, {glyph: "transfer"})),
React.createElement(DropdownButton, {title: this.state.activeAccount},
userbuttons
),
React.createElement(DropdownButton, {title: React.createElement(Glyphicon, {glyph: "menu-hamburger"})},
React.createElement(MenuItem, {
onClick: this.clearCache,
href: "javascript:void(0);"
}, "Clear Cache"),
React.createElement(MenuItem, {href: "#/search"}, "Search"),
React.createElement(MenuItem, {href: "#/settings"}, "Settings"),
React.createElement(MenuItem, {href: "#/howtofollow"}, "How to Follow"),
React.createElement(MenuItem, {href: "#/trendinghashtags"}, "Trending Hashtags")
)
),
React.createElement("br", null),
React.createElement(RouteHandler, {
pollInterval: this.state.pollInterval,
pollIntervalProfile: this.state.pollIntervalProfile,
activeAccount: this.state.activeAccount,
key: this.getHandlerKey()}
)
)
)
)
);
}
});
var routes = (
React.createElement(Route, {handler: App, path: "/"},
React.createElement(Route, {name: "profile-active", path: "/profile", handler: Profile},
React.createElement(Route, {name: "profile-active-timeline", path: "timeline", handler: Timeline}),
React.createElement(Route, {name: "profile-active-followings", path: "followings", handler: Followings}),
React.createElement(Route, {name: "profile-active-mentions", path: "mentions", handler: Mentions}),
React.createElement(DefaultRoute, {name: "profile-active-timeline-default", handler: Timeline})
),
React.createElement(Route, {name: "profile", path: "/profile/:username", handler: Profile},
React.createElement(Route, {name: "profile-timeline", path: "timeline", handler: Timeline}),
React.createElement(Route, {name: "profile-followings", path: "followings", handler: Followings}),
React.createElement(Route, {name: "profile-mentions", path: "mentions", handler: Mentions}),
React.createElement(DefaultRoute, {name: "profile-timeline-default", handler: Timeline})
),
React.createElement(DefaultRoute, {name: "home", handler: Home})
)
);
Router.run(routes, function (Handler) {
React.render(React.createElement(Handler, null), document.getElementById('content'));
});
////// INIT EVENTLISTENERS ON WINDOW
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 50) {
var event = new Event('scrolledtobottom');
//alert("scrolled to bottom")
window.dispatchEvent(event);
}
};

12
build-buffer/common/EventListenerMixin.js

@ -0,0 +1,12 @@
module.exports = EventListenerMixin = function (eventtype) {
return {
componentDidMount: function() {
window.addEventListener(eventtype, this["on"+eventtype]);
},
componentWillUnmount: function() {
window.removeEventListener(eventtype, this["on"+eventtype]);
}
}
}

42
build-buffer/common/MiniProfile.js

@ -0,0 +1,42 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
, ListGroup = ReactBootstrap.ListGroup
, Nav = ReactBootstrap.Nav
, NavItem = ReactBootstrap.NavItem
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
var React = require('react');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var ProfileMixin = require('../common/ProfileMixin.js');
module.exports = MiniProfile = React.createClass({displayName: "MiniProfile",
mixins: [SetIntervalMixin,SafeStateChangeMixin,ProfileMixin],
render: function() {
return (
React.createElement(ListGroupItem, null,
React.createElement(Row, {className: "nomargin"},
React.createElement(Col, {xs: 2, md: 2, className: "fullytight"},
React.createElement("a", {href: "#/profile/"+this.props.username},
React.createElement("img", {className: "img-responsive", src: this.state.avatar})
)
),
React.createElement(Col, {xs: 9, md: 9},
React.createElement("h5", {className: "nomargin-top"},
this.state.fullname, React.createElement("small", null, "   ", '@'+this.props.username)
),
React.createElement("p", null, this.state.bio)
),
React.createElement(Col, {xs: 1, md: 1, className: "fullytight text-align-right"})
)
)
);
}
});

107
build-buffer/common/Post.js

@ -0,0 +1,107 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
var React = require('react');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
module.exports = Post = React.createClass({displayName: "Post",
mixins: [SetIntervalMixin,SafeStateChangeMixin],
getInitialState: function() {
return {
avatar: "img/genericPerson.png",
fullname: "",
retwistingUser: this.props.post.retwistingUser,
timeAgo: ""
};
},
updateTimeAgo: function() {
var secondsAgo = Date.now()/1000-this.props.post.timestamp;
var newTimeAgo = "";
if (secondsAgo<45) {newTimeAgo="1m"}
else if (secondsAgo<45*60) {newTimeAgo=Math.round(secondsAgo/60)+"m"}
else if (secondsAgo<18*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"}
else if (secondsAgo<26*24*60*60) {newTimeAgo=Math.round(secondsAgo/24/60/60)+"d"}
else if (secondsAgo<9*30.5*24*60*60) {newTimeAgo=Math.round(secondsAgo/30.5/24/60/60)+"mo"}
else {newTimeAgo=Math.round(secondsAgo/365/24/60/60)+"y"}
this.setStateSafe({timeAgo: newTimeAgo});
},
componentDidMount: function () {
var thisComponent = this;
//console.log(this.props.post.username+":post"+this.props.post.id);
Twister.getUser(this.props.post.username).doAvatar(function(avatar){
if (avatar.getUrl()) {
thisComponent.setStateSafe({avatar: avatar.getUrl()});
}
});
Twister.getUser(this.props.post.username).doProfile(function(profile){
thisComponent.setStateSafe({fullname: profile.getField("fullname")});
});
if (this.props.post.isRetwist) {
Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){
thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")});
});
}
this.updateTimeAgo();
this.setInterval(this.updateTimeAgo,60000);
},
render: function() {
var post = this.props.post;
return (
React.createElement(ListGroupItem, null,
React.createElement(Row, {className: "nomargin"},
React.createElement(Col, {xs: 2, md: 2, className: "fullytight"},
React.createElement("a", {href: "#/profile/"+this.props.post.username},
React.createElement("img", {className: "img-responsive", src: this.state.avatar})
)
),
React.createElement(Col, {xs: 9, md: 9},
React.createElement("strong", null, this.state.fullname), " ",
post.content
),
React.createElement(Col, {xs: 1, md: 1, className: "fullytight text-align-right"}, this.state.timeAgo)
),
React.createElement(Row, {className: "nomargin"},
React.createElement(Col, {xs: 6, md: 6, className: "fullytight"},
post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser))
),
React.createElement(Col, {xs: 6, md: 6, className: "fullytight text-align-right"}, React.createElement("small", null, React.createElement("em", null, "test")))
)
)
);
}
});
/*
<div className="post-avatar">
<img src={this.state.avatar}/>
</div>
<div className="post-bulk">
<div className="post-username">
<span className="post-fullname">{this.state.fullname} </span>
@{post.username} - {post.id}
</div>
<div className="post-timestamp">{post.timestamp}</div>
<div className="post-content">{post.content}</div>
</div>
<hr/>
*/

34
build-buffer/common/Postboard.js

@ -0,0 +1,34 @@
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
var React = require('react/addons');
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var Post = require("../common/Post.js");
module.exports = Postboard = React.createClass({displayName: "Postboard",
render: function() {
var posts = this.props.data.map(function(post, index) {
return (
React.createElement(Post, {post: post, key: post.postid})
);
});
return (
React.createElement(ListGroup, {fill: true},
this.props.header,
React.createElement(ReactCSSTransitionGroup, {transitionName: "item"},
posts
)
)
);
}
});

71
build-buffer/common/ProfileMixin.js

@ -0,0 +1,71 @@
module.exports = ProfileMixin = {
getInitialState: function() {
var username = this.props.username;
if (!username) {
username = (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount);
}
var state = {
username: username,
avatar: "img/genericPerson.png",
fullname: "",
bio: "",
location: "",
url: ""
};
var profile = Twister.getUser(username).getProfile();
if (profile.inCache()) {
state.fullname = profile.getField("fullname");
state.bio = profile.getField("bio");
state.location = profile.getField("location");
state.url = profile.getField("url");
}
var avatar = Twister.getUser(username).getAvatar();
if (avatar.inCache()) {
state.avatar = avatar.getUrl();
}
return state;
},
updateProfile: function () {
var thisComponent = this;
Twister.getUser(this.state.username).doAvatar(function(avatar){
if (avatar.getUrl()) {
thisComponent.setStateSafe({avatar: avatar.getUrl()});
}
});
Twister.getUser(this.state.username).doProfile(function(profile){
thisComponent.setStateSafe({
fullname: profile.getField("fullname"),
bio: profile.getField("bio"),
location: profile.getField("location"),
url: profile.getField("url"),
});
});
},
componentDidMount: function () {
this.updateProfile();
this.setInterval(this.updateProfile,this.props.pollIntervalProfile*1000);
}
};

62
build-buffer/common/SafeStateChangeMixin.js

@ -0,0 +1,62 @@
function isValidLifeCycleForReplaceState(instance) {
// See function validateLifeCycleOnReplaceState(instance) in
// ReactCompositeComponent.js
var result = true;
//result &= ReactCurrentOwner.current == null;
//result &= __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || __REACT_DEVTOOLS_GLOBAL_HOOK__._reactRuntime.CurrentOwner.current == null;
result &= instance.isMounted();
return result;
}
var safeStateChangeMixin = {
/**
* Calls setState with the provided parameters if it is safe to do so.
*
* Safe means it will try to do the same checks as setState does
* without throwing an exception.
* See function validateLifeCycleOnReplaceState(instance) in
* ReactCompositeComponent.js
*
* @param {object} partialState Next partial state to be merged with state.
* @param {?function} callback Called after state is updated.
* @return {boolean} Whether or not setState is called.
* @final
* @protected
*/
setStateSafe: function (partialState, callback) {
if (isValidLifeCycleForReplaceState(this)) {
this.setState(partialState, callback);
return true;
}
return false;
},
/**
* Calls replaceState with the provided parameters if it safe to do so.
*
* Safe means it will try to do the same checks as replaceState does
* without throwing an exception.
* See function validateLifeCycleOnReplaceState(instance) in
* ReactCompositeComponent.js
*
* @param {object} completeState Next state.
* @param {?function} callback Called after state is updated.
* @return {boolean} Whether or not setState is called.
* @final
* @protected
*/
replaceStateSafe: function(completeState, callback) {
if (isValidLifeCycleForReplaceState(this)) {
this.replaceState(completeState, callback);
return true;
}
return false;
}
};
module.exports = safeStateChangeMixin;

11
build-buffer/common/SetIntervalMixin.js

@ -0,0 +1,11 @@
module.exports = SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.map(clearInterval);
}
};

60
build-buffer/common/StreamMixin.js

@ -0,0 +1,60 @@
module.exports = StreamMixin = {
addPost: function(post) {
var postid = post.getUsername() + ":post" + post.getId();
if (!this.state.postIdentifiers[postid]) {
this.setStateSafe(function(previousState, currentProps) {
previousState.postIdentifiers[postid] = true;
if (post.isRetwist()){
var postdata = {
username: post.getRetwistedUser(),
retwistingUser: post.getUsername(),
content: post.getRetwistedContent(),
id: post.getRetwistedId(),
timestamp: post.getTimestamp(),
postid: postid,
isRetwist: true
}
} else {
var postdata = {
username: post.getUsername(),
content: post.getContent(),
id: post.getId(),
timestamp: post.getTimestamp(),
postid: postid,
isRetwist: false
}
}
previousState.data.push(postdata)
var compare = function (a,b) {
if (a.timestamp < b.timestamp)
return 1;
if (a.timestamp > b.timestamp)
return -1;
return 0;
}
previousState.data.sort(compare);
return {data: previousState.data, postIdentifiers: previousState.postIdentifiers };
});
} else {
}
}
}

183
build-buffer/home/Home.js

@ -0,0 +1,183 @@
var React = require('react');
var Postboard = require("../common/Postboard.js");
var NewPostModalButton = require("../home/NewPostModalButton.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Home = React.createClass({displayName: "Home",
mixins: [
StreamMixin,
SetIntervalMixin,
SafeStateChangeMixin,
EventListenerMixin('scrolledtobottom'),
EventListenerMixin('newpostbyuser')
],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
data: [],
postIdentifiers: {},
usernames: [],
postrange: ( Date.now()/1000 - 12*60*60 ),
min_posts: 30
};
},
addUser: function(username) {
var thisComponent = this;
this.setStateSafe(function(previousState, currentProps){
previousState.usernames.push(username);
return previousState;
},function(){
Twister.getUser(username).doLatestPostsUntil(function(post){
if (post!==null) {
if(post.getTimestamp()<thisComponent.state.postrange) {
return false;
} else {
thisComponent.addPost(post);
//console.log("adding post",post.getUsername(),post.getId())
}
} else {
thisComponent.removeUser(thisUsername);
return false;
}
},{outdatedLimit: 2*thisComponent.props.pollInterval});
});
},
removeUser: function(username) {
this.setStateSafe(function(previousState, currentProps){
var newusers = [];
for (var i = 0; i<previousState.usernames.length; i++) {
if (previousState.usernames[i]!=username) {
newusers.push(previousState.usernames[i]);
}
}
previousState.usernames = newusers;
var newdata = [];
for (var i = 0; i<previousState.data.length; i++) {
if (previousState.data[i].username!=username) {
newusers.push(previousState.data[i]);
} else {
previousState.postIdentifiers[previousState.data[i].postid]=false;
}
}
previousState.data = newdata;
return previousState;
});
},
updatePosts: function(outdatedLimit) {
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
for (var i = 0; i<this.state.usernames.length; i++) {
var thisComponent = this;
var thisUsername = this.state.usernames[i];
Twister.getUser(thisUsername).doLatestPostsUntil(function(post){
if (post!==null) {
if(post.getTimestamp()<thisComponent.state.postrange) {
return false;
} else {
thisComponent.addPost(post);
//console.log("adding post",post.getUsername(),post.getId())
}
} else {
thisComponent.removeUser(thisUsername);
return false;
}
},{outdatedLimit: outdatedLimit});
}
},
componentDidMount: function() {
if (this.props.activeAccount) {
console.log("active account is "+this.props.activeAccount)
var thisComponent = this;
var username=this.props.activeAccount;
thisComponent.addUser(username);
Twister.getUser(username).doFollowings(function(followings){
for(var i in followings){
thisComponent.addUser(followings[i].getUsername());
//console.log(followings[i].getUsername())
}
//thisComponent.updatePosts(thisComponent.props.pollInterval);
});
this.setInterval(this.updatePosts, this.props.pollInterval*1000);
} else {console.log("active account is null")}
},
onscrolledtobottom: function () {
this.setStateSafe(function(previousState, currentProps){
previousState.postrange -= 6*60*60;
return previousState;
},function(){
this.updatePosts(2*this.props.pollInterval);
});
},
onnewpostbyuser: function (event) {
for (var i in this.state.usernames) {
if(this.state.usernames[i]==event.detail.getUsername()) {
this.addPost(event.detail);
}
}
},
render: function() {
return (
React.createElement(Postboard, {data: this.state.data, header:
React.createElement(ListGroupItem, null,
"Home",
React.createElement(NewPostModalButton, {activeAccount: this.props.activeAccount})
)
})
);
}
});

77
build-buffer/home/NewPostModalButton.js

@ -0,0 +1,77 @@
var ReactBootstrap = require('react-bootstrap')
, OverlayMixin = ReactBootstrap.OverlayMixin
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
, Modal = ReactBootstrap.Modal
, Input = ReactBootstrap.Input
var React = require('react');
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
module.exports = NewPostModalButton = React.createClass({displayName: "NewPostModalButton",
mixins: [OverlayMixin],
getInitialState: function () {
return {
isModalOpen: false
};
},
handleToggle: function () {
this.setState({
isModalOpen: !this.state.isModalOpen
});
},
handleNewPost: function (e) {
e.preventDefault();
//console.log(e)
var msg = JSON.parse(JSON.stringify(e.target[0].value));
if (!msg) {
console.log("empty post was passed as new post")
return;
}
Twister.getAccount(this.props.activeAccount).post(msg,function(post){
var event = new CustomEvent('newpostbyuser',{detail: post});
//alert("scrolled to bottom")
window.dispatchEvent(event);
});
e.target[0].value = "";
this.handleToggle();
//React.findDOMNode(this.refs.msg).value = '';
return;
},
render: function() {
return (
React.createElement(Button, {onClick: this.handleToggle, className: "link-button-gray pull-right fullytight_all", bsStyle: "link"},
React.createElement(Glyphicon, {glyph: "pencil"})
)
);
},
renderOverlay: function() {
if (!this.state.isModalOpen) {
return React.createElement("span", null);
}
return (
React.createElement(Modal, {bsStyle: "primary", title: React.createElement(Glyphicon, {glyph: "pencil"}), onRequestHide: this.handleToggle},
React.createElement("div", {className: "modal-body"},
React.createElement("form", {onSubmit: this.handleNewPost},
React.createElement(Input, {type: "textarea", label: "Text Area", placeholder: "textarea"}),
React.createElement(Input, {type: "submit", value: "Submit button", "data-dismiss": "modal"})
)
)
)
);
}
});

84
build-buffer/profile/Followings.js

@ -0,0 +1,84 @@
var React = require('react/addons');
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var MiniProfile = require("../common/MiniProfile.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Home = React.createClass({displayName: "Home",
mixins: [SetIntervalMixin,SafeStateChangeMixin],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
followings: []
};
},
updateFollowings: function(outdatedLimit) {
thisComponent=this;
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
Twister.getUser(this.state.username).doFollowings(function(followings){
thisComponent.setStateSafe(function(state){
var newfollowings = [];
for(var i in followings){
newfollowings.push(followings[i].getUsername());
}
state.followings = newfollowings;
return state;
});
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updateFollowings(this.props.pollInterval*2);
this.setInterval(this.updateFollowings, this.props.pollInterval*1000);
},
render: function() {
var thisComponent = this;
var profiles = this.state.followings.map(function(username, index) {
return (
React.createElement(MiniProfile, {username: username, key: "miniprofile:"+username, pollIntervalProfile: thisComponent.props.pollIntervalProfile})
);
});
return (
React.createElement(ListGroup, {fill: true},
React.createElement(ReactCSSTransitionGroup, {transitionName: "item"},
profiles
)
)
);
}
});

51
build-buffer/profile/Mentions.js

@ -0,0 +1,51 @@
var React = require('react');
var MiniProfile = require("../common/MiniProfile.js");
var Postboard = require("../common/Postboard.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
module.exports = Home = React.createClass({displayName: "Home",
mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
data: [],
postIdentifiers: {}
};
},
updateMentions: function(outdatedLimit) {
thisComponent=this;
if (outdatedLimit===undefined) {outdatedLimit=this.props.pollInterval/2;}
Twister.getUser(this.state.username).doMentions(function(mentions){
for(var i in mentions){
thisComponent.addPost(mentions[i]);
}
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updateMentions(this.props.pollInterval*2);
this.setInterval(this.updateMentions, this.props.pollInterval*1000);
},
render: function() {
return (
React.createElement(Postboard, {data: this.state.data, header: ""})
);
}
});

80
build-buffer/profile/Profile.js

@ -0,0 +1,80 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
, ListGroup = ReactBootstrap.ListGroup
, Nav = ReactBootstrap.Nav
, NavItem = ReactBootstrap.NavItem
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
var React = require('react');
var Router = require('react-router');
var { Route, DefaultRoute, RouteHandler, Link } = Router;
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var ProfileMixin = require('../common/ProfileMixin.js');
module.exports = Post = React.createClass({displayName: "Post",
mixins: [SetIntervalMixin,SafeStateChangeMixin,ProfileMixin],
contextTypes: {
router: React.PropTypes.func
},
getHandlerKey: function () {
var childDepth = 2; // assuming App is top-level route
var { router } = this.context;
//console.log(router.getCurrentParams())
if ( router.getCurrentRoutes()[childDepth] ) {
var key = router.getCurrentRoutes()[childDepth].name;
if (key.indexOf("active")>-1) {key+="/"+this.props.activeAccount;}
var id = JSON.stringify(router.getCurrentParams());
if (id) { key += id; }
console.log(key);
return key;
} else {return "none"}
},
render: function() {
var routeprefix = "#/profile/"+(this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username+"/" : "")
var subroute = this.context.router.getCurrentRoutes()[2].name
console.log(this.context.router.getCurrentRoutes());
return (
React.createElement(ListGroup, {fill: true},
React.createElement(ListGroupItem, null,
React.createElement(Row, {className: "nomargin"},
React.createElement(Col, {xs: 3, md: 3, className: "fullytight"},
React.createElement("img", {className: "img-responsive", src: this.state.avatar})
),
React.createElement(Col, {xs: 8, md: 8},
React.createElement("h4", {className: "nomargin-top"}, this.state.fullname, React.createElement("small", null, "   ", '@'+this.state.username)),
React.createElement("p", {className: "text-center"}, this.state.location),
React.createElement("p", {className: "text-center"}, this.state.bio),
React.createElement("p", {className: "text-center"}, React.createElement("a", {href: this.state.url}, this.state.url))
),
React.createElement(Col, {xs: 1, md: 1, className: "fullytight text-align-right"})
)
),
React.createElement(ListGroupItem, {className: "fullytight_all"},
React.createElement(ButtonGroup, {justified: true},
React.createElement(Button, {href: routeprefix+"timeline", bsStyle: subroute.indexOf("timeline")>-1 ? "primary" : "default"}, React.createElement(Glyphicon, {glyph: "list"})),
React.createElement(Button, {href: routeprefix+"followings", bsStyle: subroute.indexOf("followings")>-1 ? "primary" : "default"}, React.createElement(Glyphicon, {glyph: "eye-open"})),
React.createElement(Button, {href: routeprefix+"mentions", bsStyle: subroute.indexOf("mentions")>-1 ? "primary" : "default"}, React.createElement(Glyphicon, {glyph: "comment"}))
)
),
React.createElement(RouteHandler, {
pollInterval: this.props.pollInterval,
pollIntervalProfile: this.props.pollIntervalProfile,
activeAccount: this.props.activeAccount,
key: this.getHandlerKey()}
)
)
);
}
});

95
build-buffer/profile/Timeline.js

@ -0,0 +1,95 @@
var React = require('react');
var Postboard = require("../common/Postboard.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Timeline = React.createClass({displayName: "Timeline",
mixins:[
StreamMixin,
SetIntervalMixin,
SafeStateChangeMixin,
EventListenerMixin('scrolledtobottom'),
EventListenerMixin('newpostbyuser')
],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
data: [],
postIdentifiers: {},
postCount: 30
};
},
updatePosts: function(outdatedLimit) {
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
var thisComponent = this;
var thisUsername = this.state.username;
var count = 0;
Twister.getUser(this.state.username).doLatestPostsUntil(function(post){
//console.log(count)
if (post!==null) {
if(count++>=thisComponent.state.postCount) {
return false;
} else {
thisComponent.addPost(post);
}
} else {
return false;
}
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updatePosts(2*this.props.pollInterval);
this.setInterval(this.updatePosts, this.props.pollInterval*1000);
console.log(this.props.pollInterval)
},
onscrolledtobottom: function () {
this.setStateSafe(function(previousState, currentProps){
previousState.postrange += 10;
return previousState;
},function(){
this.updatePosts(2*this.props.pollInterval);
});
},
onnewpostbyuser: function (event) {
//alert("got event")
if(this.state.username==event.post.getUsername()) {
this.addPost(event.post);
}
},
render: function() {
return (
React.createElement(Postboard, {data: this.state.data, header: ""})
);
}
});

12
jsx/common/EventListenerMixin.js

@ -0,0 +1,12 @@
module.exports = EventListenerMixin = function (eventtype) {
return {
componentDidMount: function() {
window.addEventListener(eventtype, this["on"+eventtype]);
},
componentWillUnmount: function() {
window.removeEventListener(eventtype, this["on"+eventtype]);
}
}
}

42
jsx/common/MiniProfile.js

@ -0,0 +1,42 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
, ListGroup = ReactBootstrap.ListGroup
, Nav = ReactBootstrap.Nav
, NavItem = ReactBootstrap.NavItem
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
var React = require('react');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var ProfileMixin = require('../common/ProfileMixin.js');
module.exports = MiniProfile = React.createClass({
mixins: [SetIntervalMixin,SafeStateChangeMixin,ProfileMixin],
render: function() {
return (
<ListGroupItem>
<Row className="nomargin">
<Col xs={2} md={2} className="fullytight">
<a href={"#/profile/"+this.props.username}>
<img className="img-responsive" src={this.state.avatar}/>
</a>
</Col>
<Col xs={9} md={9}>
<h5 className="nomargin-top">
{this.state.fullname}<small> &nbsp; {'@'+this.props.username}</small>
</h5>
<p>{this.state.bio}</p>
</Col>
<Col xs={1} md={1} className="fullytight text-align-right"></Col>
</Row>
</ListGroupItem>
);
}
});

107
jsx/common/Post.js

@ -0,0 +1,107 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
var React = require('react');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
module.exports = Post = React.createClass({
mixins: [SetIntervalMixin,SafeStateChangeMixin],
getInitialState: function() {
return {
avatar: "img/genericPerson.png",
fullname: "",
retwistingUser: this.props.post.retwistingUser,
timeAgo: ""
};
},
updateTimeAgo: function() {
var secondsAgo = Date.now()/1000-this.props.post.timestamp;
var newTimeAgo = "";
if (secondsAgo<45) {newTimeAgo="1m"}
else if (secondsAgo<45*60) {newTimeAgo=Math.round(secondsAgo/60)+"m"}
else if (secondsAgo<18*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"}
else if (secondsAgo<26*24*60*60) {newTimeAgo=Math.round(secondsAgo/24/60/60)+"d"}
else if (secondsAgo<9*30.5*24*60*60) {newTimeAgo=Math.round(secondsAgo/30.5/24/60/60)+"mo"}
else {newTimeAgo=Math.round(secondsAgo/365/24/60/60)+"y"}
this.setStateSafe({timeAgo: newTimeAgo});
},
componentDidMount: function () {
var thisComponent = this;
//console.log(this.props.post.username+":post"+this.props.post.id);
Twister.getUser(this.props.post.username).doAvatar(function(avatar){
if (avatar.getUrl()) {
thisComponent.setStateSafe({avatar: avatar.getUrl()});
}
});
Twister.getUser(this.props.post.username).doProfile(function(profile){
thisComponent.setStateSafe({fullname: profile.getField("fullname")});
});
if (this.props.post.isRetwist) {
Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){
thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")});
});
}
this.updateTimeAgo();
this.setInterval(this.updateTimeAgo,60000);
},
render: function() {
var post = this.props.post;
return (
<ListGroupItem>
<Row className="nomargin">
<Col xs={2} md={2} className="fullytight">
<a href={"#/profile/"+this.props.post.username}>
<img className="img-responsive" src={this.state.avatar}/>
</a>
</Col>
<Col xs={9} md={9}>
<strong>{this.state.fullname}</strong>&nbsp;
{post.content}
</Col>
<Col xs={1} md={1} className="fullytight text-align-right">{this.state.timeAgo}</Col>
</Row>
<Row className="nomargin">
<Col xs={6} md={6} className="fullytight">
{post.isRetwist && <small><span className="glyphicon glyphicon-retweet" aria-hidden="true"></span> <em> &nbsp;retwisted by {this.state.retwistingUser}</em></small>
}
</Col>
<Col xs={6} md={6} className="fullytight text-align-right"><small><em>test</em></small></Col>
</Row>
</ListGroupItem>
);
}
});
/*
<div className="post-avatar">
<img src={this.state.avatar}/>
</div>
<div className="post-bulk">
<div className="post-username">
<span className="post-fullname">{this.state.fullname} </span>
@{post.username} - {post.id}
</div>
<div className="post-timestamp">{post.timestamp}</div>
<div className="post-content">{post.content}</div>
</div>
<hr/>
*/

34
jsx/common/Postboard.js

@ -0,0 +1,34 @@
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
var React = require('react/addons');
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var Post = require("../common/Post.js");
module.exports = Postboard = React.createClass({
render: function() {
var posts = this.props.data.map(function(post, index) {
return (
<Post post={post} key={post.postid} />
);
});
return (
<ListGroup fill>
{this.props.header}
<ReactCSSTransitionGroup transitionName="item">
{posts}
</ReactCSSTransitionGroup>
</ListGroup>
);
}
});

71
jsx/common/ProfileMixin.js

@ -0,0 +1,71 @@
module.exports = ProfileMixin = {
getInitialState: function() {
var username = this.props.username;
if (!username) {
username = (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount);
}
var state = {
username: username,
avatar: "img/genericPerson.png",
fullname: "",
bio: "",
location: "",
url: ""
};
var profile = Twister.getUser(username).getProfile();
if (profile.inCache()) {
state.fullname = profile.getField("fullname");
state.bio = profile.getField("bio");
state.location = profile.getField("location");
state.url = profile.getField("url");
}
var avatar = Twister.getUser(username).getAvatar();
if (avatar.inCache()) {
state.avatar = avatar.getUrl();
}
return state;
},
updateProfile: function () {
var thisComponent = this;
Twister.getUser(this.state.username).doAvatar(function(avatar){
if (avatar.getUrl()) {
thisComponent.setStateSafe({avatar: avatar.getUrl()});
}
});
Twister.getUser(this.state.username).doProfile(function(profile){
thisComponent.setStateSafe({
fullname: profile.getField("fullname"),
bio: profile.getField("bio"),
location: profile.getField("location"),
url: profile.getField("url"),
});
});
},
componentDidMount: function () {
this.updateProfile();
this.setInterval(this.updateProfile,this.props.pollIntervalProfile*1000);
}
};

62
jsx/common/SafeStateChangeMixin.js

@ -0,0 +1,62 @@
function isValidLifeCycleForReplaceState(instance) {
// See function validateLifeCycleOnReplaceState(instance) in
// ReactCompositeComponent.js
var result = true;
//result &= ReactCurrentOwner.current == null;
//result &= __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || __REACT_DEVTOOLS_GLOBAL_HOOK__._reactRuntime.CurrentOwner.current == null;
result &= instance.isMounted();
return result;
}
var safeStateChangeMixin = {
/**
* Calls setState with the provided parameters if it is safe to do so.
*
* Safe means it will try to do the same checks as setState does
* without throwing an exception.
* See function validateLifeCycleOnReplaceState(instance) in
* ReactCompositeComponent.js
*
* @param {object} partialState Next partial state to be merged with state.
* @param {?function} callback Called after state is updated.
* @return {boolean} Whether or not setState is called.
* @final
* @protected
*/
setStateSafe: function (partialState, callback) {
if (isValidLifeCycleForReplaceState(this)) {
this.setState(partialState, callback);
return true;
}
return false;
},
/**
* Calls replaceState with the provided parameters if it safe to do so.
*
* Safe means it will try to do the same checks as replaceState does
* without throwing an exception.
* See function validateLifeCycleOnReplaceState(instance) in
* ReactCompositeComponent.js
*
* @param {object} completeState Next state.
* @param {?function} callback Called after state is updated.
* @return {boolean} Whether or not setState is called.
* @final
* @protected
*/
replaceStateSafe: function(completeState, callback) {
if (isValidLifeCycleForReplaceState(this)) {
this.replaceState(completeState, callback);
return true;
}
return false;
}
};
module.exports = safeStateChangeMixin;

11
jsx/common/SetIntervalMixin.js

@ -0,0 +1,11 @@
module.exports = SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.map(clearInterval);
}
};

60
jsx/common/StreamMixin.js

@ -0,0 +1,60 @@
module.exports = StreamMixin = {
addPost: function(post) {
var postid = post.getUsername() + ":post" + post.getId();
if (!this.state.postIdentifiers[postid]) {
this.setStateSafe(function(previousState, currentProps) {
previousState.postIdentifiers[postid] = true;
if (post.isRetwist()){
var postdata = {
username: post.getRetwistedUser(),
retwistingUser: post.getUsername(),
content: post.getRetwistedContent(),
id: post.getRetwistedId(),
timestamp: post.getTimestamp(),
postid: postid,
isRetwist: true
}
} else {
var postdata = {
username: post.getUsername(),
content: post.getContent(),
id: post.getId(),
timestamp: post.getTimestamp(),
postid: postid,
isRetwist: false
}
}
previousState.data.push(postdata)
var compare = function (a,b) {
if (a.timestamp < b.timestamp)
return 1;
if (a.timestamp > b.timestamp)
return -1;
return 0;
}
previousState.data.sort(compare);
return {data: previousState.data, postIdentifiers: previousState.postIdentifiers };
});
} else {
}
}
}

183
jsx/home/Home.js

@ -0,0 +1,183 @@
var React = require('react');
var Postboard = require("../common/Postboard.js");
var NewPostModalButton = require("../home/NewPostModalButton.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Home = React.createClass({
mixins: [
StreamMixin,
SetIntervalMixin,
SafeStateChangeMixin,
EventListenerMixin('scrolledtobottom'),
EventListenerMixin('newpostbyuser')
],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
data: [],
postIdentifiers: {},
usernames: [],
postrange: ( Date.now()/1000 - 12*60*60 ),
min_posts: 30
};
},
addUser: function(username) {
var thisComponent = this;
this.setStateSafe(function(previousState, currentProps){
previousState.usernames.push(username);
return previousState;
},function(){
Twister.getUser(username).doLatestPostsUntil(function(post){
if (post!==null) {
if(post.getTimestamp()<thisComponent.state.postrange) {
return false;
} else {
thisComponent.addPost(post);
//console.log("adding post",post.getUsername(),post.getId())
}
} else {
thisComponent.removeUser(thisUsername);
return false;
}
},{outdatedLimit: 2*thisComponent.props.pollInterval});
});
},
removeUser: function(username) {
this.setStateSafe(function(previousState, currentProps){
var newusers = [];
for (var i = 0; i<previousState.usernames.length; i++) {
if (previousState.usernames[i]!=username) {
newusers.push(previousState.usernames[i]);
}
}
previousState.usernames = newusers;
var newdata = [];
for (var i = 0; i<previousState.data.length; i++) {
if (previousState.data[i].username!=username) {
newusers.push(previousState.data[i]);
} else {
previousState.postIdentifiers[previousState.data[i].postid]=false;
}
}
previousState.data = newdata;
return previousState;
});
},
updatePosts: function(outdatedLimit) {
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
for (var i = 0; i<this.state.usernames.length; i++) {
var thisComponent = this;
var thisUsername = this.state.usernames[i];
Twister.getUser(thisUsername).doLatestPostsUntil(function(post){
if (post!==null) {
if(post.getTimestamp()<thisComponent.state.postrange) {
return false;
} else {
thisComponent.addPost(post);
//console.log("adding post",post.getUsername(),post.getId())
}
} else {
thisComponent.removeUser(thisUsername);
return false;
}
},{outdatedLimit: outdatedLimit});
}
},
componentDidMount: function() {
if (this.props.activeAccount) {
console.log("active account is "+this.props.activeAccount)
var thisComponent = this;
var username=this.props.activeAccount;
thisComponent.addUser(username);
Twister.getUser(username).doFollowings(function(followings){
for(var i in followings){
thisComponent.addUser(followings[i].getUsername());
//console.log(followings[i].getUsername())
}
//thisComponent.updatePosts(thisComponent.props.pollInterval);
});
this.setInterval(this.updatePosts, this.props.pollInterval*1000);
} else {console.log("active account is null")}
},
onscrolledtobottom: function () {
this.setStateSafe(function(previousState, currentProps){
previousState.postrange -= 6*60*60;
return previousState;
},function(){
this.updatePosts(2*this.props.pollInterval);
});
},
onnewpostbyuser: function (event) {
for (var i in this.state.usernames) {
if(this.state.usernames[i]==event.detail.getUsername()) {
this.addPost(event.detail);
}
}
},
render: function() {
return (
<Postboard data={this.state.data} header={
<ListGroupItem>
Home
<NewPostModalButton activeAccount={this.props.activeAccount}/>
</ListGroupItem>
}/>
);
}
});

77
jsx/home/NewPostModalButton.js

@ -0,0 +1,77 @@
var ReactBootstrap = require('react-bootstrap')
, OverlayMixin = ReactBootstrap.OverlayMixin
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
, Modal = ReactBootstrap.Modal
, Input = ReactBootstrap.Input
var React = require('react');
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
module.exports = NewPostModalButton = React.createClass({
mixins: [OverlayMixin],
getInitialState: function () {
return {
isModalOpen: false
};
},
handleToggle: function () {
this.setState({
isModalOpen: !this.state.isModalOpen
});
},
handleNewPost: function (e) {
e.preventDefault();
//console.log(e)
var msg = JSON.parse(JSON.stringify(e.target[0].value));
if (!msg) {
console.log("empty post was passed as new post")
return;
}
Twister.getAccount(this.props.activeAccount).post(msg,function(post){
var event = new CustomEvent('newpostbyuser',{detail: post});
//alert("scrolled to bottom")
window.dispatchEvent(event);
});
e.target[0].value = "";
this.handleToggle();
//React.findDOMNode(this.refs.msg).value = '';
return;
},
render: function() {
return (
<Button onClick={this.handleToggle} className="link-button-gray pull-right fullytight_all" bsStyle="link">
<Glyphicon glyph='pencil' />
</Button>
);
},
renderOverlay: function() {
if (!this.state.isModalOpen) {
return <span/>;
}
return (
<Modal bsStyle='primary' title={<Glyphicon glyph='pencil'/>} onRequestHide={this.handleToggle}>
<div className='modal-body'>
<form onSubmit={this.handleNewPost}>
<Input type='textarea' label='Text Area' placeholder='textarea'/>
<Input type='submit' value='Submit button' data-dismiss="modal" />
</form>
</div>
</Modal>
);
}
});

84
jsx/profile/Followings.js

@ -0,0 +1,84 @@
var React = require('react/addons');
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var MiniProfile = require("../common/MiniProfile.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Home = React.createClass({
mixins: [SetIntervalMixin,SafeStateChangeMixin],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
followings: []
};
},
updateFollowings: function(outdatedLimit) {
thisComponent=this;
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
Twister.getUser(this.state.username).doFollowings(function(followings){
thisComponent.setStateSafe(function(state){
var newfollowings = [];
for(var i in followings){
newfollowings.push(followings[i].getUsername());
}
state.followings = newfollowings;
return state;
});
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updateFollowings(this.props.pollInterval*2);
this.setInterval(this.updateFollowings, this.props.pollInterval*1000);
},
render: function() {
var thisComponent = this;
var profiles = this.state.followings.map(function(username, index) {
return (
<MiniProfile username={username} key={"miniprofile:"+username} pollIntervalProfile={thisComponent.props.pollIntervalProfile}/>
);
});
return (
<ListGroup fill>
<ReactCSSTransitionGroup transitionName="item">
{profiles}
</ReactCSSTransitionGroup>
</ListGroup>
);
}
});

51
jsx/profile/Mentions.js

@ -0,0 +1,51 @@
var React = require('react');
var MiniProfile = require("../common/MiniProfile.js");
var Postboard = require("../common/Postboard.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
module.exports = Home = React.createClass({
mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
data: [],
postIdentifiers: {}
};
},
updateMentions: function(outdatedLimit) {
thisComponent=this;
if (outdatedLimit===undefined) {outdatedLimit=this.props.pollInterval/2;}
Twister.getUser(this.state.username).doMentions(function(mentions){
for(var i in mentions){
thisComponent.addPost(mentions[i]);
}
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updateMentions(this.props.pollInterval*2);
this.setInterval(this.updateMentions, this.props.pollInterval*1000);
},
render: function() {
return (
<Postboard data={this.state.data} header=""/>
);
}
});

80
jsx/profile/Profile.js

@ -0,0 +1,80 @@
var ReactBootstrap = require('react-bootstrap')
, Grid = ReactBootstrap.Grid
, Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row
, ListGroupItem = ReactBootstrap.ListGroupItem
, ListGroup = ReactBootstrap.ListGroup
, Nav = ReactBootstrap.Nav
, NavItem = ReactBootstrap.NavItem
, Button = ReactBootstrap.Button
, ButtonGroup = ReactBootstrap.ButtonGroup
, Glyphicon = ReactBootstrap.Glyphicon
var React = require('react');
var Router = require('react-router');
var { Route, DefaultRoute, RouteHandler, Link } = Router;
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var ProfileMixin = require('../common/ProfileMixin.js');
module.exports = Post = React.createClass({
mixins: [SetIntervalMixin,SafeStateChangeMixin,ProfileMixin],
contextTypes: {
router: React.PropTypes.func
},
getHandlerKey: function () {
var childDepth = 2; // assuming App is top-level route
var { router } = this.context;
//console.log(router.getCurrentParams())
if ( router.getCurrentRoutes()[childDepth] ) {
var key = router.getCurrentRoutes()[childDepth].name;
if (key.indexOf("active")>-1) {key+="/"+this.props.activeAccount;}
var id = JSON.stringify(router.getCurrentParams());
if (id) { key += id; }
console.log(key);
return key;
} else {return "none"}
},
render: function() {
var routeprefix = "#/profile/"+(this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username+"/" : "")
var subroute = this.context.router.getCurrentRoutes()[2].name
console.log(this.context.router.getCurrentRoutes());
return (
<ListGroup fill>
<ListGroupItem>
<Row className="nomargin">
<Col xs={3} md={3} className="fullytight">
<img className="img-responsive" src={this.state.avatar}/>
</Col>
<Col xs={8} md={8}>
<h4 className="nomargin-top">{this.state.fullname}<small> &nbsp; {'@'+this.state.username}</small></h4>
<p className="text-center">{this.state.location}</p>
<p className="text-center">{this.state.bio}</p>
<p className="text-center"><a href={this.state.url}>{this.state.url}</a></p>
</Col>
<Col xs={1} md={1} className="fullytight text-align-right"></Col>
</Row>
</ListGroupItem>
<ListGroupItem className="fullytight_all">
<ButtonGroup justified>
<Button href={routeprefix+"timeline"} bsStyle={subroute.indexOf("timeline")>-1 ? "primary" : "default"}><Glyphicon glyph="list"/></Button>
<Button href={routeprefix+"followings"} bsStyle={subroute.indexOf("followings")>-1 ? "primary" : "default"}><Glyphicon glyph="eye-open"/></Button>
<Button href={routeprefix+"mentions"} bsStyle={subroute.indexOf("mentions")>-1 ? "primary" : "default"}><Glyphicon glyph="comment"/></Button>
</ButtonGroup>
</ListGroupItem>
<RouteHandler
pollInterval={this.props.pollInterval}
pollIntervalProfile={this.props.pollIntervalProfile}
activeAccount={this.props.activeAccount}
key={this.getHandlerKey()}
/>
</ListGroup>
);
}
});

95
jsx/profile/Timeline.js

@ -0,0 +1,95 @@
var React = require('react');
var Postboard = require("../common/Postboard.js");
var SetIntervalMixin = require("../common/SetIntervalMixin.js");
var StreamMixin = require("../common/StreamMixin.js");
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
var EventListenerMixin = require('../common/EventListenerMixin.js');
var ReactBootstrap = require('react-bootstrap')
, NavItem = ReactBootstrap.NavItem
, Nav = ReactBootstrap.Nav
, ListGroup = ReactBootstrap.ListGroup
, ListGroupItem = ReactBootstrap.ListGroupItem
, Panel = ReactBootstrap.Panel
, Glyphicon = ReactBootstrap.Glyphicon
, Button = ReactBootstrap.Button
module.exports = Timeline = React.createClass({
mixins:[
StreamMixin,
SetIntervalMixin,
SafeStateChangeMixin,
EventListenerMixin('scrolledtobottom'),
EventListenerMixin('newpostbyuser')
],
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
username: (this.context.router.getCurrentParams().username ? this.context.router.getCurrentParams().username : this.props.activeAccount),
data: [],
postIdentifiers: {},
postCount: 30
};
},
updatePosts: function(outdatedLimit) {
if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;}
var thisComponent = this;
var thisUsername = this.state.username;
var count = 0;
Twister.getUser(this.state.username).doLatestPostsUntil(function(post){
//console.log(count)
if (post!==null) {
if(count++>=thisComponent.state.postCount) {
return false;
} else {
thisComponent.addPost(post);
}
} else {
return false;
}
},{outdatedLimit: outdatedLimit});
},
componentDidMount: function() {
this.updatePosts(2*this.props.pollInterval);
this.setInterval(this.updatePosts, this.props.pollInterval*1000);
console.log(this.props.pollInterval)
},
onscrolledtobottom: function () {
this.setStateSafe(function(previousState, currentProps){
previousState.postrange += 10;
return previousState;
},function(){
this.updatePosts(2*this.props.pollInterval);
});
},
onnewpostbyuser: function (event) {
//alert("got event")
if(this.state.username==event.post.getUsername()) {
this.addPost(event.post);
}
},
render: function() {
return (
<Postboard data={this.state.data} header=""/>
);
}
});
Loading…
Cancel
Save