From 5d08929e04cec09f76eee086a365bd0124f4b494 Mon Sep 17 00:00:00 2001 From: Julian Steinwachs Date: Wed, 22 Apr 2015 10:38:44 +0200 Subject: [PATCH] endless scrolling --- build/app-bundle.js | 659 ++++++++++-------- build/twister-lib.js | 23 +- css/main.css | 13 +- ...8c714844c29536ebc79f9d30805d704b52fd613.js | 101 +++ ...790c1dcc8106c5ece39d81ebfaa7b9ffa396496.js | 102 +++ ...dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.js | 160 +++++ ...7e111cc9b81f1cdb7a5eaa6ce00f435348bd48a.js | 12 + ...c5a8a3726ee4db1fc5375c1f0b9ff889948e240.js | 101 +++ ...cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.js | 101 +++ ...d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.js | 172 +++++ ...f1e941d8495d0f750d535161ad70ea16a9e4746.js | 60 ++ ...2b320e94d738a654a51f0072466d00e804e745d.js | 101 +++ ...963c41578eaddc39957b6cb561cf7b19a2dc5ce.js | 162 +++++ ...bdf1b84f178854813606fd7d13938769358b0aa.js | 101 +++ ...b03360003ecd9b3f73a35665504c5c526098e44.js | 162 +++++ ...0a01a350ccea8f837824abb8a78698c5971130d.js | 60 ++ ...17d69cf89ab760cfd9dfbc25814ba6962145289.js | 101 +++ ...3a76356a36e400cc41c7877268fef1c940f2214.js | 101 +++ ...5bd287b14edcd74662d28b1aaf141b7e86eb5a4.js | 101 +++ ...9d6a84f3275b12417299ef742e2824d3ce6e610.js | 102 +++ ...a94dd6850590563ad4a1c5bfe8d9538c625f7cc.js | 12 + ...75daba84d9bb9b874cc39f466ceed477f12a293.js | 101 +++ ...96e5b381fdf9155de48fe91471ffc18f049dae0.js | 160 +++++ ...44a64a27d99a484a4cf8e757c2d902e147932fa.js | 12 + ...b2cde08d4b5a26c66a5c56c75e288b0d0476c48.js | 172 +++++ ...57d14fa426b54106d5bc5cc344fa166bfb8f51b.js | 166 +++++ ...7f08b920603d73fac97d6007dbf6b5bc7f57ba5.js | 62 ++ ...71ed2a487872dd50be6d967cedeff0a6b5767b9.js | 101 +++ ...4da31f5826a7a96ab3cc20d1d12e0b754e4085a.js | 172 +++++ ...837fa85d2697fe09e9b8a879a4ced37d7c6d3c0.js | 101 +++ ...714844c29536ebc79f9d30805d704b52fd613.json | 1 + ...0c1dcc8106c5ece39d81ebfaa7b9ffa396496.json | 1 + ...4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.json | 1 + ...111cc9b81f1cdb7a5eaa6ce00f435348bd48a.json | 1 + ...a8a3726ee4db1fc5375c1f0b9ff889948e240.json | 1 + ...5ee718a67a61dc4cbdfb8e03165b978a0e71a.json | 1 + ...f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.json | 1 + ...e941d8495d0f750d535161ad70ea16a9e4746.json | 1 + ...320e94d738a654a51f0072466d00e804e745d.json | 1 + ...3c41578eaddc39957b6cb561cf7b19a2dc5ce.json | 1 + ...f1b84f178854813606fd7d13938769358b0aa.json | 1 + ...3360003ecd9b3f73a35665504c5c526098e44.json | 1 + ...01a350ccea8f837824abb8a78698c5971130d.json | 1 + ...d69cf89ab760cfd9dfbc25814ba6962145289.json | 1 + ...76356a36e400cc41c7877268fef1c940f2214.json | 1 + ...d287b14edcd74662d28b1aaf141b7e86eb5a4.json | 1 + ...6a84f3275b12417299ef742e2824d3ce6e610.json | 1 + ...4dd6850590563ad4a1c5bfe8d9538c625f7cc.json | 1 + ...daba84d9bb9b874cc39f466ceed477f12a293.json | 1 + ...e5b381fdf9155de48fe91471ffc18f049dae0.json | 1 + ...a64a27d99a484a4cf8e757c2d902e147932fa.json | 1 + ...cde08d4b5a26c66a5c56c75e288b0d0476c48.json | 1 + ...d14fa426b54106d5bc5cc344fa166bfb8f51b.json | 1 + ...08b920603d73fac97d6007dbf6b5bc7f57ba5.json | 1 + ...ed2a487872dd50be6d967cedeff0a6b5767b9.json | 1 + ...a31f5826a7a96ab3cc20d1d12e0b754e4085a.json | 1 + ...7fa85d2697fe09e9b8a879a4ced37d7c6d3c0.json | 1 + js/App.js | 13 +- js/EventListenerMixin.js | 12 + js/Post.js | 21 +- js/SafeStateChangeMixin.js | 62 ++ js/StreamMixin.js | 2 +- js/Timeline.js | 27 +- jsx/App.js | 13 +- jsx/EventListenerMixin.js | 12 + jsx/Post.js | 21 +- jsx/SafeStateChangeMixin.js | 62 ++ jsx/StreamMixin.js | 2 +- jsx/Timeline.js | 27 +- .../react-mixin-safe-state-change/LICENSE | 22 + .../react-mixin-safe-state-change/README.md | 35 + .../react-mixin-safe-state-change/index.js | 89 +++ .../package.json | 49 ++ 73 files changed, 3716 insertions(+), 334 deletions(-) create mode 100644 js/.module-cache/08c714844c29536ebc79f9d30805d704b52fd613.js create mode 100644 js/.module-cache/1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.js create mode 100644 js/.module-cache/1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.js create mode 100644 js/.module-cache/37e111cc9b81f1cdb7a5eaa6ce00f435348bd48a.js create mode 100644 js/.module-cache/3c5a8a3726ee4db1fc5375c1f0b9ff889948e240.js create mode 100644 js/.module-cache/3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.js create mode 100644 js/.module-cache/5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.js create mode 100644 js/.module-cache/5f1e941d8495d0f750d535161ad70ea16a9e4746.js create mode 100644 js/.module-cache/62b320e94d738a654a51f0072466d00e804e745d.js create mode 100644 js/.module-cache/6963c41578eaddc39957b6cb561cf7b19a2dc5ce.js create mode 100644 js/.module-cache/6bdf1b84f178854813606fd7d13938769358b0aa.js create mode 100644 js/.module-cache/7b03360003ecd9b3f73a35665504c5c526098e44.js create mode 100644 js/.module-cache/80a01a350ccea8f837824abb8a78698c5971130d.js create mode 100644 js/.module-cache/817d69cf89ab760cfd9dfbc25814ba6962145289.js create mode 100644 js/.module-cache/83a76356a36e400cc41c7877268fef1c940f2214.js create mode 100644 js/.module-cache/95bd287b14edcd74662d28b1aaf141b7e86eb5a4.js create mode 100644 js/.module-cache/99d6a84f3275b12417299ef742e2824d3ce6e610.js create mode 100644 js/.module-cache/9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.js create mode 100644 js/.module-cache/a75daba84d9bb9b874cc39f466ceed477f12a293.js create mode 100644 js/.module-cache/a96e5b381fdf9155de48fe91471ffc18f049dae0.js create mode 100644 js/.module-cache/b44a64a27d99a484a4cf8e757c2d902e147932fa.js create mode 100644 js/.module-cache/bb2cde08d4b5a26c66a5c56c75e288b0d0476c48.js create mode 100644 js/.module-cache/c57d14fa426b54106d5bc5cc344fa166bfb8f51b.js create mode 100644 js/.module-cache/c7f08b920603d73fac97d6007dbf6b5bc7f57ba5.js create mode 100644 js/.module-cache/d71ed2a487872dd50be6d967cedeff0a6b5767b9.js create mode 100644 js/.module-cache/f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.js create mode 100644 js/.module-cache/f837fa85d2697fe09e9b8a879a4ced37d7c6d3c0.js create mode 100644 js/.module-cache/manifest/08c714844c29536ebc79f9d30805d704b52fd613.json create mode 100644 js/.module-cache/manifest/1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.json create mode 100644 js/.module-cache/manifest/1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.json create mode 100644 js/.module-cache/manifest/37e111cc9b81f1cdb7a5eaa6ce00f435348bd48a.json create mode 100644 js/.module-cache/manifest/3c5a8a3726ee4db1fc5375c1f0b9ff889948e240.json create mode 100644 js/.module-cache/manifest/3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.json create mode 100644 js/.module-cache/manifest/5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.json create mode 100644 js/.module-cache/manifest/5f1e941d8495d0f750d535161ad70ea16a9e4746.json create mode 100644 js/.module-cache/manifest/62b320e94d738a654a51f0072466d00e804e745d.json create mode 100644 js/.module-cache/manifest/6963c41578eaddc39957b6cb561cf7b19a2dc5ce.json create mode 100644 js/.module-cache/manifest/6bdf1b84f178854813606fd7d13938769358b0aa.json create mode 100644 js/.module-cache/manifest/7b03360003ecd9b3f73a35665504c5c526098e44.json create mode 100644 js/.module-cache/manifest/80a01a350ccea8f837824abb8a78698c5971130d.json create mode 100644 js/.module-cache/manifest/817d69cf89ab760cfd9dfbc25814ba6962145289.json create mode 100644 js/.module-cache/manifest/83a76356a36e400cc41c7877268fef1c940f2214.json create mode 100644 js/.module-cache/manifest/95bd287b14edcd74662d28b1aaf141b7e86eb5a4.json create mode 100644 js/.module-cache/manifest/99d6a84f3275b12417299ef742e2824d3ce6e610.json create mode 100644 js/.module-cache/manifest/9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.json create mode 100644 js/.module-cache/manifest/a75daba84d9bb9b874cc39f466ceed477f12a293.json create mode 100644 js/.module-cache/manifest/a96e5b381fdf9155de48fe91471ffc18f049dae0.json create mode 100644 js/.module-cache/manifest/b44a64a27d99a484a4cf8e757c2d902e147932fa.json create mode 100644 js/.module-cache/manifest/bb2cde08d4b5a26c66a5c56c75e288b0d0476c48.json create mode 100644 js/.module-cache/manifest/c57d14fa426b54106d5bc5cc344fa166bfb8f51b.json create mode 100644 js/.module-cache/manifest/c7f08b920603d73fac97d6007dbf6b5bc7f57ba5.json create mode 100644 js/.module-cache/manifest/d71ed2a487872dd50be6d967cedeff0a6b5767b9.json create mode 100644 js/.module-cache/manifest/f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.json create mode 100644 js/.module-cache/manifest/f837fa85d2697fe09e9b8a879a4ced37d7c6d3c0.json create mode 100644 js/EventListenerMixin.js create mode 100644 js/SafeStateChangeMixin.js create mode 100644 jsx/EventListenerMixin.js create mode 100644 jsx/SafeStateChangeMixin.js create mode 100644 node_modules/react-mixin-safe-state-change/LICENSE create mode 100644 node_modules/react-mixin-safe-state-change/README.md create mode 100644 node_modules/react-mixin-safe-state-change/index.js create mode 100644 node_modules/react-mixin-safe-state-change/package.json diff --git a/build/app-bundle.js b/build/app-bundle.js index bf7aa02..6d3baf4 100644 --- a/build/app-bundle.js +++ b/build/app-bundle.js @@ -57,7 +57,7 @@ App = React.createClass({displayName: "App", "pampalulu" ) ), - React.createElement(RouteHandler, {pollInterval: "60000", key: this.getHandlerKey()}) + React.createElement(RouteHandler, {pollInterval: "60", key: this.getHandlerKey()}) ) ); } @@ -92,7 +92,29 @@ loadCache(); setInterval(saveCache,300000); Twister.loadServerAccounts(intitializeApp); -},{"./Timeline.js":6,"react":261,"react-bootstrap":58,"react-router":91}],2:[function(require,module,exports){ + +////// INIT EVENTLISTENERS ON WINDOW + +window.onscroll = function(ev) { + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + var event = new Event('scrolledtobottom'); + window.dispatchEvent(event); + } +}; +},{"./Timeline.js":8,"react":263,"react-bootstrap":60,"react-router":93}],2:[function(require,module,exports){ +module.exports = EventListenerMixin = function (eventtype) { + + return { + componentDidMount: function() { + window.addEventListener(eventtype, this["on"+eventtype]); + }, + componentWillUnmount: function() { + window.removeEventListener(eventtype, this["on"+eventtype]); + } + } + +} +},{}],3:[function(require,module,exports){ var ReactBootstrap = require('react-bootstrap') , Grid = ReactBootstrap.Grid @@ -103,9 +125,10 @@ var ReactBootstrap = require('react-bootstrap') var React = require('react'); var SetIntervalMixin = require("./SetIntervalMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); module.exports = Post = React.createClass({displayName: "Post", - mixins: [SetIntervalMixin], + mixins: [SetIntervalMixin,SafeStateChangeMixin], getInitialState: function() { return { avatar: "img/genericPerson.png", @@ -124,7 +147,7 @@ module.exports = Post = React.createClass({displayName: "Post", else if (secondsAgo<45*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"} else if (secondsAgo<60*60*60*18) {newTimeAgo=Math.round(secondsAgo/60/60/60)+"d"} - this.setState({timeAgo: newTimeAgo}); + this.setStateSafe({timeAgo: newTimeAgo}); }, componentDidMount: function () { @@ -132,16 +155,16 @@ module.exports = Post = React.createClass({displayName: "Post", //console.log(this.props.post.username+":post"+this.props.post.id); Twister.getUser(this.props.post.username).doAvatar(function(avatar){ - thisComponent.setState({avatar: avatar.getUrl()}); + thisComponent.setStateSafe({avatar: avatar.getUrl()}); }); Twister.getUser(this.props.post.username).doProfile(function(profile){ - thisComponent.setState({fullname: profile.getField("fullname")}); + thisComponent.setStateSafe({fullname: profile.getField("fullname")}); }); if (this.props.post.isRetwist) { Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){ - thisComponent.setState({retwistingUser: profile.getField("fullname")}); + thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")}); }); } @@ -153,22 +176,22 @@ module.exports = Post = React.createClass({displayName: "Post", render: function() { var post = this.props.post; return ( - React.createElement(ListGroupItem, null, + React.createElement(ListGroupItem, {fill: true}, React.createElement(Grid, {fill: true}, React.createElement(Row, null, - React.createElement(Col, {xs: 2}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), + React.createElement(Col, {xs: 2, className: "fullytight"}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), React.createElement(Col, {xs: 9}, React.createElement("strong", null, this.state.fullname), " ", post.content ), - React.createElement(Col, {xs: 1}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) + React.createElement(Col, {xs: 1, className: "fullytight"}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) ), React.createElement(Row, null, - React.createElement(Col, {xs: 4}, + React.createElement(Col, {xs: 6}, post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser)) ), - React.createElement(Col, {xs: 8}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) + React.createElement(Col, {xs: 6}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) ) ) @@ -193,7 +216,7 @@ module.exports = Post = React.createClass({displayName: "Post",
*/ -},{"./SetIntervalMixin.js":4,"react":261,"react-bootstrap":58}],3:[function(require,module,exports){ +},{"./SafeStateChangeMixin.js":5,"./SetIntervalMixin.js":6,"react":263,"react-bootstrap":60}],4:[function(require,module,exports){ var ReactBootstrap = require('react-bootstrap') , NavItem = ReactBootstrap.NavItem @@ -219,7 +242,70 @@ module.exports = Postboard = React.createClass({displayName: "Postboard", ); } }); -},{"./Post.js":2,"react":261,"react-bootstrap":58}],4:[function(require,module,exports){ +},{"./Post.js":3,"react":263,"react-bootstrap":60}],5:[function(require,module,exports){ +function isValidLifeCycleForReplaceState(instance) { + // See function validateLifeCycleOnReplaceState(instance) in + // ReactCompositeComponent.js + var result = true; + + //result &= ReactCurrentOwner.current == null; + //result &= __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || __REACT_DEVTOOLS_GLOBAL_HOOK__._reactRuntime.CurrentOwner.current == null; + + result &= instance.isMounted(); + + return result; +} + +var safeStateChangeMixin = { + /** + * Calls setState with the provided parameters if it is safe to do so. + * + * Safe means it will try to do the same checks as setState does + * without throwing an exception. + * See function validateLifeCycleOnReplaceState(instance) in + * ReactCompositeComponent.js + * + * @param {object} partialState Next partial state to be merged with state. + * @param {?function} callback Called after state is updated. + * @return {boolean} Whether or not setState is called. + * @final + * @protected + */ + setStateSafe: function (partialState, callback) { + if (isValidLifeCycleForReplaceState(this)) { + this.setState(partialState, callback); + return true; + } + + return false; + }, + + /** + * Calls replaceState with the provided parameters if it safe to do so. + * + * Safe means it will try to do the same checks as replaceState does + * without throwing an exception. + * See function validateLifeCycleOnReplaceState(instance) in + * ReactCompositeComponent.js + * + * @param {object} completeState Next state. + * @param {?function} callback Called after state is updated. + * @return {boolean} Whether or not setState is called. + * @final + * @protected + */ + replaceStateSafe: function(completeState, callback) { + if (isValidLifeCycleForReplaceState(this)) { + this.replaceState(completeState, callback); + return true; + } + + return false; + } +}; + +module.exports = safeStateChangeMixin; +},{}],6:[function(require,module,exports){ module.exports = SetIntervalMixin = { componentWillMount: function() { this.intervals = []; @@ -231,7 +317,7 @@ module.exports = SetIntervalMixin = { this.intervals.map(clearInterval); } }; -},{}],5:[function(require,module,exports){ +},{}],7:[function(require,module,exports){ module.exports = StreamMixin = { addPost: function(post) { @@ -240,7 +326,7 @@ module.exports = StreamMixin = { if (!this.state.postIdentifiers[postid] && this.verifyPost(post)) { - this.setState(function(previousState, currentProps) { + this.setStateSafe(function(previousState, currentProps) { previousState.postIdentifiers[postid] = true; @@ -292,7 +378,7 @@ module.exports = StreamMixin = { } } } -},{}],6:[function(require,module,exports){ +},{}],8:[function(require,module,exports){ var ReactBootstrap = require('react-bootstrap') , NavItem = ReactBootstrap.NavItem @@ -306,10 +392,13 @@ var React = require('react'); var Postboard = require("./Postboard.js"); var SetIntervalMixin = require("./SetIntervalMixin.js"); var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +var EventListenerMixin = require('./EventListenerMixin.js') module.exports = Timeline = React.createClass({displayName: "Timeline", - mixins: [StreamMixin,SetIntervalMixin], + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin,EventListenerMixin('scrolledtobottom')], contextTypes: { router: React.PropTypes.func }, @@ -332,7 +421,7 @@ module.exports = Timeline = React.createClass({displayName: "Timeline", postIdentifiers: {}, usernames: [], timelineUser: [], - postrange: ( Date.now()/1000 - 24*60*60 ), + postrange: ( Date.now()/1000 - 12*60*60 ), min_posts: 30 }; }, @@ -341,7 +430,7 @@ module.exports = Timeline = React.createClass({displayName: "Timeline", var thisComponent = this; - this.setState(function(previousState, currentProps){ + this.setStateSafe(function(previousState, currentProps){ previousState.usernames.push(username); @@ -362,7 +451,7 @@ module.exports = Timeline = React.createClass({displayName: "Timeline", }, removeUser: function(username) { - this.setState(function(previousState, currentProps){ + this.setStateSafe(function(previousState, currentProps){ var newusers = []; @@ -392,7 +481,7 @@ module.exports = Timeline = React.createClass({displayName: "Timeline", }, updatePosts: function(outdatedLimit) { - if (!outdatedLimit) {outdatedLimit=30;} + if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;} for (var i = 0; i + + +
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.js b/js/.module-cache/1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.js new file mode 100644 index 0000000..03d393e --- /dev/null +++ b/js/.module-cache/1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.js @@ -0,0 +1,102 @@ + + +/* +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') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + +var React = require('react'); +var Router = require('react-router'); +var { Route, DefaultRoute, RouteHandler, Link } = Router; + +var Timeline = require("./Timeline.js"); + +App = React.createClass({displayName: "App", + + 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; + var id = JSON.stringify(router.getCurrentParams()); + if (id) { key += id; } + return key; + } else {return "none"} + }, + + render: function() { + return ( + React.createElement("div", null, + React.createElement(Nav, {bsStyle: "pills"}, + React.createElement(NavItem, {href: "#timeline/tschaul"}, + "tschaul" + ), + React.createElement(NavItem, {href: "#timeline/timbuktu"}, + "timbuktu" + ), + React.createElement(NavItem, {href: "#timeline/pampalulu"}, + "pampalulu" + ) + ), + React.createElement(RouteHandler, {pollInterval: "60", key: this.getHandlerKey()}) + ) + ); + } +}); + + +var routes = ( + React.createElement(Route, {handler: App, path: "/"}, + React.createElement(Route, {name: "timeline", path: "timeline/:timelineUser", handler: Timeline}) + ) +); + + +var intitializeApp = function(res){ + + Router.run(routes, function (Handler) { + React.render(React.createElement(Handler, null), document.getElementById('content')); + }); + +}; + +///////// LOAD TWISTER FROM CACHE AND INITIALIZE + + +Twister.init({ + host: 'http://user:pwd@localhost:28332', + errorfunc: function(error){console.log(this,error)} +}); + +loadCache(); + +setInterval(saveCache,300000); + +Twister.loadServerAccounts(intitializeApp); + +////// INIT EVENTLISTENERS ON WINDOW + +window.onscroll = function(ev) { + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + var event = new Event('scrolledtobottom'); + window.dispatchEvent(event); + } +}; \ No newline at end of file diff --git a/js/.module-cache/1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.js b/js/.module-cache/1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.js new file mode 100644 index 0000000..d0c2336 --- /dev/null +++ b/js/.module-cache/1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.js @@ -0,0 +1,160 @@ + +var ReactBootstrap = require('react-bootstrap') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + + +var React = require('react'); + +var Postboard = require("./Postboard.js"); +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('react-mixin-safe-state-change'); + +module.exports = Timeline = React.createClass({displayName: "Timeline", + + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin], + contextTypes: { + router: React.PropTypes.func + }, + verifyPost: function (post) { + + var verified = false; + + for (var i = 0; i + + +
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.js b/js/.module-cache/3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.js new file mode 100644 index 0000000..11ef710 --- /dev/null +++ b/js/.module-cache/3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.js @@ -0,0 +1,101 @@ + +var ReactBootstrap = require('react-bootstrap') + , Grid = ReactBootstrap.Grid + , Col = ReactBootstrap.Col + , Row = ReactBootstrap.Row + , ListGroupItem = ReactBootstrap.ListGroupItem + +var React = require('react'); + +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var SafeStateChangeMixin = require('react-mixin-safe-state-change'); + +module.exports = Post = React.createClass({displayName: "Post", + mixins: [SetIntervalMixin], + getInitialState: function() { + return { + avatar: "img/genericPerson.png", + fullname: "", + retwistingUser: this.props.post.retwistingUser, + timeAgo: "" + }; + }, + updateTimeAgo: function() { + var secondsAgo = Date.now()/1000-this.props.post.timestamp; + + var newTimeAgo = ""; + + if (secondsAgo<45) {newTimeAgo="1m"} + else if (secondsAgo<45*60) {newTimeAgo=Math.round(secondsAgo/60)+"m"} + else if (secondsAgo<45*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"} + else if (secondsAgo<60*60*60*18) {newTimeAgo=Math.round(secondsAgo/60/60/60)+"d"} + + this.setStateSafe({timeAgo: newTimeAgo}); + + }, + componentDidMount: function () { + var thisComponent = this; + + //console.log(this.props.post.username+":post"+this.props.post.id); + Twister.getUser(this.props.post.username).doAvatar(function(avatar){ + thisComponent.setStateSafe({avatar: avatar.getUrl()}); + }); + Twister.getUser(this.props.post.username).doProfile(function(profile){ + thisComponent.setStateSafe({fullname: profile.getField("fullname")}); + }); + + if (this.props.post.isRetwist) { + + Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){ + thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")}); + }); + + } + + this.updateTimeAgo(); + + this.setInterval(this.updateTimeAgo,60000); + }, + render: function() { + var post = this.props.post; + return ( + React.createElement(ListGroupItem, null, + React.createElement(Grid, {fill: true}, + React.createElement(Row, null, + React.createElement(Col, {xs: 2}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), + React.createElement(Col, {xs: 9}, + React.createElement("strong", null, this.state.fullname), " ", + post.content + ), + React.createElement(Col, {xs: 1}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) + ), + React.createElement(Row, null, + React.createElement(Col, {xs: 4}, + post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser)) + + ), + React.createElement(Col, {xs: 8}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) + ) + ) + + ) + ); + } +}); + +/* +
+ +
+
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.js b/js/.module-cache/5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.js new file mode 100644 index 0000000..af3e075 --- /dev/null +++ b/js/.module-cache/5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.js @@ -0,0 +1,172 @@ + +var ReactBootstrap = require('react-bootstrap') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + + +var React = require('react'); + +var Postboard = require("./Postboard.js"); +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +var EventListenerMixin = require('./EventListenerMixin.js') + +module.exports = Timeline = React.createClass({displayName: "Timeline", + + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin,EventListenerMixin('scrolledtobottom')], + contextTypes: { + router: React.PropTypes.func + }, + verifyPost: function (post) { + + var verified = false; + + for (var i = 0; i b.timestamp) + return -1; + return 0; + } + + previousState.data.sort(compare); + + return {data: previousState.data, postIdentifiers: previousState.postIdentifiers }; + }); + + } else { + + + } + } +} \ No newline at end of file diff --git a/js/.module-cache/62b320e94d738a654a51f0072466d00e804e745d.js b/js/.module-cache/62b320e94d738a654a51f0072466d00e804e745d.js new file mode 100644 index 0000000..af71ea1 --- /dev/null +++ b/js/.module-cache/62b320e94d738a654a51f0072466d00e804e745d.js @@ -0,0 +1,101 @@ + +var ReactBootstrap = require('react-bootstrap') + , Grid = ReactBootstrap.Grid + , Col = ReactBootstrap.Col + , Row = ReactBootstrap.Row + , ListGroupItem = ReactBootstrap.ListGroupItem + +var React = require('react'); + +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +module.exports = Post = React.createClass({displayName: "Post", + mixins: [SetIntervalMixin,SafeStateChangeMixin], + getInitialState: function() { + return { + avatar: "img/genericPerson.png", + fullname: "", + retwistingUser: this.props.post.retwistingUser, + timeAgo: "" + }; + }, + updateTimeAgo: function() { + var secondsAgo = Date.now()/1000-this.props.post.timestamp; + + var newTimeAgo = ""; + + if (secondsAgo<45) {newTimeAgo="1m"} + else if (secondsAgo<45*60) {newTimeAgo=Math.round(secondsAgo/60)+"m"} + else if (secondsAgo<45*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"} + else if (secondsAgo<60*60*60*18) {newTimeAgo=Math.round(secondsAgo/60/60/60)+"d"} + + this.setStateSafe({timeAgo: newTimeAgo}); + + }, + componentDidMount: function () { + var thisComponent = this; + + //console.log(this.props.post.username+":post"+this.props.post.id); + Twister.getUser(this.props.post.username).doAvatar(function(avatar){ + thisComponent.setStateSafe({avatar: avatar.getUrl()}); + }); + Twister.getUser(this.props.post.username).doProfile(function(profile){ + thisComponent.setStateSafe({fullname: profile.getField("fullname")}); + }); + + if (this.props.post.isRetwist) { + + Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){ + thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")}); + }); + + } + + this.updateTimeAgo(); + + this.setInterval(this.updateTimeAgo,60000); + }, + render: function() { + var post = this.props.post; + return ( + React.createElement(ListGroupItem, {fill: true}, + React.createElement(Grid, {fill: true}, + React.createElement(Row, null, + React.createElement(Col, {xs: 2, className: "tight"}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), + React.createElement(Col, {xs: 9}, + React.createElement("strong", null, this.state.fullname), " ", + post.content + ), + React.createElement(Col, {xs: 1}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) + ), + React.createElement(Row, null, + React.createElement(Col, {xs: 4}, + post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser)) + + ), + React.createElement(Col, {xs: 8}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) + ) + ) + + ) + ); + } +}); + +/* +
+ +
+
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/6963c41578eaddc39957b6cb561cf7b19a2dc5ce.js b/js/.module-cache/6963c41578eaddc39957b6cb561cf7b19a2dc5ce.js new file mode 100644 index 0000000..0ce178d --- /dev/null +++ b/js/.module-cache/6963c41578eaddc39957b6cb561cf7b19a2dc5ce.js @@ -0,0 +1,162 @@ + +var ReactBootstrap = require('react-bootstrap') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + + +var React = require('react'); + +var Postboard = require("./Postboard.js"); +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +var EventListenerMixin = require('./EventListenerMixin.js') + +module.exports = Timeline = React.createClass({displayName: "Timeline", + + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin,EventListenerMixin('scrolledtobottom')], + contextTypes: { + router: React.PropTypes.func + }, + verifyPost: function (post) { + + var verified = false; + + for (var i = 0; i + + +
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/7b03360003ecd9b3f73a35665504c5c526098e44.js b/js/.module-cache/7b03360003ecd9b3f73a35665504c5c526098e44.js new file mode 100644 index 0000000..090c83f --- /dev/null +++ b/js/.module-cache/7b03360003ecd9b3f73a35665504c5c526098e44.js @@ -0,0 +1,162 @@ + +var ReactBootstrap = require('react-bootstrap') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + + +var React = require('react'); + +var Postboard = require("./Postboard.js"); +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +var EventListenerMixin = require('./EventListenerMixin.js') + +module.exports = Timeline = React.createClass({displayName: "Timeline", + + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin,EventListenerMixin('scrolledtobottom')], + contextTypes: { + router: React.PropTypes.func + }, + verifyPost: function (post) { + + var verified = false; + + for (var i = 0; i b.timestamp) + return -1; + return 0; + } + + previousState.data.sort(compare); + + return {data: previousState.data, postIdentifiers: previousState.postIdentifiers }; + }); + + } else { + + + } + } +} \ No newline at end of file diff --git a/js/.module-cache/817d69cf89ab760cfd9dfbc25814ba6962145289.js b/js/.module-cache/817d69cf89ab760cfd9dfbc25814ba6962145289.js new file mode 100644 index 0000000..25cd7a8 --- /dev/null +++ b/js/.module-cache/817d69cf89ab760cfd9dfbc25814ba6962145289.js @@ -0,0 +1,101 @@ + +var ReactBootstrap = require('react-bootstrap') + , Grid = ReactBootstrap.Grid + , Col = ReactBootstrap.Col + , Row = ReactBootstrap.Row + , ListGroupItem = ReactBootstrap.ListGroupItem + +var React = require('react'); + +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +module.exports = Post = React.createClass({displayName: "Post", + mixins: [SetIntervalMixin,SafeStateChangeMixin], + getInitialState: function() { + return { + avatar: "img/genericPerson.png", + fullname: "", + retwistingUser: this.props.post.retwistingUser, + timeAgo: "" + }; + }, + updateTimeAgo: function() { + var secondsAgo = Date.now()/1000-this.props.post.timestamp; + + var newTimeAgo = ""; + + if (secondsAgo<45) {newTimeAgo="1m"} + else if (secondsAgo<45*60) {newTimeAgo=Math.round(secondsAgo/60)+"m"} + else if (secondsAgo<45*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"} + else if (secondsAgo<60*60*60*18) {newTimeAgo=Math.round(secondsAgo/60/60/60)+"d"} + + this.setStateSafe({timeAgo: newTimeAgo}); + + }, + componentDidMount: function () { + var thisComponent = this; + + //console.log(this.props.post.username+":post"+this.props.post.id); + Twister.getUser(this.props.post.username).doAvatar(function(avatar){ + thisComponent.setStateSafe({avatar: avatar.getUrl()}); + }); + Twister.getUser(this.props.post.username).doProfile(function(profile){ + thisComponent.setStateSafe({fullname: profile.getField("fullname")}); + }); + + if (this.props.post.isRetwist) { + + Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){ + thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")}); + }); + + } + + this.updateTimeAgo(); + + this.setInterval(this.updateTimeAgo,60000); + }, + render: function() { + var post = this.props.post; + return ( + React.createElement(ListGroupItem, {fill: true}, + React.createElement(Grid, {fill: true}, + React.createElement(Row, null, + React.createElement(Col, {xs: 2, className: "fullytight"}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), + React.createElement(Col, {xs: 9}, + React.createElement("strong", null, this.state.fullname), " ", + post.content + ), + React.createElement(Col, {xs: 1, className: "fullytight"}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) + ), + React.createElement(Row, null, + React.createElement(Col, {xs: 4}, + post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser)) + + ), + React.createElement(Col, {xs: 8}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) + ) + ) + + ) + ); + } +}); + +/* +
+ +
+
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/83a76356a36e400cc41c7877268fef1c940f2214.js b/js/.module-cache/83a76356a36e400cc41c7877268fef1c940f2214.js new file mode 100644 index 0000000..71d7b35 --- /dev/null +++ b/js/.module-cache/83a76356a36e400cc41c7877268fef1c940f2214.js @@ -0,0 +1,101 @@ + +var ReactBootstrap = require('react-bootstrap') + , Grid = ReactBootstrap.Grid + , Col = ReactBootstrap.Col + , Row = ReactBootstrap.Row + , ListGroupItem = ReactBootstrap.ListGroupItem + +var React = require('react'); + +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +module.exports = Post = React.createClass({displayName: "Post", + mixins: [SetIntervalMixin,SafeStateChangeMixin], + getInitialState: function() { + return { + avatar: "img/genericPerson.png", + fullname: "", + retwistingUser: this.props.post.retwistingUser, + timeAgo: "" + }; + }, + updateTimeAgo: function() { + var secondsAgo = Date.now()/1000-this.props.post.timestamp; + + var newTimeAgo = ""; + + if (secondsAgo<45) {newTimeAgo="1m"} + else if (secondsAgo<45*60) {newTimeAgo=Math.round(secondsAgo/60)+"m"} + else if (secondsAgo<45*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"} + else if (secondsAgo<60*60*60*18) {newTimeAgo=Math.round(secondsAgo/60/60/60)+"d"} + + this.setStateSafe({timeAgo: newTimeAgo}); + + }, + componentDidMount: function () { + var thisComponent = this; + + //console.log(this.props.post.username+":post"+this.props.post.id); + Twister.getUser(this.props.post.username).doAvatar(function(avatar){ + thisComponent.setStateSafe({avatar: avatar.getUrl()}); + }); + Twister.getUser(this.props.post.username).doProfile(function(profile){ + thisComponent.setStateSafe({fullname: profile.getField("fullname")}); + }); + + if (this.props.post.isRetwist) { + + Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){ + thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")}); + }); + + } + + this.updateTimeAgo(); + + this.setInterval(this.updateTimeAgo,60000); + }, + render: function() { + var post = this.props.post; + return ( + React.createElement(ListGroupItem, {fill: true}, + React.createElement(Grid, {fill: true}, + React.createElement(Row, null, + React.createElement(Col, {xs: 2, className: "nopadding"}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), + React.createElement(Col, {xs: 9}, + React.createElement("strong", null, this.state.fullname), " ", + post.content + ), + React.createElement(Col, {xs: 1}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) + ), + React.createElement(Row, null, + React.createElement(Col, {xs: 4}, + post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser)) + + ), + React.createElement(Col, {xs: 8}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) + ) + ) + + ) + ); + } +}); + +/* +
+ +
+
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/95bd287b14edcd74662d28b1aaf141b7e86eb5a4.js b/js/.module-cache/95bd287b14edcd74662d28b1aaf141b7e86eb5a4.js new file mode 100644 index 0000000..6b0a099 --- /dev/null +++ b/js/.module-cache/95bd287b14edcd74662d28b1aaf141b7e86eb5a4.js @@ -0,0 +1,101 @@ + +var ReactBootstrap = require('react-bootstrap') + , Grid = ReactBootstrap.Grid + , Col = ReactBootstrap.Col + , Row = ReactBootstrap.Row + , ListGroupItem = ReactBootstrap.ListGroupItem + +var React = require('react'); + +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +module.exports = Post = React.createClass({displayName: "Post", + mixins: [SetIntervalMixin,SafeStateChangeMixin], + getInitialState: function() { + return { + avatar: "img/genericPerson.png", + fullname: "", + retwistingUser: this.props.post.retwistingUser, + timeAgo: "" + }; + }, + updateTimeAgo: function() { + var secondsAgo = Date.now()/1000-this.props.post.timestamp; + + var newTimeAgo = ""; + + if (secondsAgo<45) {newTimeAgo="1m"} + else if (secondsAgo<45*60) {newTimeAgo=Math.round(secondsAgo/60)+"m"} + else if (secondsAgo<45*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"} + else if (secondsAgo<60*60*60*18) {newTimeAgo=Math.round(secondsAgo/60/60/60)+"d"} + + this.setStateSafe({timeAgo: newTimeAgo}); + + }, + componentDidMount: function () { + var thisComponent = this; + + //console.log(this.props.post.username+":post"+this.props.post.id); + Twister.getUser(this.props.post.username).doAvatar(function(avatar){ + thisComponent.setStateSafe({avatar: avatar.getUrl()}); + }); + Twister.getUser(this.props.post.username).doProfile(function(profile){ + thisComponent.setStateSafe({fullname: profile.getField("fullname")}); + }); + + if (this.props.post.isRetwist) { + + Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){ + thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")}); + }); + + } + + this.updateTimeAgo(); + + this.setInterval(this.updateTimeAgo,60000); + }, + render: function() { + var post = this.props.post; + return ( + React.createElement(ListGroupItem, {fill: true}, + React.createElement(Grid, {fill: true}, + React.createElement(Row, null, + React.createElement(Col, {xs: 2, nopadding: true}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), + React.createElement(Col, {xs: 9}, + React.createElement("strong", null, this.state.fullname), " ", + post.content + ), + React.createElement(Col, {xs: 1}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) + ), + React.createElement(Row, null, + React.createElement(Col, {xs: 4}, + post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser)) + + ), + React.createElement(Col, {xs: 8}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) + ) + ) + + ) + ); + } +}); + +/* +
+ +
+
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/99d6a84f3275b12417299ef742e2824d3ce6e610.js b/js/.module-cache/99d6a84f3275b12417299ef742e2824d3ce6e610.js new file mode 100644 index 0000000..ba6f769 --- /dev/null +++ b/js/.module-cache/99d6a84f3275b12417299ef742e2824d3ce6e610.js @@ -0,0 +1,102 @@ + + +/* +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') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + +var React = require('react'); +var Router = require('react-router'); +var { Route, DefaultRoute, RouteHandler, Link } = Router; + +var Timeline = require("./Timeline.js"); + +App = React.createClass({displayName: "App", + + 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; + var id = JSON.stringify(router.getCurrentParams()); + if (id) { key += id; } + return key; + } else {return "none"} + }, + + render: function() { + return ( + React.createElement("div", null, + React.createElement(Nav, {bsStyle: "pills"}, + React.createElement(NavItem, {href: "#timeline/tschaul"}, + "tschaul" + ), + React.createElement(NavItem, {href: "#timeline/timbuktu"}, + "timbuktu" + ), + React.createElement(NavItem, {href: "#timeline/pampalulu"}, + "pampalulu" + ) + ), + React.createElement(RouteHandler, {pollInterval: "60000", key: this.getHandlerKey()}) + ) + ); + } +}); + + +var routes = ( + React.createElement(Route, {handler: App, path: "/"}, + React.createElement(Route, {name: "timeline", path: "timeline/:timelineUser", handler: Timeline}) + ) +); + + +var intitializeApp = function(res){ + + Router.run(routes, function (Handler) { + React.render(React.createElement(Handler, null), document.getElementById('content')); + }); + +}; + +///////// LOAD TWISTER FROM CACHE AND INITIALIZE + + +Twister.init({ + host: 'http://user:pwd@localhost:28332', + errorfunc: function(error){console.log(this,error)} +}); + +loadCache(); + +setInterval(saveCache,300000); + +Twister.loadServerAccounts(intitializeApp); + +////// INIT EVENTLISTENERS ON WINDOW + +window.onscroll = function(ev) { + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + var event = new Event('scrolledtobottom'); + window.dispatchEvent(event); + } +}; \ No newline at end of file diff --git a/js/.module-cache/9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.js b/js/.module-cache/9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.js new file mode 100644 index 0000000..48ffe8a --- /dev/null +++ b/js/.module-cache/9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.js @@ -0,0 +1,12 @@ +module.exports = EventListenerMixin = function (eventtype) { + + return { + componentDidMount: function() { + window.addEventListener(eventtype, this["on"+eventtype]); + }, + componentWillUnmount: function() { + window.removeEventListener(eventtype, this["on"+eventtype]); + } + } + +} \ No newline at end of file diff --git a/js/.module-cache/a75daba84d9bb9b874cc39f466ceed477f12a293.js b/js/.module-cache/a75daba84d9bb9b874cc39f466ceed477f12a293.js new file mode 100644 index 0000000..6446867 --- /dev/null +++ b/js/.module-cache/a75daba84d9bb9b874cc39f466ceed477f12a293.js @@ -0,0 +1,101 @@ + + +/* +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') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + +var React = require('react'); +var Router = require('react-router'); +var { Route, DefaultRoute, RouteHandler, Link } = Router; + +var Timeline = require("./Timeline.js"); + +App = React.createClass({displayName: "App", + + 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; + var id = JSON.stringify(router.getCurrentParams()); + if (id) { key += id; } + return key; + } else {return "none"} + }, + + render: function() { + return ( + React.createElement("div", null, + React.createElement(Nav, {bsStyle: "pills"}, + React.createElement(NavItem, {href: "#timeline/tschaul"}, + "tschaul" + ), + React.createElement(NavItem, {href: "#timeline/timbuktu"}, + "timbuktu" + ), + React.createElement(NavItem, {href: "#timeline/pampalulu"}, + "pampalulu" + ) + ), + React.createElement(RouteHandler, {pollInterval: "60000", key: this.getHandlerKey()}) + ) + ); + } +}); + + +var routes = ( + React.createElement(Route, {handler: App, path: "/"}, + React.createElement(Route, {name: "timeline", path: "timeline/:timelineUser", handler: Timeline}) + ) +); + + +var intitializeApp = function(res){ + + Router.run(routes, function (Handler) { + React.render(React.createElement(Handler, null), document.getElementById('content')); + }); + +}; + +///////// LOAD TWISTER FROM CACHE AND INITIALIZE + + +Twister.init({ + host: 'http://user:pwd@localhost:28332', + errorfunc: function(error){console.log(this,error)} +}); + +loadCache(); + +setInterval(saveCache,300000); + +Twister.loadServerAccounts(intitializeApp); + +////// INIT EVENTLISTENERS ON WINDOW + +window.onscroll = function(ev) { + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + alert("you're at the bottom of the page"); + } +}; \ No newline at end of file diff --git a/js/.module-cache/a96e5b381fdf9155de48fe91471ffc18f049dae0.js b/js/.module-cache/a96e5b381fdf9155de48fe91471ffc18f049dae0.js new file mode 100644 index 0000000..bfcfc11 --- /dev/null +++ b/js/.module-cache/a96e5b381fdf9155de48fe91471ffc18f049dae0.js @@ -0,0 +1,160 @@ + +var ReactBootstrap = require('react-bootstrap') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + + +var React = require('react'); + +var Postboard = require("./Postboard.js"); +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +module.exports = Timeline = React.createClass({displayName: "Timeline", + + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin], + contextTypes: { + router: React.PropTypes.func + }, + verifyPost: function (post) { + + var verified = false; + + for (var i = 0; i + + +
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.js b/js/.module-cache/f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.js new file mode 100644 index 0000000..08a7e8c --- /dev/null +++ b/js/.module-cache/f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.js @@ -0,0 +1,172 @@ + +var ReactBootstrap = require('react-bootstrap') + , NavItem = ReactBootstrap.NavItem + , Nav = ReactBootstrap.Nav + , ListGroup = ReactBootstrap.ListGroup + , Panel = ReactBootstrap.Panel + + +var React = require('react'); + +var Postboard = require("./Postboard.js"); +var SetIntervalMixin = require("./SetIntervalMixin.js"); +var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +var EventListenerMixin = require('./EventListenerMixin.js') + +module.exports = Timeline = React.createClass({displayName: "Timeline", + + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin,EventListenerMixin('scrolledtobottom')], + contextTypes: { + router: React.PropTypes.func + }, + verifyPost: function (post) { + + var verified = false; + + for (var i = 0; i + + +
+
+ {this.state.fullname} + @{post.username} - {post.id} + +
+
{post.timestamp}
+
{post.content}
+
+
+ + */ \ No newline at end of file diff --git a/js/.module-cache/manifest/08c714844c29536ebc79f9d30805d704b52fd613.json b/js/.module-cache/manifest/08c714844c29536ebc79f9d30805d704b52fd613.json new file mode 100644 index 0000000..75e9f90 --- /dev/null +++ b/js/.module-cache/manifest/08c714844c29536ebc79f9d30805d704b52fd613.json @@ -0,0 +1 @@ +{".js":"08c714844c29536ebc79f9d30805d704b52fd613.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.json b/js/.module-cache/manifest/1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.json new file mode 100644 index 0000000..6a5a234 --- /dev/null +++ b/js/.module-cache/manifest/1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.json @@ -0,0 +1 @@ +{".js":"1790c1dcc8106c5ece39d81ebfaa7b9ffa396496.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.json b/js/.module-cache/manifest/1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.json new file mode 100644 index 0000000..bbbb89b --- /dev/null +++ b/js/.module-cache/manifest/1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.json @@ -0,0 +1 @@ +{".js":"1dc4fe12ecab4f1f54667b86d2cfa2071aa1e5bc.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/37e111cc9b81f1cdb7a5eaa6ce00f435348bd48a.json b/js/.module-cache/manifest/37e111cc9b81f1cdb7a5eaa6ce00f435348bd48a.json new file mode 100644 index 0000000..78b4cf2 --- /dev/null +++ b/js/.module-cache/manifest/37e111cc9b81f1cdb7a5eaa6ce00f435348bd48a.json @@ -0,0 +1 @@ +{".js":"37e111cc9b81f1cdb7a5eaa6ce00f435348bd48a.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/3c5a8a3726ee4db1fc5375c1f0b9ff889948e240.json b/js/.module-cache/manifest/3c5a8a3726ee4db1fc5375c1f0b9ff889948e240.json new file mode 100644 index 0000000..4240642 --- /dev/null +++ b/js/.module-cache/manifest/3c5a8a3726ee4db1fc5375c1f0b9ff889948e240.json @@ -0,0 +1 @@ +{".js":"3c5a8a3726ee4db1fc5375c1f0b9ff889948e240.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.json b/js/.module-cache/manifest/3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.json new file mode 100644 index 0000000..d64d2b1 --- /dev/null +++ b/js/.module-cache/manifest/3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.json @@ -0,0 +1 @@ +{".js":"3cb5ee718a67a61dc4cbdfb8e03165b978a0e71a.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.json b/js/.module-cache/manifest/5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.json new file mode 100644 index 0000000..d4c363c --- /dev/null +++ b/js/.module-cache/manifest/5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.json @@ -0,0 +1 @@ +{".js":"5d1f97ef0ac61cdf58e8fa2bb34cc7fadc08f04c.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/5f1e941d8495d0f750d535161ad70ea16a9e4746.json b/js/.module-cache/manifest/5f1e941d8495d0f750d535161ad70ea16a9e4746.json new file mode 100644 index 0000000..9c41213 --- /dev/null +++ b/js/.module-cache/manifest/5f1e941d8495d0f750d535161ad70ea16a9e4746.json @@ -0,0 +1 @@ +{".js":"5f1e941d8495d0f750d535161ad70ea16a9e4746.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/62b320e94d738a654a51f0072466d00e804e745d.json b/js/.module-cache/manifest/62b320e94d738a654a51f0072466d00e804e745d.json new file mode 100644 index 0000000..3ffa706 --- /dev/null +++ b/js/.module-cache/manifest/62b320e94d738a654a51f0072466d00e804e745d.json @@ -0,0 +1 @@ +{".js":"62b320e94d738a654a51f0072466d00e804e745d.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/6963c41578eaddc39957b6cb561cf7b19a2dc5ce.json b/js/.module-cache/manifest/6963c41578eaddc39957b6cb561cf7b19a2dc5ce.json new file mode 100644 index 0000000..6527807 --- /dev/null +++ b/js/.module-cache/manifest/6963c41578eaddc39957b6cb561cf7b19a2dc5ce.json @@ -0,0 +1 @@ +{".js":"6963c41578eaddc39957b6cb561cf7b19a2dc5ce.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/6bdf1b84f178854813606fd7d13938769358b0aa.json b/js/.module-cache/manifest/6bdf1b84f178854813606fd7d13938769358b0aa.json new file mode 100644 index 0000000..674d197 --- /dev/null +++ b/js/.module-cache/manifest/6bdf1b84f178854813606fd7d13938769358b0aa.json @@ -0,0 +1 @@ +{".js":"6bdf1b84f178854813606fd7d13938769358b0aa.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/7b03360003ecd9b3f73a35665504c5c526098e44.json b/js/.module-cache/manifest/7b03360003ecd9b3f73a35665504c5c526098e44.json new file mode 100644 index 0000000..da7a8ba --- /dev/null +++ b/js/.module-cache/manifest/7b03360003ecd9b3f73a35665504c5c526098e44.json @@ -0,0 +1 @@ +{".js":"7b03360003ecd9b3f73a35665504c5c526098e44.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/80a01a350ccea8f837824abb8a78698c5971130d.json b/js/.module-cache/manifest/80a01a350ccea8f837824abb8a78698c5971130d.json new file mode 100644 index 0000000..1bf38a8 --- /dev/null +++ b/js/.module-cache/manifest/80a01a350ccea8f837824abb8a78698c5971130d.json @@ -0,0 +1 @@ +{".js":"80a01a350ccea8f837824abb8a78698c5971130d.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/817d69cf89ab760cfd9dfbc25814ba6962145289.json b/js/.module-cache/manifest/817d69cf89ab760cfd9dfbc25814ba6962145289.json new file mode 100644 index 0000000..dcaa5a6 --- /dev/null +++ b/js/.module-cache/manifest/817d69cf89ab760cfd9dfbc25814ba6962145289.json @@ -0,0 +1 @@ +{".js":"817d69cf89ab760cfd9dfbc25814ba6962145289.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/83a76356a36e400cc41c7877268fef1c940f2214.json b/js/.module-cache/manifest/83a76356a36e400cc41c7877268fef1c940f2214.json new file mode 100644 index 0000000..4aeb77b --- /dev/null +++ b/js/.module-cache/manifest/83a76356a36e400cc41c7877268fef1c940f2214.json @@ -0,0 +1 @@ +{".js":"83a76356a36e400cc41c7877268fef1c940f2214.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/95bd287b14edcd74662d28b1aaf141b7e86eb5a4.json b/js/.module-cache/manifest/95bd287b14edcd74662d28b1aaf141b7e86eb5a4.json new file mode 100644 index 0000000..6347c57 --- /dev/null +++ b/js/.module-cache/manifest/95bd287b14edcd74662d28b1aaf141b7e86eb5a4.json @@ -0,0 +1 @@ +{".js":"95bd287b14edcd74662d28b1aaf141b7e86eb5a4.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/99d6a84f3275b12417299ef742e2824d3ce6e610.json b/js/.module-cache/manifest/99d6a84f3275b12417299ef742e2824d3ce6e610.json new file mode 100644 index 0000000..e40c74f --- /dev/null +++ b/js/.module-cache/manifest/99d6a84f3275b12417299ef742e2824d3ce6e610.json @@ -0,0 +1 @@ +{".js":"99d6a84f3275b12417299ef742e2824d3ce6e610.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.json b/js/.module-cache/manifest/9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.json new file mode 100644 index 0000000..9777d15 --- /dev/null +++ b/js/.module-cache/manifest/9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.json @@ -0,0 +1 @@ +{".js":"9a94dd6850590563ad4a1c5bfe8d9538c625f7cc.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/a75daba84d9bb9b874cc39f466ceed477f12a293.json b/js/.module-cache/manifest/a75daba84d9bb9b874cc39f466ceed477f12a293.json new file mode 100644 index 0000000..53110ee --- /dev/null +++ b/js/.module-cache/manifest/a75daba84d9bb9b874cc39f466ceed477f12a293.json @@ -0,0 +1 @@ +{".js":"a75daba84d9bb9b874cc39f466ceed477f12a293.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/a96e5b381fdf9155de48fe91471ffc18f049dae0.json b/js/.module-cache/manifest/a96e5b381fdf9155de48fe91471ffc18f049dae0.json new file mode 100644 index 0000000..0a00451 --- /dev/null +++ b/js/.module-cache/manifest/a96e5b381fdf9155de48fe91471ffc18f049dae0.json @@ -0,0 +1 @@ +{".js":"a96e5b381fdf9155de48fe91471ffc18f049dae0.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/b44a64a27d99a484a4cf8e757c2d902e147932fa.json b/js/.module-cache/manifest/b44a64a27d99a484a4cf8e757c2d902e147932fa.json new file mode 100644 index 0000000..118942e --- /dev/null +++ b/js/.module-cache/manifest/b44a64a27d99a484a4cf8e757c2d902e147932fa.json @@ -0,0 +1 @@ +{".js":"b44a64a27d99a484a4cf8e757c2d902e147932fa.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/bb2cde08d4b5a26c66a5c56c75e288b0d0476c48.json b/js/.module-cache/manifest/bb2cde08d4b5a26c66a5c56c75e288b0d0476c48.json new file mode 100644 index 0000000..f47a18f --- /dev/null +++ b/js/.module-cache/manifest/bb2cde08d4b5a26c66a5c56c75e288b0d0476c48.json @@ -0,0 +1 @@ +{".js":"bb2cde08d4b5a26c66a5c56c75e288b0d0476c48.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/c57d14fa426b54106d5bc5cc344fa166bfb8f51b.json b/js/.module-cache/manifest/c57d14fa426b54106d5bc5cc344fa166bfb8f51b.json new file mode 100644 index 0000000..37e46e6 --- /dev/null +++ b/js/.module-cache/manifest/c57d14fa426b54106d5bc5cc344fa166bfb8f51b.json @@ -0,0 +1 @@ +{".js":"c57d14fa426b54106d5bc5cc344fa166bfb8f51b.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/c7f08b920603d73fac97d6007dbf6b5bc7f57ba5.json b/js/.module-cache/manifest/c7f08b920603d73fac97d6007dbf6b5bc7f57ba5.json new file mode 100644 index 0000000..9b9fa72 --- /dev/null +++ b/js/.module-cache/manifest/c7f08b920603d73fac97d6007dbf6b5bc7f57ba5.json @@ -0,0 +1 @@ +{".js":"c7f08b920603d73fac97d6007dbf6b5bc7f57ba5.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/d71ed2a487872dd50be6d967cedeff0a6b5767b9.json b/js/.module-cache/manifest/d71ed2a487872dd50be6d967cedeff0a6b5767b9.json new file mode 100644 index 0000000..3e7c50b --- /dev/null +++ b/js/.module-cache/manifest/d71ed2a487872dd50be6d967cedeff0a6b5767b9.json @@ -0,0 +1 @@ +{".js":"d71ed2a487872dd50be6d967cedeff0a6b5767b9.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.json b/js/.module-cache/manifest/f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.json new file mode 100644 index 0000000..ec45ed2 --- /dev/null +++ b/js/.module-cache/manifest/f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.json @@ -0,0 +1 @@ +{".js":"f4da31f5826a7a96ab3cc20d1d12e0b754e4085a.js"} \ No newline at end of file diff --git a/js/.module-cache/manifest/f837fa85d2697fe09e9b8a879a4ced37d7c6d3c0.json b/js/.module-cache/manifest/f837fa85d2697fe09e9b8a879a4ced37d7c6d3c0.json new file mode 100644 index 0000000..419be15 --- /dev/null +++ b/js/.module-cache/manifest/f837fa85d2697fe09e9b8a879a4ced37d7c6d3c0.json @@ -0,0 +1 @@ +{".js":"f837fa85d2697fe09e9b8a879a4ced37d7c6d3c0.js"} \ No newline at end of file diff --git a/js/App.js b/js/App.js index 0139d8b..03d393e 100644 --- a/js/App.js +++ b/js/App.js @@ -56,7 +56,7 @@ App = React.createClass({displayName: "App", "pampalulu" ) ), - React.createElement(RouteHandler, {pollInterval: "60000", key: this.getHandlerKey()}) + React.createElement(RouteHandler, {pollInterval: "60", key: this.getHandlerKey()}) ) ); } @@ -90,4 +90,13 @@ loadCache(); setInterval(saveCache,300000); -Twister.loadServerAccounts(intitializeApp); \ No newline at end of file +Twister.loadServerAccounts(intitializeApp); + +////// INIT EVENTLISTENERS ON WINDOW + +window.onscroll = function(ev) { + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + var event = new Event('scrolledtobottom'); + window.dispatchEvent(event); + } +}; \ No newline at end of file diff --git a/js/EventListenerMixin.js b/js/EventListenerMixin.js new file mode 100644 index 0000000..48ffe8a --- /dev/null +++ b/js/EventListenerMixin.js @@ -0,0 +1,12 @@ +module.exports = EventListenerMixin = function (eventtype) { + + return { + componentDidMount: function() { + window.addEventListener(eventtype, this["on"+eventtype]); + }, + componentWillUnmount: function() { + window.removeEventListener(eventtype, this["on"+eventtype]); + } + } + +} \ No newline at end of file diff --git a/js/Post.js b/js/Post.js index c089445..66b295c 100644 --- a/js/Post.js +++ b/js/Post.js @@ -8,9 +8,10 @@ var ReactBootstrap = require('react-bootstrap') var React = require('react'); var SetIntervalMixin = require("./SetIntervalMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); module.exports = Post = React.createClass({displayName: "Post", - mixins: [SetIntervalMixin], + mixins: [SetIntervalMixin,SafeStateChangeMixin], getInitialState: function() { return { avatar: "img/genericPerson.png", @@ -29,7 +30,7 @@ module.exports = Post = React.createClass({displayName: "Post", else if (secondsAgo<45*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"} else if (secondsAgo<60*60*60*18) {newTimeAgo=Math.round(secondsAgo/60/60/60)+"d"} - this.setState({timeAgo: newTimeAgo}); + this.setStateSafe({timeAgo: newTimeAgo}); }, componentDidMount: function () { @@ -37,16 +38,16 @@ module.exports = Post = React.createClass({displayName: "Post", //console.log(this.props.post.username+":post"+this.props.post.id); Twister.getUser(this.props.post.username).doAvatar(function(avatar){ - thisComponent.setState({avatar: avatar.getUrl()}); + thisComponent.setStateSafe({avatar: avatar.getUrl()}); }); Twister.getUser(this.props.post.username).doProfile(function(profile){ - thisComponent.setState({fullname: profile.getField("fullname")}); + thisComponent.setStateSafe({fullname: profile.getField("fullname")}); }); if (this.props.post.isRetwist) { Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){ - thisComponent.setState({retwistingUser: profile.getField("fullname")}); + thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")}); }); } @@ -58,22 +59,22 @@ module.exports = Post = React.createClass({displayName: "Post", render: function() { var post = this.props.post; return ( - React.createElement(ListGroupItem, null, + React.createElement(ListGroupItem, {fill: true}, React.createElement(Grid, {fill: true}, React.createElement(Row, null, - React.createElement(Col, {xs: 2}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), + React.createElement(Col, {xs: 2, className: "fullytight"}, React.createElement("img", {className: "img-responsive", src: this.state.avatar})), React.createElement(Col, {xs: 9}, React.createElement("strong", null, this.state.fullname), " ", post.content ), - React.createElement(Col, {xs: 1}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) + React.createElement(Col, {xs: 1, className: "fullytight"}, React.createElement("p", {className: "text-right"}, this.state.timeAgo)) ), React.createElement(Row, null, - React.createElement(Col, {xs: 4}, + React.createElement(Col, {xs: 6}, post.isRetwist && React.createElement("small", null, React.createElement("span", {className: "glyphicon glyphicon-retweet", "aria-hidden": "true"}), " ", React.createElement("em", null, "  retwisted by ", this.state.retwistingUser)) ), - React.createElement(Col, {xs: 8}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) + React.createElement(Col, {xs: 6}, React.createElement("p", {className: "text-right"}, React.createElement("small", null, React.createElement("em", null, "test")))) ) ) diff --git a/js/SafeStateChangeMixin.js b/js/SafeStateChangeMixin.js new file mode 100644 index 0000000..2dddc93 --- /dev/null +++ b/js/SafeStateChangeMixin.js @@ -0,0 +1,62 @@ +function isValidLifeCycleForReplaceState(instance) { + // See function validateLifeCycleOnReplaceState(instance) in + // ReactCompositeComponent.js + var result = true; + + //result &= ReactCurrentOwner.current == null; + //result &= __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || __REACT_DEVTOOLS_GLOBAL_HOOK__._reactRuntime.CurrentOwner.current == null; + + result &= instance.isMounted(); + + return result; +} + +var safeStateChangeMixin = { + /** + * Calls setState with the provided parameters if it is safe to do so. + * + * Safe means it will try to do the same checks as setState does + * without throwing an exception. + * See function validateLifeCycleOnReplaceState(instance) in + * ReactCompositeComponent.js + * + * @param {object} partialState Next partial state to be merged with state. + * @param {?function} callback Called after state is updated. + * @return {boolean} Whether or not setState is called. + * @final + * @protected + */ + setStateSafe: function (partialState, callback) { + if (isValidLifeCycleForReplaceState(this)) { + this.setState(partialState, callback); + return true; + } + + return false; + }, + + /** + * Calls replaceState with the provided parameters if it safe to do so. + * + * Safe means it will try to do the same checks as replaceState does + * without throwing an exception. + * See function validateLifeCycleOnReplaceState(instance) in + * ReactCompositeComponent.js + * + * @param {object} completeState Next state. + * @param {?function} callback Called after state is updated. + * @return {boolean} Whether or not setState is called. + * @final + * @protected + */ + replaceStateSafe: function(completeState, callback) { + if (isValidLifeCycleForReplaceState(this)) { + this.replaceState(completeState, callback); + return true; + } + + return false; + } +}; + +module.exports = safeStateChangeMixin; \ No newline at end of file diff --git a/js/StreamMixin.js b/js/StreamMixin.js index aa6da63..502958f 100644 --- a/js/StreamMixin.js +++ b/js/StreamMixin.js @@ -6,7 +6,7 @@ module.exports = StreamMixin = { if (!this.state.postIdentifiers[postid] && this.verifyPost(post)) { - this.setState(function(previousState, currentProps) { + this.setStateSafe(function(previousState, currentProps) { previousState.postIdentifiers[postid] = true; diff --git a/js/Timeline.js b/js/Timeline.js index 13e6b1b..af3e075 100644 --- a/js/Timeline.js +++ b/js/Timeline.js @@ -11,10 +11,13 @@ var React = require('react'); var Postboard = require("./Postboard.js"); var SetIntervalMixin = require("./SetIntervalMixin.js"); var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +var EventListenerMixin = require('./EventListenerMixin.js') module.exports = Timeline = React.createClass({displayName: "Timeline", - mixins: [StreamMixin,SetIntervalMixin], + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin,EventListenerMixin('scrolledtobottom')], contextTypes: { router: React.PropTypes.func }, @@ -37,7 +40,7 @@ module.exports = Timeline = React.createClass({displayName: "Timeline", postIdentifiers: {}, usernames: [], timelineUser: [], - postrange: ( Date.now()/1000 - 24*60*60 ), + postrange: ( Date.now()/1000 - 12*60*60 ), min_posts: 30 }; }, @@ -46,7 +49,7 @@ module.exports = Timeline = React.createClass({displayName: "Timeline", var thisComponent = this; - this.setState(function(previousState, currentProps){ + this.setStateSafe(function(previousState, currentProps){ previousState.usernames.push(username); @@ -67,7 +70,7 @@ module.exports = Timeline = React.createClass({displayName: "Timeline", }, removeUser: function(username) { - this.setState(function(previousState, currentProps){ + this.setStateSafe(function(previousState, currentProps){ var newusers = []; @@ -97,7 +100,7 @@ module.exports = Timeline = React.createClass({displayName: "Timeline", }, updatePosts: function(outdatedLimit) { - if (!outdatedLimit) {outdatedLimit=30;} + if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;} for (var i = 0; i - + ); } @@ -90,4 +90,13 @@ loadCache(); setInterval(saveCache,300000); -Twister.loadServerAccounts(intitializeApp); \ No newline at end of file +Twister.loadServerAccounts(intitializeApp); + +////// INIT EVENTLISTENERS ON WINDOW + +window.onscroll = function(ev) { + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + var event = new Event('scrolledtobottom'); + window.dispatchEvent(event); + } +}; \ No newline at end of file diff --git a/jsx/EventListenerMixin.js b/jsx/EventListenerMixin.js new file mode 100644 index 0000000..48ffe8a --- /dev/null +++ b/jsx/EventListenerMixin.js @@ -0,0 +1,12 @@ +module.exports = EventListenerMixin = function (eventtype) { + + return { + componentDidMount: function() { + window.addEventListener(eventtype, this["on"+eventtype]); + }, + componentWillUnmount: function() { + window.removeEventListener(eventtype, this["on"+eventtype]); + } + } + +} \ No newline at end of file diff --git a/jsx/Post.js b/jsx/Post.js index f57e389..c548c3e 100644 --- a/jsx/Post.js +++ b/jsx/Post.js @@ -8,9 +8,10 @@ var ReactBootstrap = require('react-bootstrap') var React = require('react'); var SetIntervalMixin = require("./SetIntervalMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); module.exports = Post = React.createClass({ - mixins: [SetIntervalMixin], + mixins: [SetIntervalMixin,SafeStateChangeMixin], getInitialState: function() { return { avatar: "img/genericPerson.png", @@ -29,7 +30,7 @@ module.exports = Post = React.createClass({ else if (secondsAgo<45*60*60) {newTimeAgo=Math.round(secondsAgo/60/60)+"h"} else if (secondsAgo<60*60*60*18) {newTimeAgo=Math.round(secondsAgo/60/60/60)+"d"} - this.setState({timeAgo: newTimeAgo}); + this.setStateSafe({timeAgo: newTimeAgo}); }, componentDidMount: function () { @@ -37,16 +38,16 @@ module.exports = Post = React.createClass({ //console.log(this.props.post.username+":post"+this.props.post.id); Twister.getUser(this.props.post.username).doAvatar(function(avatar){ - thisComponent.setState({avatar: avatar.getUrl()}); + thisComponent.setStateSafe({avatar: avatar.getUrl()}); }); Twister.getUser(this.props.post.username).doProfile(function(profile){ - thisComponent.setState({fullname: profile.getField("fullname")}); + thisComponent.setStateSafe({fullname: profile.getField("fullname")}); }); if (this.props.post.isRetwist) { Twister.getUser(this.props.post.retwistingUser).doProfile(function(profile){ - thisComponent.setState({retwistingUser: profile.getField("fullname")}); + thisComponent.setStateSafe({retwistingUser: profile.getField("fullname")}); }); } @@ -58,22 +59,22 @@ module.exports = Post = React.createClass({ render: function() { var post = this.props.post; return ( - + - + {this.state.fullname}  {post.content} -

{this.state.timeAgo}

+

{this.state.timeAgo}

- + {post.isRetwist &&  retwisted by {this.state.retwistingUser} } -

test

+

test

diff --git a/jsx/SafeStateChangeMixin.js b/jsx/SafeStateChangeMixin.js new file mode 100644 index 0000000..2dddc93 --- /dev/null +++ b/jsx/SafeStateChangeMixin.js @@ -0,0 +1,62 @@ +function isValidLifeCycleForReplaceState(instance) { + // See function validateLifeCycleOnReplaceState(instance) in + // ReactCompositeComponent.js + var result = true; + + //result &= ReactCurrentOwner.current == null; + //result &= __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || __REACT_DEVTOOLS_GLOBAL_HOOK__._reactRuntime.CurrentOwner.current == null; + + result &= instance.isMounted(); + + return result; +} + +var safeStateChangeMixin = { + /** + * Calls setState with the provided parameters if it is safe to do so. + * + * Safe means it will try to do the same checks as setState does + * without throwing an exception. + * See function validateLifeCycleOnReplaceState(instance) in + * ReactCompositeComponent.js + * + * @param {object} partialState Next partial state to be merged with state. + * @param {?function} callback Called after state is updated. + * @return {boolean} Whether or not setState is called. + * @final + * @protected + */ + setStateSafe: function (partialState, callback) { + if (isValidLifeCycleForReplaceState(this)) { + this.setState(partialState, callback); + return true; + } + + return false; + }, + + /** + * Calls replaceState with the provided parameters if it safe to do so. + * + * Safe means it will try to do the same checks as replaceState does + * without throwing an exception. + * See function validateLifeCycleOnReplaceState(instance) in + * ReactCompositeComponent.js + * + * @param {object} completeState Next state. + * @param {?function} callback Called after state is updated. + * @return {boolean} Whether or not setState is called. + * @final + * @protected + */ + replaceStateSafe: function(completeState, callback) { + if (isValidLifeCycleForReplaceState(this)) { + this.replaceState(completeState, callback); + return true; + } + + return false; + } +}; + +module.exports = safeStateChangeMixin; \ No newline at end of file diff --git a/jsx/StreamMixin.js b/jsx/StreamMixin.js index aa6da63..502958f 100644 --- a/jsx/StreamMixin.js +++ b/jsx/StreamMixin.js @@ -6,7 +6,7 @@ module.exports = StreamMixin = { if (!this.state.postIdentifiers[postid] && this.verifyPost(post)) { - this.setState(function(previousState, currentProps) { + this.setStateSafe(function(previousState, currentProps) { previousState.postIdentifiers[postid] = true; diff --git a/jsx/Timeline.js b/jsx/Timeline.js index 859d281..4aebda3 100644 --- a/jsx/Timeline.js +++ b/jsx/Timeline.js @@ -11,10 +11,13 @@ var React = require('react'); var Postboard = require("./Postboard.js"); var SetIntervalMixin = require("./SetIntervalMixin.js"); var StreamMixin = require("./StreamMixin.js"); +var SafeStateChangeMixin = require('./SafeStateChangeMixin.js'); + +var EventListenerMixin = require('./EventListenerMixin.js') module.exports = Timeline = React.createClass({ - mixins: [StreamMixin,SetIntervalMixin], + mixins: [StreamMixin,SetIntervalMixin,SafeStateChangeMixin,EventListenerMixin('scrolledtobottom')], contextTypes: { router: React.PropTypes.func }, @@ -37,7 +40,7 @@ module.exports = Timeline = React.createClass({ postIdentifiers: {}, usernames: [], timelineUser: [], - postrange: ( Date.now()/1000 - 24*60*60 ), + postrange: ( Date.now()/1000 - 12*60*60 ), min_posts: 30 }; }, @@ -46,7 +49,7 @@ module.exports = Timeline = React.createClass({ var thisComponent = this; - this.setState(function(previousState, currentProps){ + this.setStateSafe(function(previousState, currentProps){ previousState.usernames.push(username); @@ -67,7 +70,7 @@ module.exports = Timeline = React.createClass({ }, removeUser: function(username) { - this.setState(function(previousState, currentProps){ + this.setStateSafe(function(previousState, currentProps){ var newusers = []; @@ -97,7 +100,7 @@ module.exports = Timeline = React.createClass({ }, updatePosts: function(outdatedLimit) { - if (!outdatedLimit) {outdatedLimit=30;} + if (!outdatedLimit) {outdatedLimit=this.props.pollInterval/2;} for (var i = 0; i