Julian Steinwachs
10 years ago
76 changed files with 5301 additions and 0 deletions
@ -0,0 +1,188 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
thisComponent.removeUser(this._name); |
||||||
|
console.log("removed user "+this._name+" because of empty status resource") |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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.state.appSettings.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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
//console.log("removed user "+this._name+" because of empty status resource")
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,100 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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:[ |
||||||
|
AppSettingsMixin, |
||||||
|
StreamMixin, |
||||||
|
SetIntervalMixin, |
||||||
|
SafeStateChangeMixin, |
||||||
|
EventListenerMixin('newpostbyuser') |
||||||
|
], |
||||||
|
contextTypes: { |
||||||
|
router: React.PropTypes.func |
||||||
|
}, |
||||||
|
getInitialState: function() { |
||||||
|
return { |
||||||
|
username: this.context.router.getCurrentParams().username, |
||||||
|
postid: parseInt(this.context.router.getCurrentParams().postid), |
||||||
|
data: [], |
||||||
|
postIdentifiers: {}, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
updatePosts: function(outdatedLimit) { |
||||||
|
|
||||||
|
//console.log(this.state.username+":post"+this.state.postid)
|
||||||
|
|
||||||
|
if (!outdatedLimit) {outdatedLimit=this.state.appSettings.pollInterval/2;} |
||||||
|
|
||||||
|
var thisComponent = this; |
||||||
|
var thisUsername = this.state.username; |
||||||
|
|
||||||
|
var goUpConversation = function (post) { |
||||||
|
|
||||||
|
thisComponent.addPost(post); |
||||||
|
|
||||||
|
thisComponent.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
if (post.isReply()) { |
||||||
|
|
||||||
|
post.doPostRepliedTo(goUpConversation); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
post.doReplies(doRepliesRecursive); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var doRepliesRecursive = function (replies) { |
||||||
|
|
||||||
|
for (var i in replies) { |
||||||
|
replies[i].doReplies(doRepliesRecursive); |
||||||
|
thisComponent.addPost(replies[i]); |
||||||
|
console.log(replies[i].getContent()) |
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
Twister.getUser(this.state.username).doPost(this.state.postid,goUpConversation,{outdatedLimit: outdatedLimit, logfunc: function(log){console.log(log)}}); |
||||||
|
|
||||||
|
}, |
||||||
|
componentDidMount: function() { |
||||||
|
|
||||||
|
this.updatePosts(2*this.state.appSettings.pollInterval); |
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.pollInterval*1000); |
||||||
|
|
||||||
|
}, |
||||||
|
onnewpostbyuser: function (event) { |
||||||
|
|
||||||
|
//alert("got event")
|
||||||
|
|
||||||
|
this.updatePosts(-1); |
||||||
|
|
||||||
|
}, |
||||||
|
render: function() { |
||||||
|
return ( |
||||||
|
React.createElement(Postboard, {header: |
||||||
|
React.createElement(ListGroupItem, null, |
||||||
|
"Conversation" |
||||||
|
), |
||||||
|
data: this.state.data, loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,41 @@ |
|||||||
|
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; |
||||||
|
|
||||||
|
var postdata = { |
||||||
|
username: post.getUsername(), |
||||||
|
id: post.getId(), |
||||||
|
timestamp: post.getTimestamp() |
||||||
|
} |
||||||
|
|
||||||
|
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 { |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,255 @@ |
|||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
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'); |
||||||
|
var Conversation = require('./other/Conversation.js'); |
||||||
|
var Settings = require('./other/Settings.js'); |
||||||
|
var AppSettingsMixin = require('./common/AppSettingsMixin.js'); |
||||||
|
|
||||||
|
App = React.createClass({displayName: "App", |
||||||
|
|
||||||
|
mixins: [AppSettingsMixin,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 () { |
||||||
|
|
||||||
|
var state={}; |
||||||
|
|
||||||
|
state.activeAccount = localStorage.getItem("twister-react-activeAccount") |
||||||
|
|
||||||
|
state.accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (!state.activeAccount) { state.activeAccount=state.accounts[0]; } |
||||||
|
|
||||||
|
//console.log(state);
|
||||||
|
|
||||||
|
return state; |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
componentDidMount: function () { |
||||||
|
|
||||||
|
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, { |
||||||
|
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(Route, {name: "conversation", path: "/conversation/:username/:postid", handler: Conversation}), |
||||||
|
React.createElement(Route, {name: "settings", path: "/settings", handler: Settings}), |
||||||
|
React.createElement(DefaultRoute, {name: "home", handler: Home}) |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
|
||||||
|
initializeApp = function () { |
||||||
|
|
||||||
|
Router.run(routes, function (Handler) { |
||||||
|
React.render(React.createElement(Handler, null), document.getElementById('content')); |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.deserializeCache(JSON.parse(localStorage.getItem("twister-cache"))); |
||||||
|
|
||||||
|
var accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (accounts.length==0) { |
||||||
|
|
||||||
|
if (!localStorage.getItem("twister-react-settings")) { |
||||||
|
|
||||||
|
var appSettings = { |
||||||
|
|
||||||
|
pollInterval:60, |
||||||
|
pollIntervalProfile: 3600, |
||||||
|
ignoredUsers: "nobody", |
||||||
|
host: "http://user:pwd@localhost:28332" |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
var appSettings = JSON.parse(localStorage.getItem("twister-react-settings")); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.setup({ |
||||||
|
host: appSettings.host, |
||||||
|
logfunc: function(log){console.log(log)}, |
||||||
|
outdatedLimit: appSettings.pollInterval, |
||||||
|
querySettingsByType: { |
||||||
|
|
||||||
|
outdatedLimit: { |
||||||
|
pubkey: appSettings.pollIntervalProfile, |
||||||
|
profile: appSettings.pollIntervalProfile, |
||||||
|
avatar: appSettings.pollIntervalProfile, |
||||||
|
torrent: appSettings.pollIntervalProfile, |
||||||
|
followings: appSettings.pollIntervalProfile |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Twister.loadServerAccounts(function(){ |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
} |
||||||
|
|
||||||
|
////// 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); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,188 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
console.log("removed user ",this) |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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.state.appSettings.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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
//console.log("removed user "+this._name+" because of empty status resource")
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,41 @@ |
|||||||
|
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; |
||||||
|
|
||||||
|
var postdata = { |
||||||
|
username: post.getUsername(), |
||||||
|
id: post.getRetwistedId(), |
||||||
|
timestamp: post.getTimestamp() |
||||||
|
} |
||||||
|
|
||||||
|
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 { |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
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.getRetwistedUsername(), |
||||||
|
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 |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (post.isReply()) { |
||||||
|
|
||||||
|
postdata.isReply = true; |
||||||
|
postdata.replyUsername = post.getReplyUsername(); |
||||||
|
postdata.replyId = post.getReplyId(); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
postdata.isReply = 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 { |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,188 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
//console.log("removed user "+this._name+" because of empty status resource")
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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.state.appSettings.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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
//console.log("removed user "+this._name+" because of empty status resource")
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,100 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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:[ |
||||||
|
AppSettingsMixin, |
||||||
|
StreamMixin, |
||||||
|
SetIntervalMixin, |
||||||
|
SafeStateChangeMixin, |
||||||
|
EventListenerMixin('newpostbyuser') |
||||||
|
], |
||||||
|
contextTypes: { |
||||||
|
router: React.PropTypes.func |
||||||
|
}, |
||||||
|
getInitialState: function() { |
||||||
|
return { |
||||||
|
username: this.context.router.getCurrentParams().username, |
||||||
|
postid: parseInt(this.context.router.getCurrentParams().postid), |
||||||
|
data: [], |
||||||
|
postIdentifiers: {}, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
updatePosts: function(outdatedLimit) { |
||||||
|
|
||||||
|
//console.log(this.state.username+":post"+this.state.postid)
|
||||||
|
|
||||||
|
if (!outdatedLimit) {outdatedLimit=this.state.appSettings.pollInterval/2;} |
||||||
|
|
||||||
|
var thisComponent = this; |
||||||
|
var thisUsername = this.state.username; |
||||||
|
|
||||||
|
var goUpConversation = function (post) { |
||||||
|
|
||||||
|
thisComponent.addPost(post); |
||||||
|
|
||||||
|
thisComponent.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
if (post.isReply()) { |
||||||
|
|
||||||
|
post.doPostRepliedTo(goUpConversation); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
post.doReplies(doRepliesRecursive); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var doRepliesRecursive = function (replies) { |
||||||
|
|
||||||
|
for (var i in replies) { |
||||||
|
replies[i].doReplies(doRepliesRecursive); |
||||||
|
thisComponent.addPost(replies[i]); |
||||||
|
//console.log(replies[i].getContent())
|
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
Twister.getUser(this.state.username).doPost(this.state.postid,goUpConversation,{outdatedLimit: outdatedLimit, logfunc: function(log){console.log(log)}}); |
||||||
|
|
||||||
|
}, |
||||||
|
componentDidMount: function() { |
||||||
|
|
||||||
|
this.updatePosts(2*this.state.appSettings.pollInterval); |
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.pollInterval*1000); |
||||||
|
|
||||||
|
}, |
||||||
|
onnewpostbyuser: function (event) { |
||||||
|
|
||||||
|
//alert("got event")
|
||||||
|
|
||||||
|
this.updatePosts(-1); |
||||||
|
|
||||||
|
}, |
||||||
|
render: function() { |
||||||
|
return ( |
||||||
|
React.createElement(Postboard, {header: |
||||||
|
React.createElement(ListGroupItem, null, |
||||||
|
"Conversation" |
||||||
|
), |
||||||
|
data: this.state.data, loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,75 @@ |
|||||||
|
var React = require('react'); |
||||||
|
var SetIntervalMixin = require("../common/SetIntervalMixin.js"); |
||||||
|
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js'); |
||||||
|
var EventListenerMixin = require('../common/EventListenerMixin.js'); |
||||||
|
var AppSettingsMixin = require('../common/AppSettingsMixin.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 |
||||||
|
, Input = ReactBootstrap.Input |
||||||
|
|
||||||
|
module.exports = Home = React.createClass({displayName: "Home", |
||||||
|
|
||||||
|
mixins: [ |
||||||
|
SetIntervalMixin, |
||||||
|
SafeStateChangeMixin, |
||||||
|
AppSettingsMixin |
||||||
|
], |
||||||
|
contextTypes: { |
||||||
|
router: React.PropTypes.func |
||||||
|
}, |
||||||
|
handeSettingsUpdate: function (e) { |
||||||
|
e.preventDefault(); |
||||||
|
|
||||||
|
var newsettings = {} |
||||||
|
|
||||||
|
newsettings.pollInterval = $(this.getDOMNode()).find(".settings-pollInterval").val(); |
||||||
|
newsettings.pollIntervalProfile = $(this.getDOMNode()).find(".settings-pollIntervalProfile").val(); |
||||||
|
newsettings.ignoredUsers = $(this.getDOMNode()).find(".settings-ignoredUsers").val(); |
||||||
|
newsettings.host = $(this.getDOMNode()).find(".settings-host").val(); |
||||||
|
newsettings.logging = $(this.getDOMNode()).find(".settings-logging").val(); |
||||||
|
|
||||||
|
console.log(newsettings) |
||||||
|
|
||||||
|
localStorage.setItem("twister-react-settings",JSON.stringify(newsettings)); |
||||||
|
|
||||||
|
var event = new CustomEvent('appsettingschanged',{detail: newsettings}); |
||||||
|
window.dispatchEvent(event); |
||||||
|
|
||||||
|
return; |
||||||
|
}, |
||||||
|
render: function() { |
||||||
|
return ( |
||||||
|
React.createElement(ListGroup, null, |
||||||
|
React.createElement(ListGroupItem, null, "Settings"), |
||||||
|
React.createElement(ListGroupItem, null, |
||||||
|
React.createElement("form", {onSubmit: this.handeSettingsUpdate, className: "form-horizontal"}, |
||||||
|
React.createElement(Input, {type: "text", label: "pollInterval", |
||||||
|
defaultValue: this.state.appSettings.pollInterval, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-pollInterval"}), |
||||||
|
React.createElement(Input, {type: "text", label: "pollIntervalProfile", |
||||||
|
defaultValue: this.state.appSettings.pollIntervalProfile, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-pollIntervalProfile"}), |
||||||
|
React.createElement(Input, {type: "text", label: "ignoredUsers", |
||||||
|
defaultValue: this.state.appSettings.ignoredUsers, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-ignoredUsers"}), |
||||||
|
React.createElement(Input, {type: "text", label: "host", |
||||||
|
defaultValue: this.state.appSettings.host, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-host"}), |
||||||
|
React.createElement(Input, {type: "checkbox", label: "logging", |
||||||
|
defaultValue: this.state.appSettings.logging, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-logging"}), |
||||||
|
React.createElement(Input, {type: "submit", value: "Save", wrapperClassName: "col-xs-offset-10 col-xs-2"}) |
||||||
|
) |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,41 @@ |
|||||||
|
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; |
||||||
|
|
||||||
|
var postdata = { |
||||||
|
username: post.getRetwistedUsername(), |
||||||
|
id: post.getRetwistedId(), |
||||||
|
timestamp: post.getTimestamp() |
||||||
|
} |
||||||
|
|
||||||
|
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 { |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,257 @@ |
|||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
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'); |
||||||
|
var Conversation = require('./other/Conversation.js'); |
||||||
|
var Settings = require('./other/Settings.js'); |
||||||
|
var AppSettingsMixin = require('./common/AppSettingsMixin.js'); |
||||||
|
|
||||||
|
App = React.createClass({displayName: "App", |
||||||
|
|
||||||
|
mixins: [AppSettingsMixin,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 () { |
||||||
|
|
||||||
|
var state={}; |
||||||
|
|
||||||
|
state.activeAccount = localStorage.getItem("twister-react-activeAccount") |
||||||
|
|
||||||
|
state.accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (!state.activeAccount) { state.activeAccount=state.accounts[0]; } |
||||||
|
|
||||||
|
//console.log(state);
|
||||||
|
|
||||||
|
return state; |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
componentDidMount: function () { |
||||||
|
|
||||||
|
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, { |
||||||
|
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(Route, {name: "conversation", path: "/conversation/:username/:postid", handler: Conversation}), |
||||||
|
React.createElement(Route, {name: "settings", path: "/settings", handler: Settings}), |
||||||
|
React.createElement(DefaultRoute, {name: "home", handler: Home}) |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
|
||||||
|
initializeApp = function () { |
||||||
|
|
||||||
|
Router.run(routes, function (Handler) { |
||||||
|
React.render(React.createElement(Handler, null), document.getElementById('content')); |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.deserializeCache(JSON.parse(localStorage.getItem("twister-cache"))); |
||||||
|
|
||||||
|
Twister.setup({logfunc: function(log){console.log(log)}}) |
||||||
|
|
||||||
|
var accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (accounts.length==0) { |
||||||
|
|
||||||
|
if (!localStorage.getItem("twister-react-settings")) { |
||||||
|
|
||||||
|
var appSettings = { |
||||||
|
|
||||||
|
pollInterval:60, |
||||||
|
pollIntervalProfile: 3600, |
||||||
|
ignoredUsers: "nobody", |
||||||
|
host: "http://user:pwd@localhost:28332" |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
var appSettings = JSON.parse(localStorage.getItem("twister-react-settings")); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.setup({ |
||||||
|
host: appSettings.host, |
||||||
|
//logfunc: function(log){console.log(log)},
|
||||||
|
outdatedLimit: appSettings.pollInterval, |
||||||
|
querySettingsByType: { |
||||||
|
|
||||||
|
outdatedLimit: { |
||||||
|
pubkey: appSettings.pollIntervalProfile, |
||||||
|
profile: appSettings.pollIntervalProfile, |
||||||
|
avatar: appSettings.pollIntervalProfile, |
||||||
|
torrent: appSettings.pollIntervalProfile, |
||||||
|
followings: appSettings.pollIntervalProfile |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Twister.loadServerAccounts(function(){ |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
} |
||||||
|
|
||||||
|
////// 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); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,72 @@ |
|||||||
|
var React = require('react'); |
||||||
|
var SetIntervalMixin = require("../common/SetIntervalMixin.js"); |
||||||
|
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js'); |
||||||
|
var EventListenerMixin = require('../common/EventListenerMixin.js'); |
||||||
|
var AppSettingsMixin = require('../common/AppSettingsMixin.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 |
||||||
|
, Input = ReactBootstrap.Input |
||||||
|
|
||||||
|
module.exports = Home = React.createClass({displayName: "Home", |
||||||
|
|
||||||
|
mixins: [ |
||||||
|
SetIntervalMixin, |
||||||
|
SafeStateChangeMixin, |
||||||
|
AppSettingsMixin |
||||||
|
], |
||||||
|
contextTypes: { |
||||||
|
router: React.PropTypes.func |
||||||
|
}, |
||||||
|
handeSettingsUpdate: function (e) { |
||||||
|
e.preventDefault(); |
||||||
|
|
||||||
|
var newsettings = {} |
||||||
|
|
||||||
|
newsettings.pollInterval = $(this.getDOMNode()).find(".settings-pollInterval").val(); |
||||||
|
newsettings.pollIntervalProfile = $(this.getDOMNode()).find(".settings-pollIntervalProfile").val(); |
||||||
|
newsettings.ignoredUsers = $(this.getDOMNode()).find(".settings-ignoredUsers").val(); |
||||||
|
newsettings.host = $(this.getDOMNode()).find(".settings-host").val(); |
||||||
|
newsettings.logging = $(this.getDOMNode()).find(".settings-logging").attr('checked'); |
||||||
|
|
||||||
|
console.log(newsettings) |
||||||
|
|
||||||
|
localStorage.setItem("twister-react-settings",JSON.stringify(newsettings)); |
||||||
|
|
||||||
|
var event = new CustomEvent('appsettingschanged',{detail: newsettings}); |
||||||
|
window.dispatchEvent(event); |
||||||
|
|
||||||
|
return; |
||||||
|
}, |
||||||
|
render: function() { |
||||||
|
return ( |
||||||
|
React.createElement(ListGroup, null, |
||||||
|
React.createElement(ListGroupItem, null, "Settings"), |
||||||
|
React.createElement(ListGroupItem, null, |
||||||
|
React.createElement("form", {onSubmit: this.handeSettingsUpdate, className: "form-horizontal"}, |
||||||
|
React.createElement(Input, {type: "text", label: "pollInterval", |
||||||
|
defaultValue: this.state.appSettings.pollInterval, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-pollInterval"}), |
||||||
|
React.createElement(Input, {type: "text", label: "pollIntervalProfile", |
||||||
|
defaultValue: this.state.appSettings.pollIntervalProfile, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-pollIntervalProfile"}), |
||||||
|
React.createElement(Input, {type: "text", label: "ignoredUsers", |
||||||
|
defaultValue: this.state.appSettings.ignoredUsers, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-ignoredUsers"}), |
||||||
|
React.createElement(Input, {type: "text", label: "host", |
||||||
|
defaultValue: this.state.appSettings.host, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-host"}), |
||||||
|
React.createElement(Input, {type: "submit", value: "Save", wrapperClassName: "col-xs-offset-10 col-xs-2"}) |
||||||
|
) |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,256 @@ |
|||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
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'); |
||||||
|
var Conversation = require('./other/Conversation.js'); |
||||||
|
var Settings = require('./other/Settings.js'); |
||||||
|
var AppSettingsMixin = require('./common/AppSettingsMixin.js'); |
||||||
|
|
||||||
|
App = React.createClass({displayName: "App", |
||||||
|
|
||||||
|
mixins: [AppSettingsMixin,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 () { |
||||||
|
|
||||||
|
var state={}; |
||||||
|
|
||||||
|
state.activeAccount = localStorage.getItem("twister-react-activeAccount") |
||||||
|
|
||||||
|
state.accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (!state.activeAccount) { state.activeAccount=state.accounts[0]; } |
||||||
|
|
||||||
|
//console.log(state);
|
||||||
|
|
||||||
|
return state; |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
componentDidMount: function () { |
||||||
|
|
||||||
|
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, { |
||||||
|
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(Route, {name: "conversation", path: "/conversation/:username/:postid", handler: Conversation}), |
||||||
|
React.createElement(Route, {name: "settings", path: "/settings", handler: Settings}), |
||||||
|
React.createElement(DefaultRoute, {name: "home", handler: Home}) |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
|
||||||
|
initializeApp = function () { |
||||||
|
|
||||||
|
Router.run(routes, function (Handler) { |
||||||
|
React.render(React.createElement(Handler, null), document.getElementById('content')); |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.deserializeCache(JSON.parse(localStorage.getItem("twister-cache"))); |
||||||
|
|
||||||
|
var accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (accounts.length==0) { |
||||||
|
|
||||||
|
if (!localStorage.getItem("twister-react-settings")) { |
||||||
|
|
||||||
|
var appSettings = { |
||||||
|
|
||||||
|
pollInterval:60, |
||||||
|
pollIntervalProfile: 3600, |
||||||
|
ignoredUsers: "nobody", |
||||||
|
host: "http://user:pwd@localhost:28332", |
||||||
|
logging: false |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
var appSettings = JSON.parse(localStorage.getItem("twister-react-settings")); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.setup({ |
||||||
|
host: appSettings.host, |
||||||
|
logfunc: function(log){console.log(log)}, |
||||||
|
outdatedLimit: appSettings.pollInterval, |
||||||
|
querySettingsByType: { |
||||||
|
|
||||||
|
outdatedLimit: { |
||||||
|
pubkey: appSettings.pollIntervalProfile, |
||||||
|
profile: appSettings.pollIntervalProfile, |
||||||
|
avatar: appSettings.pollIntervalProfile, |
||||||
|
torrent: appSettings.pollIntervalProfile, |
||||||
|
followings: appSettings.pollIntervalProfile |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Twister.loadServerAccounts(function(){ |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
} |
||||||
|
|
||||||
|
////// 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); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,12 @@ |
|||||||
|
module.exports = SetIntervalMixin = { |
||||||
|
componentWillMount: function() { |
||||||
|
this.intervals = []; |
||||||
|
}, |
||||||
|
setInterval: function() { |
||||||
|
console.log(arguments) |
||||||
|
this.intervals.push(setInterval.apply(null, arguments)); |
||||||
|
}, |
||||||
|
componentWillUnmount: function() { |
||||||
|
this.intervals.map(clearInterval); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,15 @@ |
|||||||
|
module.exports = SetIntervalMixin = { |
||||||
|
componentWillMount: function() { |
||||||
|
this.intervals = []; |
||||||
|
}, |
||||||
|
setInterval: function() { |
||||||
|
if (arguments[1]) { |
||||||
|
this.intervals.push(setInterval.apply(null, arguments)); |
||||||
|
} else { |
||||||
|
console.log("setInterval requested with malformed interval argument"); |
||||||
|
} |
||||||
|
}, |
||||||
|
componentWillUnmount: function() { |
||||||
|
this.intervals.map(clearInterval); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,188 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
console.log("removed user "+this) |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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.state.appSettings.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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
//console.log("removed user "+this._name+" because of empty status resource")
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,75 @@ |
|||||||
|
var React = require('react'); |
||||||
|
var SetIntervalMixin = require("../common/SetIntervalMixin.js"); |
||||||
|
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js'); |
||||||
|
var EventListenerMixin = require('../common/EventListenerMixin.js'); |
||||||
|
var AppSettingsMixin = require('../common/AppSettingsMixin.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 |
||||||
|
, Input = ReactBootstrap.Input |
||||||
|
|
||||||
|
module.exports = Home = React.createClass({displayName: "Home", |
||||||
|
|
||||||
|
mixins: [ |
||||||
|
SetIntervalMixin, |
||||||
|
SafeStateChangeMixin, |
||||||
|
AppSettingsMixin |
||||||
|
], |
||||||
|
contextTypes: { |
||||||
|
router: React.PropTypes.func |
||||||
|
}, |
||||||
|
handeSettingsUpdate: function (e) { |
||||||
|
e.preventDefault(); |
||||||
|
|
||||||
|
var newsettings = {} |
||||||
|
|
||||||
|
newsettings.pollInterval = $(this.getDOMNode()).find(".settings-pollInterval").val(); |
||||||
|
newsettings.pollIntervalProfile = $(this.getDOMNode()).find(".settings-pollIntervalProfile").val(); |
||||||
|
newsettings.ignoredUsers = $(this.getDOMNode()).find(".settings-ignoredUsers").val(); |
||||||
|
newsettings.host = $(this.getDOMNode()).find(".settings-host").val(); |
||||||
|
newsettings.logging = $(this.getDOMNode()).find(".settings-logging").val(); |
||||||
|
|
||||||
|
console.log(newsettings) |
||||||
|
|
||||||
|
localStorage.setItem("twister-react-settings",JSON.stringify(newsettings)); |
||||||
|
|
||||||
|
var event = new CustomEvent('appsettingschanged',{detail: newsettings}); |
||||||
|
window.dispatchEvent(event); |
||||||
|
|
||||||
|
return; |
||||||
|
}, |
||||||
|
render: function() { |
||||||
|
return ( |
||||||
|
React.createElement(ListGroup, null, |
||||||
|
React.createElement(ListGroupItem, null, "Settings"), |
||||||
|
React.createElement(ListGroupItem, null, |
||||||
|
React.createElement("form", {onSubmit: this.handeSettingsUpdate, className: "form-horizontal"}, |
||||||
|
React.createElement(Input, {type: "text", label: "pollInterval", |
||||||
|
defaultValue: this.state.appSettings.pollInterval, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-pollInterval"}), |
||||||
|
React.createElement(Input, {type: "text", label: "pollIntervalProfile", |
||||||
|
defaultValue: this.state.appSettings.pollIntervalProfile, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-pollIntervalProfile"}), |
||||||
|
React.createElement(Input, {type: "text", label: "ignoredUsers", |
||||||
|
defaultValue: this.state.appSettings.ignoredUsers, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-ignoredUsers"}), |
||||||
|
React.createElement(Input, {type: "text", label: "host", |
||||||
|
defaultValue: this.state.appSettings.host, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-host"}), |
||||||
|
React.createElement(Input, {type: "checkbox", label: "logging", |
||||||
|
defaultValue: this.state.appSettings.host, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-logging"}), |
||||||
|
React.createElement(Input, {type: "submit", value: "Save", wrapperClassName: "col-xs-offset-10 col-xs-2"}) |
||||||
|
) |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,72 @@ |
|||||||
|
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.getRetwistedUsername(), |
||||||
|
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 |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (post.isReply()) { |
||||||
|
|
||||||
|
postdata.isReply = true; |
||||||
|
postdata.replyUser = post.getReplyUser(); |
||||||
|
postdata.replyId = post.getReplyId(); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
postdata.isReply = 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 { |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,188 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
console.log("removed user ",this,error) |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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.state.appSettings.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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
//thisComponent.removeUser(this._name);
|
||||||
|
//console.log("removed user "+this._name+" because of empty status resource")
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,186 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
if (error.code==32052) { thisComponent.removeUser(this._name); } |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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) { |
||||||
|
newdata.push(previousState.data[i]); |
||||||
|
} else { |
||||||
|
previousState.postIdentifiers[previousState.data[i].postid]=false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
previousState.data = newdata; |
||||||
|
|
||||||
|
return previousState; |
||||||
|
|
||||||
|
}); |
||||||
|
}, |
||||||
|
updatePosts: function(outdatedLimit) { |
||||||
|
|
||||||
|
if (!outdatedLimit) {outdatedLimit=this.state.appSettings.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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
if (error.code==32052) { thisComponent.removeUser(this._name); } |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,255 @@ |
|||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
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'); |
||||||
|
var Conversation = require('./other/Conversation.js'); |
||||||
|
var Settings = require('./other/Settings.js'); |
||||||
|
var AppSettingsMixin = require('./common/AppSettingsMixin.js'); |
||||||
|
|
||||||
|
App = React.createClass({displayName: "App", |
||||||
|
|
||||||
|
mixins: [AppSettingsMixin,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 () { |
||||||
|
|
||||||
|
var state={}; |
||||||
|
|
||||||
|
state.activeAccount = localStorage.getItem("twister-react-activeAccount") |
||||||
|
|
||||||
|
state.accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (!state.activeAccount) { state.activeAccount=state.accounts[0]; } |
||||||
|
|
||||||
|
//console.log(state);
|
||||||
|
|
||||||
|
return state; |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
componentDidMount: function () { |
||||||
|
|
||||||
|
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, { |
||||||
|
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(Route, {name: "conversation", path: "/conversation/:username/:postid", handler: Conversation}), |
||||||
|
React.createElement(Route, {name: "settings", path: "/settings", handler: Settings}), |
||||||
|
React.createElement(DefaultRoute, {name: "home", handler: Home}) |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
|
||||||
|
initializeApp = function () { |
||||||
|
|
||||||
|
Router.run(routes, function (Handler) { |
||||||
|
React.render(React.createElement(Handler, null), document.getElementById('content')); |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.deserializeCache(JSON.parse(localStorage.getItem("twister-cache"))); |
||||||
|
|
||||||
|
var accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (accounts.length==0) { |
||||||
|
|
||||||
|
if (!localStorage.getItem("twister-react-settings")) { |
||||||
|
|
||||||
|
var appSettings = { |
||||||
|
|
||||||
|
pollInterval:60, |
||||||
|
pollIntervalProfile: 3600, |
||||||
|
ignoredUsers: "nobody", |
||||||
|
host: "http://user:pwd@localhost:28332" |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
var appSettings = JSON.parse(localStorage.getItem("twister-react-settings")); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.setup({ |
||||||
|
host: appSettings.host, |
||||||
|
//logfunc: function(log){console.log(log)},
|
||||||
|
outdatedLimit: appSettings.pollInterval, |
||||||
|
querySettingsByType: { |
||||||
|
|
||||||
|
outdatedLimit: { |
||||||
|
pubkey: appSettings.pollIntervalProfile, |
||||||
|
profile: appSettings.pollIntervalProfile, |
||||||
|
avatar: appSettings.pollIntervalProfile, |
||||||
|
torrent: appSettings.pollIntervalProfile, |
||||||
|
followings: appSettings.pollIntervalProfile |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Twister.loadServerAccounts(function(){ |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
} |
||||||
|
|
||||||
|
////// 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); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,42 @@ |
|||||||
|
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; |
||||||
|
|
||||||
|
var postdata = { |
||||||
|
username: post.getUsername(), |
||||||
|
id: post.getId(), |
||||||
|
timestamp: post.getTimestamp(), |
||||||
|
postid: postid |
||||||
|
} |
||||||
|
|
||||||
|
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 { |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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:[ |
||||||
|
AppSettingsMixin, |
||||||
|
StreamMixin, |
||||||
|
SetIntervalMixin, |
||||||
|
SafeStateChangeMixin, |
||||||
|
EventListenerMixin('newpostbyuser') |
||||||
|
], |
||||||
|
contextTypes: { |
||||||
|
router: React.PropTypes.func |
||||||
|
}, |
||||||
|
getInitialState: function() { |
||||||
|
return { |
||||||
|
username: this.context.router.getCurrentParams().username, |
||||||
|
postid: parseInt(this.context.router.getCurrentParams().postid), |
||||||
|
data: [], |
||||||
|
postIdentifiers: {}, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
updatePosts: function(outdatedLimit) { |
||||||
|
|
||||||
|
//console.log(this.state.username+":post"+this.state.postid)
|
||||||
|
|
||||||
|
if (!outdatedLimit) {outdatedLimit=this.state.appSettings.pollInterval/2;} |
||||||
|
|
||||||
|
var thisComponent = this; |
||||||
|
var thisUsername = this.state.username; |
||||||
|
|
||||||
|
var goUpConversation = function (post) { |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (post.isReply()) { |
||||||
|
|
||||||
|
post.doPostRepliedTo(goUpConversation); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
thisComponent.addPost(post); |
||||||
|
|
||||||
|
thisComponent.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
post.doReplies(doRepliesRecursive); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var doRepliesRecursive = function (replies) { |
||||||
|
|
||||||
|
for (var i in replies) { |
||||||
|
replies[i].doReplies(doRepliesRecursive); |
||||||
|
thisComponent.addPost(replies[i]); |
||||||
|
//console.log(replies[i].getContent())
|
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
Twister.getUser(this.state.username).doPost(this.state.postid,goUpConversation,{outdatedLimit: outdatedLimit, logfunc: function(log){console.log(log)}}); |
||||||
|
|
||||||
|
}, |
||||||
|
componentDidMount: function() { |
||||||
|
|
||||||
|
this.updatePosts(2*this.state.appSettings.pollInterval); |
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.pollInterval*1000); |
||||||
|
|
||||||
|
}, |
||||||
|
onnewpostbyuser: function (event) { |
||||||
|
|
||||||
|
//alert("got event")
|
||||||
|
|
||||||
|
this.updatePosts(-1); |
||||||
|
|
||||||
|
}, |
||||||
|
render: function() { |
||||||
|
return ( |
||||||
|
React.createElement(Postboard, {header: |
||||||
|
React.createElement(ListGroupItem, null, |
||||||
|
"Conversation" |
||||||
|
), |
||||||
|
data: this.state.data, loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,188 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
thisComponent.removeUser(this._name); |
||||||
|
console.log("removed user ",this,error) |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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) { |
||||||
|
newdata.push(previousState.data[i]); |
||||||
|
} else { |
||||||
|
previousState.postIdentifiers[previousState.data[i].postid]=false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
previousState.data = newdata; |
||||||
|
|
||||||
|
return previousState; |
||||||
|
|
||||||
|
}); |
||||||
|
}, |
||||||
|
updatePosts: function(outdatedLimit) { |
||||||
|
|
||||||
|
if (!outdatedLimit) {outdatedLimit=this.state.appSettings.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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
thisComponent.removeUser(this._name); |
||||||
|
console.log("removed user "+this._name+" because of empty status resource") |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,188 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
thisComponent.removeUser(this._name); |
||||||
|
console.log("removed user "+this._name+" because of empty status resource") |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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.state.appSettings.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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
thisComponent.removeUser(this._name); |
||||||
|
console.log("removed user "+this._name+" because of empty status resource") |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,188 @@ |
|||||||
|
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 AppSettingsMixin = require('../common/AppSettingsMixin.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: [ |
||||||
|
AppSettingsMixin, |
||||||
|
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, |
||||||
|
loading: true |
||||||
|
}; |
||||||
|
}, |
||||||
|
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.getTimestamp()<thisComponent.state.postrange) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
thisComponent.addPost(post); |
||||||
|
} |
||||||
|
|
||||||
|
},{ |
||||||
|
outdatedLimit: 2*thisComponent.state.appSettings.pollInterval, |
||||||
|
errorfunc: function(error){ |
||||||
|
thisComponent.removeUser(this._name); |
||||||
|
console.log("removed user "+this._name+" because of empty status resource") |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}, |
||||||
|
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.state.appSettings.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.setStateSafe({loading: false}); |
||||||
|
|
||||||
|
//thisComponent.updatePosts(thisComponent.state.appSettings.pollInterval);
|
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
this.setInterval(this.updatePosts, this.state.appSettings.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.state.appSettings.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}) |
||||||
|
), |
||||||
|
loading: this.state.loading}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,246 @@ |
|||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
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'); |
||||||
|
var Conversation = require('./other/Conversation.js'); |
||||||
|
var Settings = require('./other/Settings.js'); |
||||||
|
var AppSettingsMixin = require('./common/AppSettingsMixin.js'); |
||||||
|
|
||||||
|
App = React.createClass({displayName: "App", |
||||||
|
|
||||||
|
mixins: [AppSettingsMixin,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.accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
//console.log(state);
|
||||||
|
|
||||||
|
return state; |
||||||
|
}, |
||||||
|
|
||||||
|
componentDidMount: function () { |
||||||
|
|
||||||
|
var thisComponent = this; |
||||||
|
|
||||||
|
if (this.state.accounts.length==0) { |
||||||
|
|
||||||
|
Twister.setup({ |
||||||
|
host: this.state.appSettings.host, |
||||||
|
logfunc: function(log){console.log(log)}, |
||||||
|
outdatedLimit: this.state.appSettings.pollInterval, |
||||||
|
querySettingsByType: { |
||||||
|
|
||||||
|
outdatedLimit: { |
||||||
|
pubkey: this.state.appSettings.pollIntervalProfile, |
||||||
|
profile: this.state.appSettings.pollIntervalProfile, |
||||||
|
avatar: this.state.appSettings.pollIntervalProfile, |
||||||
|
torrent: this.state.appSettings.pollIntervalProfile, |
||||||
|
followings: this.state.appSettings.pollIntervalProfile |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
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, { |
||||||
|
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(Route, {name: "conversation", path: "/conversation/:username/:postid", handler: Conversation}), |
||||||
|
React.createElement(Route, {name: "settings", path: "/settings", handler: Settings}), |
||||||
|
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); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,75 @@ |
|||||||
|
var React = require('react'); |
||||||
|
var SetIntervalMixin = require("../common/SetIntervalMixin.js"); |
||||||
|
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js'); |
||||||
|
var EventListenerMixin = require('../common/EventListenerMixin.js'); |
||||||
|
var AppSettingsMixin = require('../common/AppSettingsMixin.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 |
||||||
|
, Input = ReactBootstrap.Input |
||||||
|
|
||||||
|
module.exports = Home = React.createClass({displayName: "Home", |
||||||
|
|
||||||
|
mixins: [ |
||||||
|
SetIntervalMixin, |
||||||
|
SafeStateChangeMixin, |
||||||
|
AppSettingsMixin |
||||||
|
], |
||||||
|
contextTypes: { |
||||||
|
router: React.PropTypes.func |
||||||
|
}, |
||||||
|
handeSettingsUpdate: function (e) { |
||||||
|
e.preventDefault(); |
||||||
|
|
||||||
|
var newsettings = {} |
||||||
|
|
||||||
|
newsettings.pollInterval = $(this.getDOMNode()).find(".settings-pollInterval").val(); |
||||||
|
newsettings.pollIntervalProfile = $(this.getDOMNode()).find(".settings-pollIntervalProfile").val(); |
||||||
|
newsettings.ignoredUsers = $(this.getDOMNode()).find(".settings-ignoredUsers").val(); |
||||||
|
newsettings.host = $(this.getDOMNode()).find(".settings-host").val(); |
||||||
|
newsettings.logging = $(this.getDOMNode()).find(".settings-logging").attr('checked'); |
||||||
|
|
||||||
|
console.log(newsettings) |
||||||
|
|
||||||
|
localStorage.setItem("twister-react-settings",JSON.stringify(newsettings)); |
||||||
|
|
||||||
|
var event = new CustomEvent('appsettingschanged',{detail: newsettings}); |
||||||
|
window.dispatchEvent(event); |
||||||
|
|
||||||
|
return; |
||||||
|
}, |
||||||
|
render: function() { |
||||||
|
return ( |
||||||
|
React.createElement(ListGroup, null, |
||||||
|
React.createElement(ListGroupItem, null, "Settings"), |
||||||
|
React.createElement(ListGroupItem, null, |
||||||
|
React.createElement("form", {onSubmit: this.handeSettingsUpdate, className: "form-horizontal"}, |
||||||
|
React.createElement(Input, {type: "text", label: "pollInterval", |
||||||
|
defaultValue: this.state.appSettings.pollInterval, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-pollInterval"}), |
||||||
|
React.createElement(Input, {type: "text", label: "pollIntervalProfile", |
||||||
|
defaultValue: this.state.appSettings.pollIntervalProfile, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-pollIntervalProfile"}), |
||||||
|
React.createElement(Input, {type: "text", label: "ignoredUsers", |
||||||
|
defaultValue: this.state.appSettings.ignoredUsers, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-ignoredUsers"}), |
||||||
|
React.createElement(Input, {type: "text", label: "host", |
||||||
|
defaultValue: this.state.appSettings.host, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-host"}), |
||||||
|
React.createElement(Input, {type: "checkbox", label: "logging", |
||||||
|
defaultValue: this.state.appSettings.logging, labelClassName: "col-xs-4", |
||||||
|
wrapperClassName: "col-xs-8", className: "settings-logging"}), |
||||||
|
React.createElement(Input, {type: "submit", value: "Save", wrapperClassName: "col-xs-offset-10 col-xs-2"}) |
||||||
|
) |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,275 @@ |
|||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
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'); |
||||||
|
var Conversation = require('./other/Conversation.js'); |
||||||
|
var Settings = require('./other/Settings.js'); |
||||||
|
var AppSettingsMixin = require('./common/AppSettingsMixin.js'); |
||||||
|
|
||||||
|
App = React.createClass({displayName: "App", |
||||||
|
|
||||||
|
mixins: [AppSettingsMixin,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 () { |
||||||
|
|
||||||
|
var state={}; |
||||||
|
|
||||||
|
state.activeAccount = localStorage.getItem("twister-react-activeAccount") |
||||||
|
|
||||||
|
state.accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (!state.activeAccount) { state.activeAccount=state.accounts[0]; } |
||||||
|
|
||||||
|
//console.log(state);
|
||||||
|
|
||||||
|
return state; |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
componentDidMount: function () { |
||||||
|
|
||||||
|
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, { |
||||||
|
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(Route, {name: "conversation", path: "/conversation/:username/:postid", handler: Conversation}), |
||||||
|
React.createElement(Route, {name: "settings", path: "/settings", handler: Settings}), |
||||||
|
React.createElement(DefaultRoute, {name: "home", handler: Home}) |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
|
||||||
|
initializeApp = function () { |
||||||
|
|
||||||
|
Router.run(routes, function (Handler) { |
||||||
|
React.render(React.createElement(Handler, null), document.getElementById('content')); |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.deserializeCache(JSON.parse(localStorage.getItem("twister-cache"))); |
||||||
|
|
||||||
|
Twister.setup({logfunc: function(log){console.log(log)}}) |
||||||
|
|
||||||
|
var accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (accounts.length==0) { |
||||||
|
|
||||||
|
if (!localStorage.getItem("twister-react-settings")) { |
||||||
|
|
||||||
|
var appSettings = { |
||||||
|
|
||||||
|
pollInterval:60, |
||||||
|
pollIntervalProfile: 3600, |
||||||
|
ignoredUsers: "nobody", |
||||||
|
host: "http://user:pwd@localhost:28332" |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
var appSettings = JSON.parse(localStorage.getItem("twister-react-settings")); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Twister.setup({ |
||||||
|
host: appSettings.host, |
||||||
|
//logfunc: function(log){console.log(log)},
|
||||||
|
outdatedLimit: appSettings.pollInterval, |
||||||
|
querySettingsByType: { |
||||||
|
|
||||||
|
outdatedLimit: { |
||||||
|
pubkey: appSettings.pollIntervalProfile, |
||||||
|
profile: appSettings.pollIntervalProfile, |
||||||
|
avatar: appSettings.pollIntervalProfile, |
||||||
|
torrent: appSettings.pollIntervalProfile, |
||||||
|
followings: appSettings.pollIntervalProfile |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Twister.loadServerAccounts(function(){ |
||||||
|
|
||||||
|
var activeAccount = localStorage.getItem("twister-react-activeAccount"); |
||||||
|
|
||||||
|
var accounts = Twister.getAccounts(); |
||||||
|
|
||||||
|
if (!activeAccount) { |
||||||
|
|
||||||
|
activeAccount = accounts[0]; |
||||||
|
localStorage.setItem("twister-react-activeAccount",activeAccount); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
console.log("active account defaulted to "+activeAccount) |
||||||
|
|
||||||
|
Twister.getAccount(activeAccount).activateTorrents(function(){ |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
initializeApp(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
////// 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); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1 @@ |
|||||||
|
{".js":"04de173f1f09e92fe10ba2856499079d37de45f7.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"0aff40b9075c302cd82ad792ae85b2edb98547f2.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"15b953bb2190396fcf451509d39120418f182314.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"1f8c40f16c571a231c635fb182d8bf2e7865878a.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"357b3c976317bd30460a76a5b582d2a806fd0a52.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"3ba2c49efd95be4ad717e6f9972efb105398eaaf.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"3bfa39aabb13db53498065a81a9dfd035d6bcd3f.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"3dcaf4ec25180cdbb6808472deab30e3b335c5af.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"3f2a37f90e1ee545b33bb432426bc5b3b8b5bddd.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"43012ad3b27487f50e721618da9d7e09e8e821db.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"48711d4fe85cb25a78d9966e1fc3826535c72c7e.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"53c695924055d7f153218cbf005457df27ff7b91.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"540a938bc19e9f984968a6425280672a470ab63a.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"57719eb13f233a593e46a1a236292193339cc9b3.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"586392bc882293105333126aa2ab09d36c0d3aaa.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"5a283d802f5720e888ae8bc435b87432d5fe0e4f.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"5c8b7e3107de4f3ad8c663314f339598adcc4c09.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"5d2323f47209b1542a4f6d1ff69e887836c4d7ef.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"65d8380a32674e1bd91226089e1490e0965ce788.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"6bb48745ac4429d537d53382f5dcec3d67511fef.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"6ce0d3c4885a6fcfa77bee2f167ed69ace239ce9.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"6e932fafed6e3b7d13a9dccfcc8012f5e12eb595.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"6fc94b273b3f1749ddf8973ab9f769ea5c890b71.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"729706f34ff41684dfb3441af0f1e16876635ef6.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"8d60c25c4e017f1ce02928c7e2a5fe595549ca8c.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"92d3322a4ef4431522163222fe51aa41db966a46.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"98d867ea326a51f69b6f3891955118ac23fde8f8.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"98dd8434ca1efe630f32b3f5db7c4977ccc91302.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"a1d3510314875c02aa598cbd3b7cde5d488c828f.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"a4b107445cccc7ecd58b53b98715784e2eda3990.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"af9f96e2470eb5c2f3be2acf762ee2e95f6e3ee2.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"b4a73e16454e22c3fe63de8dc592a66eeeba019e.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"b4ceb3db3c520b3d0f6b7fe5018c500dd44180fd.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"b59a0c4e7d06c25ad079b1440889e933dd52e54f.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"bfd014f2b9b75cbb8a352f92628468e74b00789c.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"d2536a92767fec2f9de04bd6bf315e18407b7991.js"} |
@ -0,0 +1 @@ |
|||||||
|
{".js":"d93282f77fea36519cc3fba804c7292c040979d8.js"} |
Loading…
Reference in new issue