mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-21 13:51:50 +03:00
Infinite scrolling works, localStorage works, progressive loading of information works, new subscription pattern works
This commit is contained in:
parent
2a2221f03a
commit
bc4f1968f2
@ -51,6 +51,15 @@ class UrbitApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notify(aud, bool) {
|
||||||
|
this.hall({
|
||||||
|
notify: {
|
||||||
|
aud,
|
||||||
|
pes: !!bool ? 'hear' : 'gone'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
permit(cir, aud, message) {
|
permit(cir, aud, message) {
|
||||||
this.hall({
|
this.hall({
|
||||||
permit: {
|
permit: {
|
||||||
|
@ -16,14 +16,47 @@ export class ChatScreen extends Component {
|
|||||||
station: props.match.params.ship + "/" + props.match.params.station,
|
station: props.match.params.ship + "/" + props.match.params.station,
|
||||||
circle: props.match.params.station,
|
circle: props.match.params.station,
|
||||||
host: props.match.params.ship,
|
host: props.match.params.ship,
|
||||||
numPeople: 0
|
numPeople: 0,
|
||||||
|
numPages: 1,
|
||||||
|
scrollLocked: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.topMessage = {};
|
||||||
this.buildMessage = this.buildMessage.bind(this);
|
this.buildMessage = this.buildMessage.bind(this);
|
||||||
|
this.onScroll = this.onScroll.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.updateNumPeople();
|
this.updateNumPeople();
|
||||||
|
this.scrollElement.scrollIntoView(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToBottom() {
|
||||||
|
if (!this.state.scrollLocked) {
|
||||||
|
console.log('scroll to bottom');
|
||||||
|
this.scrollElement.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onScroll(e) {
|
||||||
|
if (e.target.scrollTop === 0) {
|
||||||
|
let topMessage = this.topMessage;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
numPages: this.state.numPages + 1,
|
||||||
|
scrollLocked: true
|
||||||
|
}, () => {
|
||||||
|
this.topMessage[1].scrollIntoView(true);
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
(e.target.scrollHeight - Math.round(e.target.scrollTop)) ===
|
||||||
|
e.target.clientHeight
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
numPages: 1,
|
||||||
|
scrollLocked: false
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
@ -41,6 +74,7 @@ export class ChatScreen extends Component {
|
|||||||
this.updateReadNumber();
|
this.updateReadNumber();
|
||||||
this.updateNumPeople();
|
this.updateNumPeople();
|
||||||
this.updateNumMessagesLoaded(prevProps, prevState);
|
this.updateNumMessagesLoaded(prevProps, prevState);
|
||||||
|
this.scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateReadNumber() {
|
updateReadNumber() {
|
||||||
@ -77,7 +111,7 @@ export class ChatScreen extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildMessage(msg) {
|
buildMessage(msg, index) {
|
||||||
let details = msg.printship ? null : getMessageContent(msg.gam);
|
let details = msg.printship ? null : getMessageContent(msg.gam);
|
||||||
|
|
||||||
if (msg.printship) {
|
if (msg.printship) {
|
||||||
@ -89,13 +123,29 @@ export class ChatScreen extends Component {
|
|||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
|
||||||
<Message key={msg.gam.uid} msg={msg.gam} details={details} />
|
if (index % 50 === 0) {
|
||||||
);
|
let pageNum = index / 50;
|
||||||
|
return (
|
||||||
|
<div ref={ el => { this.topMessage[pageNum] = el; }}>
|
||||||
|
<Message
|
||||||
|
key={msg.gam.uid} msg={msg.gam} details={details} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Message key={msg.gam.uid} msg={msg.gam} details={details} />
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { props, state } = this;
|
||||||
let messages = this.props.messages[this.state.station] || [];
|
let messages = this.props.messages[this.state.station] || [];
|
||||||
|
if (messages.length > 50 * state.numPages) {
|
||||||
|
messages =
|
||||||
|
messages.slice(messages.length - (50 * state.numPages), messages.length);
|
||||||
|
}
|
||||||
let chatMessages = messages.map(this.buildMessage);
|
let chatMessages = messages.map(this.buildMessage);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -104,8 +154,12 @@ export class ChatScreen extends Component {
|
|||||||
<h2>{this.state.circle}</h2>
|
<h2>{this.state.circle}</h2>
|
||||||
<ChatTabBar {...this.props} station={this.state.station} />
|
<ChatTabBar {...this.props} station={this.state.station} />
|
||||||
</div>
|
</div>
|
||||||
<div className="overflow-y-scroll" style={{ flexGrow: 1 }}>
|
<div
|
||||||
|
className="overflow-y-scroll"
|
||||||
|
style={{ flexGrow: 1 }}
|
||||||
|
onScroll={this.onScroll}>
|
||||||
{chatMessages}
|
{chatMessages}
|
||||||
|
<div ref={ el => { this.scrollElement = el; }}></div>
|
||||||
</div>
|
</div>
|
||||||
<ChatInput
|
<ChatInput
|
||||||
api={this.props.api}
|
api={this.props.api}
|
||||||
|
@ -105,6 +105,42 @@ export class ChatInput extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
|
const { props, state } = this;
|
||||||
|
/*let closure = () => {
|
||||||
|
let aud, sep;
|
||||||
|
let wen = Date.now();
|
||||||
|
let uid = uuid();
|
||||||
|
let aut = window.ship;
|
||||||
|
|
||||||
|
let config = props.configs[state.station];
|
||||||
|
|
||||||
|
aud = [props.station];
|
||||||
|
sep = {
|
||||||
|
lin: {
|
||||||
|
msg: Date.now().toString(),
|
||||||
|
pat: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = {
|
||||||
|
uid,
|
||||||
|
aut,
|
||||||
|
wen,
|
||||||
|
aud,
|
||||||
|
sep,
|
||||||
|
};
|
||||||
|
|
||||||
|
props.api.hall({
|
||||||
|
convey: [message]
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(closure, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
closure();*/
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt2 pa3 cf flex black bt">
|
<div className="mt2 pa3 cf flex black bt">
|
||||||
<div className="fl" style={{ flexBasis: 35, height: 40 }}>
|
<div className="fl" style={{ flexBasis: 35, height: 40 }}>
|
||||||
@ -114,8 +150,8 @@ export class ChatInput extends Component {
|
|||||||
<input className="ml2 bn"
|
<input className="ml2 bn"
|
||||||
style={{ flexGrow: 1 }}
|
style={{ flexGrow: 1 }}
|
||||||
ref={this.textareaRef}
|
ref={this.textareaRef}
|
||||||
placeholder={this.props.placeholder}
|
placeholder={props.placeholder}
|
||||||
value={this.state.message}
|
value={state.message}
|
||||||
onChange={this.messageChange} />
|
onChange={this.messageChange} />
|
||||||
<div className="pointer" onClick={this.messageSubmit}>
|
<div className="pointer" onClick={this.messageSubmit}>
|
||||||
<IconSend />
|
<IconSend />
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
export class ChatReducer {
|
export class ConfigReducer {
|
||||||
reduce(json, state) {
|
reduce(json, state) {
|
||||||
let data = _.get(json, 'chat', false);
|
let data = _.get(json, 'chat', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
state.messages = data.messages;
|
|
||||||
state.inbox = data.inbox;
|
state.inbox = data.inbox;
|
||||||
state.configs = data.configs;
|
state.configs = data.configs;
|
||||||
state.circles = data.circles;
|
state.circles = data.circles;
|
15
apps/chat/src/js/reducers/initial.js
Normal file
15
apps/chat/src/js/reducers/initial.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
|
export class InitialReducer {
|
||||||
|
reduce(json, state) {
|
||||||
|
let data = _.get(json, 'initial', false);
|
||||||
|
if (data) {
|
||||||
|
state.messages = data.messages;
|
||||||
|
state.inbox = data.inbox;
|
||||||
|
state.configs = data.configs;
|
||||||
|
state.circles = data.circles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ export class UpdateReducer {
|
|||||||
if (data) {
|
if (data) {
|
||||||
this.reduceInbox(_.get(data, 'inbox', false), state);
|
this.reduceInbox(_.get(data, 'inbox', false), state);
|
||||||
this.reduceMessage(_.get(data, 'message', false), state);
|
this.reduceMessage(_.get(data, 'message', false), state);
|
||||||
|
this.reduceMessages(_.get(data, 'messages', false), state);
|
||||||
this.reduceConfig(_.get(data, 'config', false), state);
|
this.reduceConfig(_.get(data, 'config', false), state);
|
||||||
this.reduceCircles(_.get(data, 'circles', false), state);
|
this.reduceCircles(_.get(data, 'circles', false), state);
|
||||||
}
|
}
|
||||||
@ -26,6 +27,22 @@ export class UpdateReducer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduceMessages(messages, state) {
|
||||||
|
if (messages.circle in state.messages) {
|
||||||
|
let station = state.messages[messages.circle];
|
||||||
|
if (
|
||||||
|
station.length > 0 &&
|
||||||
|
station[station.length - 1].num === station.length - 1 &&
|
||||||
|
messages.start === station.length
|
||||||
|
) {
|
||||||
|
state.messages[messages.circle] =
|
||||||
|
state.messages[messages.circle].concat(messages.envelopes);
|
||||||
|
} else {
|
||||||
|
console.error('%messages has indices inconsistent with localStorage');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reduceConfig(config, state) {
|
reduceConfig(config, state) {
|
||||||
if (config) {
|
if (config) {
|
||||||
state.configs[config.circle] = config.config;
|
state.configs[config.circle] = config.config;
|
||||||
|
@ -1,20 +1,34 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { ChatReducer } from '/reducers/chat';
|
import { InitialReducer } from '/reducers/initial';
|
||||||
|
import { ConfigReducer } from '/reducers/config';
|
||||||
import { UpdateReducer } from '/reducers/update';
|
import { UpdateReducer } from '/reducers/update';
|
||||||
|
|
||||||
|
|
||||||
class Store {
|
class Store {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.state = {
|
let state = localStorage.getItem('store');
|
||||||
inbox: {},
|
|
||||||
messages: [],
|
|
||||||
configs: {},
|
|
||||||
circles: []
|
|
||||||
};
|
|
||||||
|
|
||||||
this.chatReducer = new ChatReducer();
|
if (!state) {
|
||||||
|
this.state = {
|
||||||
|
inbox: {},
|
||||||
|
messages: [],
|
||||||
|
configs: {},
|
||||||
|
circles: [],
|
||||||
|
local: false
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.state = JSON.parse(state);
|
||||||
|
// TODO: wtf???
|
||||||
|
delete this.state.messages[undefined];
|
||||||
|
console.log(this.state);
|
||||||
|
this.state.local = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initialReducer = new InitialReducer();
|
||||||
|
this.configReducer = new ConfigReducer();
|
||||||
this.updateReducer = new UpdateReducer();
|
this.updateReducer = new UpdateReducer();
|
||||||
this.setState = () => {};
|
this.setState = () => {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setStateHandler(setState) {
|
setStateHandler(setState) {
|
||||||
@ -22,14 +36,17 @@ class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleEvent(data) {
|
handleEvent(data) {
|
||||||
|
console.log(data);
|
||||||
let json = data.data;
|
let json = data.data;
|
||||||
|
|
||||||
this.chatReducer.reduce(json, this.state);
|
this.initialReducer.reduce(json, this.state);
|
||||||
|
this.configReducer.reduce(json, this.state);
|
||||||
this.updateReducer.reduce(json, this.state);
|
this.updateReducer.reduce(json, this.state);
|
||||||
|
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
localStorage.setItem('store', JSON.stringify(this.state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export let store = new Store();
|
export let store = new Store();
|
||||||
|
window.store = store;
|
||||||
|
@ -7,33 +7,32 @@ export class Subscription {
|
|||||||
start() {
|
start() {
|
||||||
if (api.authTokens) {
|
if (api.authTokens) {
|
||||||
this.initializeChat();
|
this.initializeChat();
|
||||||
//this.setCleanupTasks();
|
|
||||||
} else {
|
} else {
|
||||||
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*setCleanupTasks() {
|
|
||||||
window.addEventListener("beforeunload", e => {
|
|
||||||
api.bindPaths.forEach(p => {
|
|
||||||
this.wipeSubscription(p);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
wipeSubscription(path) {
|
|
||||||
api.hall({
|
|
||||||
wipe: {
|
|
||||||
sub: [{
|
|
||||||
hos: api.authTokens.ship,
|
|
||||||
pax: path
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}*/
|
|
||||||
|
|
||||||
initializeChat() {
|
initializeChat() {
|
||||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'chat',
|
if (store.state.local) {
|
||||||
|
let path = [];
|
||||||
|
let msg = Object.keys(store.state.messages);
|
||||||
|
for (let i = 0; i < msg.length; i++) {
|
||||||
|
let cir = msg[i];
|
||||||
|
let len = store.state.messages[cir].length;
|
||||||
|
path.push(`${cir}/${len}`);
|
||||||
|
}
|
||||||
|
path = path.join('/');
|
||||||
|
|
||||||
|
api.bind(`/primary/${path}`, 'PUT', api.authTokens.ship, 'chat',
|
||||||
|
this.handleEvent.bind(this),
|
||||||
|
this.handleError.bind(this));
|
||||||
|
} else {
|
||||||
|
api.bind('/primary', 'PUT', api.authTokens.ship, 'chat',
|
||||||
|
this.handleEvent.bind(this),
|
||||||
|
this.handleError.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
api.bind('/updates', 'PUT', api.authTokens.ship, 'chat',
|
||||||
this.handleEvent.bind(this),
|
this.handleEvent.bind(this),
|
||||||
this.handleError.bind(this));
|
this.handleError.bind(this));
|
||||||
}
|
}
|
||||||
|
@ -44,9 +44,9 @@
|
|||||||
|= old=(unit state)
|
|= old=(unit state)
|
||||||
^- (quip move _this)
|
^- (quip move _this)
|
||||||
?~ old
|
?~ old
|
||||||
=/ inboxpat /circle/inbox/config/group
|
=/ inboxpat /circle/inbox/config-l/config-r/group-r/group-l
|
||||||
=/ circlespat /circles/[(scot %p our.bol)]
|
=/ circlespat /circles/[(scot %p our.bol)]
|
||||||
=/ inboxwir /circle/[(scot %p our.bol)]/inbox/config/group
|
=/ inboxwir /circle/[(scot %p our.bol)]/inbox/config/group-r/group-l
|
||||||
=/ inboxi/poke
|
=/ inboxi/poke
|
||||||
:- %hall-action
|
:- %hall-action
|
||||||
[%source %inbox %.y (silt [[our.bol %i] ~]~)]
|
[%source %inbox %.y (silt [[our.bol %i] ~]~)]
|
||||||
@ -58,13 +58,97 @@
|
|||||||
==
|
==
|
||||||
[~ this(sta u.old)]
|
[~ this(sta u.old)]
|
||||||
::
|
::
|
||||||
:: +peer-primary: subscribe to our data and updates
|
:: +peer-messages: subscribe to subset of messages and updates
|
||||||
|
::
|
||||||
|
+$ internal-state
|
||||||
|
$:
|
||||||
|
lis=(list [circle:hall @])
|
||||||
|
item=[cir=circle:hall count=@ud]
|
||||||
|
index=@
|
||||||
|
==
|
||||||
|
++ generate-circle-indices
|
||||||
|
|= wir=wire
|
||||||
|
^- (list [circle:hall @])
|
||||||
|
=/ data
|
||||||
|
%^ spin (swag [0 (lent wir)] wir) *internal-state
|
||||||
|
|= [a=@ta b=internal-state]
|
||||||
|
^- [* out=internal-state]
|
||||||
|
=/ switch (dvr index.b 3)
|
||||||
|
?: =(q.switch 0) :: remainder 0, should be a ship
|
||||||
|
?: =(index.b 0) :: if item is null, don't add to list
|
||||||
|
:- 0
|
||||||
|
%= b
|
||||||
|
hos.cir.item (slav %p a)
|
||||||
|
index +(index.b)
|
||||||
|
==
|
||||||
|
:: if item is not null, add to list
|
||||||
|
:- 0
|
||||||
|
%= b
|
||||||
|
hos.cir.item (slav %p a)
|
||||||
|
nom.cir.item *name:hall
|
||||||
|
count.item 0
|
||||||
|
lis (snoc lis.b item.b)
|
||||||
|
index +(index.b)
|
||||||
|
==
|
||||||
|
?: =(q.switch 1) :: remainder 1, should be a circle name
|
||||||
|
:- 0
|
||||||
|
%= b
|
||||||
|
nom.cir.item a
|
||||||
|
index +(index.b)
|
||||||
|
==
|
||||||
|
?: =(q.switch 2) :: remainder 2, should be a number
|
||||||
|
:- 0
|
||||||
|
%= b
|
||||||
|
count.item (need (rush a dem))
|
||||||
|
index +(index.b)
|
||||||
|
==
|
||||||
|
!! :: impossible
|
||||||
|
?: =(index.q.data 0)
|
||||||
|
~
|
||||||
|
(snoc lis.q.data item.q.data)
|
||||||
::
|
::
|
||||||
++ peer-primary
|
++ peer-primary
|
||||||
|= wir=wire
|
|= wir=wire
|
||||||
^- (quip move _this)
|
^- (quip move _this)
|
||||||
|
=/ indices (generate-circle-indices wir)
|
||||||
|
?~ indices
|
||||||
|
:_ this
|
||||||
|
[ost.bol %diff %chat-initial str.sta]~
|
||||||
|
=* messages messages.str.sta
|
||||||
|
=/ lisunitmov/(list (unit move))
|
||||||
|
%+ turn indices
|
||||||
|
|= [cir=circle:hall start=@ud]
|
||||||
|
^- (unit move)
|
||||||
|
=/ wholelist/(unit (list envelope:hall)) (~(get by messages) cir)
|
||||||
|
?~ wholelist
|
||||||
|
~
|
||||||
|
=/ end/@ (lent u.wholelist)
|
||||||
|
?: (gte start end)
|
||||||
|
~
|
||||||
|
:- ~
|
||||||
|
:* ost.bol
|
||||||
|
%diff
|
||||||
|
%chat-update
|
||||||
|
[%messages cir start end (swag [start end] u.wholelist)]
|
||||||
|
==
|
||||||
|
=/ lismov/(list move)
|
||||||
|
%+ turn
|
||||||
|
%+ skim lisunitmov
|
||||||
|
|= umov=(unit move)
|
||||||
|
^- ?
|
||||||
|
?~ umov
|
||||||
|
%.n
|
||||||
|
%.y
|
||||||
|
need
|
||||||
:_ this
|
:_ this
|
||||||
[ost.bol %diff %chat-streams str.sta]~
|
%+ weld
|
||||||
|
[ost.bol %diff %chat-config str.sta]~
|
||||||
|
lismov
|
||||||
|
::
|
||||||
|
++ peer-updates
|
||||||
|
|= wir=wire
|
||||||
|
^- (quip move _this)
|
||||||
|
[~ this]
|
||||||
::
|
::
|
||||||
++ poke-noun
|
++ poke-noun
|
||||||
|= a=*
|
|= a=*
|
||||||
@ -93,7 +177,7 @@
|
|||||||
++ send-chat-update
|
++ send-chat-update
|
||||||
|= upd=update
|
|= upd=update
|
||||||
^- (list move)
|
^- (list move)
|
||||||
%+ turn (prey:pubsub:userlib /primary bol)
|
%+ turn (prey:pubsub:userlib /updates bol)
|
||||||
|= [=bone *]
|
|= [=bone *]
|
||||||
[bone %diff %chat-update upd]
|
[bone %diff %chat-update upd]
|
||||||
::
|
::
|
||||||
@ -123,19 +207,12 @@
|
|||||||
:: %circle wire
|
:: %circle wire
|
||||||
::
|
::
|
||||||
%circle
|
%circle
|
||||||
:: ?+ -.piz
|
|
||||||
:: ::
|
|
||||||
:: :: %peers prize
|
|
||||||
:: ::
|
|
||||||
:::: %peers
|
|
||||||
:::: ?> ?=(%peers -.piz)
|
|
||||||
:::: [~ this]
|
|
||||||
:: ::
|
:: ::
|
||||||
:: :: %circle prize
|
:: :: %circle prize
|
||||||
:: ::
|
:: ::
|
||||||
:: %circle
|
:: %circle
|
||||||
?> ?=(%circle -.piz)
|
?> ?=(%circle -.piz)
|
||||||
~& piz
|
~& pes.piz
|
||||||
=/ circle/circle:hall [our.bol &2:wir]
|
=/ circle/circle:hall [our.bol &2:wir]
|
||||||
?: =(circle [our.bol %inbox])
|
?: =(circle [our.bol %inbox])
|
||||||
::
|
::
|
||||||
@ -145,27 +222,46 @@
|
|||||||
%- ~(uni in configs.str.sta)
|
%- ~(uni in configs.str.sta)
|
||||||
^- (map circle:hall (unit config:hall))
|
^- (map circle:hall (unit config:hall))
|
||||||
(~(run by rem.cos.piz) |=(a=config:hall `a))
|
(~(run by rem.cos.piz) |=(a=config:hall `a))
|
||||||
~& pes.piz
|
::
|
||||||
=/ circles/(list circle:hall)
|
=/ circles/(list circle:hall)
|
||||||
%+ turn ~(tap in src.loc.cos.piz)
|
%+ turn ~(tap in src.loc.cos.piz)
|
||||||
|= src=source:hall
|
|= src=source:hall
|
||||||
^- circle:hall
|
^- circle:hall
|
||||||
cir.src
|
cir.src
|
||||||
|
::
|
||||||
=/ meslis/(list [circle:hall (list envelope:hall)])
|
=/ meslis/(list [circle:hall (list envelope:hall)])
|
||||||
%+ turn circles
|
%+ turn circles
|
||||||
|= cir=circle:hall
|
|= cir=circle:hall
|
||||||
^- [circle:hall (list envelope:hall)]
|
^- [circle:hall (list envelope:hall)]
|
||||||
[cir ~]
|
[cir ~]
|
||||||
|
::
|
||||||
|
=/ localpeers/(set @p)
|
||||||
|
%- silt %+ turn ~(tap by loc.pes.piz)
|
||||||
|
|= [shp=@p stat=status:hall]
|
||||||
|
shp
|
||||||
|
::
|
||||||
|
=/ peers/(map circle:hall (set @p))
|
||||||
|
%- ~(rep by rem.pes.piz)
|
||||||
|
|= [[cir=circle:hall grp=group:hall] acc=(map circle:hall (set @p))]
|
||||||
|
^- (map circle:hall (set @p))
|
||||||
|
=/ newset
|
||||||
|
%- silt %+ turn ~(tap by grp)
|
||||||
|
|= [shp=@p stat=status:hall]
|
||||||
|
shp
|
||||||
|
(~(put by acc) cir newset)
|
||||||
|
::
|
||||||
:-
|
:-
|
||||||
%+ turn ~(tap in (~(del in (silt circles)) [our.bol %inbox]))
|
%+ turn ~(tap in (~(del in (silt circles)) [our.bol %inbox]))
|
||||||
|= cir=circle:hall
|
|= cir=circle:hall
|
||||||
^- move
|
^- move
|
||||||
=/ pat/path /circle/[nom.cir]/config/grams
|
=/ pat/path /circle/[nom.cir]/config-l/config-r/group-r/group-l
|
||||||
[ost.bol %peer pat [our.bol %hall] pat]
|
[ost.bol %peer pat [our.bol %hall] pat]
|
||||||
|
::
|
||||||
%= this
|
%= this
|
||||||
inbox.str.sta loc.cos.piz
|
inbox.str.sta loc.cos.piz
|
||||||
configs.str.sta configs
|
configs.str.sta configs
|
||||||
messages.str.sta (molt meslis)
|
messages.str.sta (molt meslis)
|
||||||
|
peers.str.sta (~(put by peers) [our.bol %inbox] localpeers)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
:: fill remote configs with message data
|
:: fill remote configs with message data
|
||||||
@ -224,22 +320,27 @@
|
|||||||
messages.str.sta (~(put by messages) circle (snoc nes nev.sto))
|
messages.str.sta (~(put by messages) circle (snoc nes nev.sto))
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
:: %peer:
|
:: %status:
|
||||||
::
|
::
|
||||||
%peer
|
%status
|
||||||
?> ?=(%peer -.sto)
|
?> ?=(%status -.sto)
|
||||||
~& add.sto
|
=/ peers/(set @p)
|
||||||
~& who.sto
|
?: =(%remove -.dif.sto)
|
||||||
~& qer.sto
|
(~(del in (~(got by peers.str.sta) cir.sto)) who.sto)
|
||||||
[~ this]
|
(~(put in (~(got by peers.str.sta) cir.sto)) who.sto)
|
||||||
|
:- (send-chat-update [%peers cir.sto peers])
|
||||||
|
%= this
|
||||||
|
peers.str.sta (~(put by peers.str.sta) cir.sto peers)
|
||||||
|
==
|
||||||
|
|
||||||
::
|
::
|
||||||
:: %config: config has changed
|
:: %config: config has changed
|
||||||
::
|
::
|
||||||
%config
|
%config
|
||||||
=* circ cir.sto
|
=* circ cir.sto
|
||||||
::
|
::
|
||||||
?+ -.dif.sto
|
?+ -.dif.sto
|
||||||
[~ this]
|
[~ this]
|
||||||
::
|
::
|
||||||
:: %full: set all of config without side effects
|
:: %full: set all of config without side effects
|
||||||
::
|
::
|
||||||
@ -277,8 +378,8 @@
|
|||||||
[~ this]
|
[~ this]
|
||||||
=* affectedcir cir.src.dif.sto
|
=* affectedcir cir.src.dif.sto
|
||||||
=/ newwir/wire
|
=/ newwir/wire
|
||||||
/circle/[(scot %p hos.affectedcir)]/[nom.affectedcir]/grams/config
|
/circle/[(scot %p hos.affectedcir)]/[nom.affectedcir]/grams/config/group-r/group-l
|
||||||
=/ pat/path /circle/[nom.affectedcir]/grams/config
|
=/ pat/path /circle/[nom.affectedcir]/grams/config/group-r/group-l
|
||||||
:: we've added a source to our inbox
|
:: we've added a source to our inbox
|
||||||
::
|
::
|
||||||
?: add.dif.sto
|
?: add.dif.sto
|
||||||
@ -411,7 +512,7 @@
|
|||||||
::
|
::
|
||||||
%circle
|
%circle
|
||||||
=/ shp/@p (slav %p &2:wir)
|
=/ shp/@p (slav %p &2:wir)
|
||||||
=/ pat /circle/[&3:wir]/grams/config
|
=/ pat /circle/[&3:wir]/grams/config/group-r/group-l
|
||||||
:_ this
|
:_ this
|
||||||
[ost.bol %peer wir [shp %hall] wir]~
|
[ost.bol %peer wir [shp %hall] wir]~
|
||||||
::
|
::
|
||||||
|
@ -17,6 +17,10 @@
|
|||||||
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCjsExportFromNamespace (n) {
|
||||||
|
return n && n.default || n;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
object-assign
|
object-assign
|
||||||
(c) Sindre Sorhus
|
(c) Sindre Sorhus
|
||||||
@ -47458,6 +47462,8 @@
|
|||||||
isBuffer: isBuffer
|
isBuffer: isBuffer
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var require$$0 = getCjsExportFromNamespace(bufferEs6);
|
||||||
|
|
||||||
var bn = createCommonjsModule(function (module) {
|
var bn = createCommonjsModule(function (module) {
|
||||||
(function (module, exports) {
|
(function (module, exports) {
|
||||||
|
|
||||||
@ -47510,7 +47516,7 @@
|
|||||||
|
|
||||||
var Buffer;
|
var Buffer;
|
||||||
try {
|
try {
|
||||||
Buffer = bufferEs6.Buffer;
|
Buffer = require$$0.Buffer;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51734,6 +51740,15 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notify(aud, bool) {
|
||||||
|
this.hall({
|
||||||
|
notify: {
|
||||||
|
aud,
|
||||||
|
pes: !!bool ? 'hear' : 'gone'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
permit(cir, aud, message) {
|
permit(cir, aud, message) {
|
||||||
this.hall({
|
this.hall({
|
||||||
permit: {
|
permit: {
|
||||||
@ -51814,11 +51829,22 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
let api = new UrbitApi();
|
let api = new UrbitApi();
|
||||||
window.api = api;
|
window.api = api;
|
||||||
|
|
||||||
class ChatReducer {
|
class InitialReducer {
|
||||||
|
reduce(json, state) {
|
||||||
|
let data = lodash.get(json, 'initial', false);
|
||||||
|
if (data) {
|
||||||
|
state.messages = data.messages;
|
||||||
|
state.inbox = data.inbox;
|
||||||
|
state.configs = data.configs;
|
||||||
|
state.circles = data.circles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigReducer {
|
||||||
reduce(json, state) {
|
reduce(json, state) {
|
||||||
let data = lodash.get(json, 'chat', false);
|
let data = lodash.get(json, 'chat', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
state.messages = data.messages;
|
|
||||||
state.inbox = data.inbox;
|
state.inbox = data.inbox;
|
||||||
state.configs = data.configs;
|
state.configs = data.configs;
|
||||||
state.circles = data.circles;
|
state.circles = data.circles;
|
||||||
@ -51832,6 +51858,7 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
if (data) {
|
if (data) {
|
||||||
this.reduceInbox(lodash.get(data, 'inbox', false), state);
|
this.reduceInbox(lodash.get(data, 'inbox', false), state);
|
||||||
this.reduceMessage(lodash.get(data, 'message', false), state);
|
this.reduceMessage(lodash.get(data, 'message', false), state);
|
||||||
|
this.reduceMessages(lodash.get(data, 'messages', false), state);
|
||||||
this.reduceConfig(lodash.get(data, 'config', false), state);
|
this.reduceConfig(lodash.get(data, 'config', false), state);
|
||||||
this.reduceCircles(lodash.get(data, 'circles', false), state);
|
this.reduceCircles(lodash.get(data, 'circles', false), state);
|
||||||
}
|
}
|
||||||
@ -51851,6 +51878,22 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduceMessages(messages, state) {
|
||||||
|
if (messages.circle in state.messages) {
|
||||||
|
let station = state.messages[messages.circle];
|
||||||
|
if (
|
||||||
|
station.length > 0 &&
|
||||||
|
station[station.length - 1].num === station.length - 1 &&
|
||||||
|
messages.start === station.length
|
||||||
|
) {
|
||||||
|
state.messages[messages.circle] =
|
||||||
|
state.messages[messages.circle].concat(messages.envelopes);
|
||||||
|
} else {
|
||||||
|
console.error('%messages has indices inconsistent with localStorage');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reduceConfig(config, state) {
|
reduceConfig(config, state) {
|
||||||
if (config) {
|
if (config) {
|
||||||
state.configs[config.circle] = config.config;
|
state.configs[config.circle] = config.config;
|
||||||
@ -51867,16 +51910,29 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
|
|
||||||
class Store {
|
class Store {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.state = {
|
let state = localStorage.getItem('store');
|
||||||
inbox: {},
|
|
||||||
messages: [],
|
|
||||||
configs: {},
|
|
||||||
circles: []
|
|
||||||
};
|
|
||||||
|
|
||||||
this.chatReducer = new ChatReducer();
|
if (!state) {
|
||||||
|
this.state = {
|
||||||
|
inbox: {},
|
||||||
|
messages: [],
|
||||||
|
configs: {},
|
||||||
|
circles: [],
|
||||||
|
local: false
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.state = JSON.parse(state);
|
||||||
|
// TODO: wtf???
|
||||||
|
delete this.state.messages[undefined];
|
||||||
|
console.log(this.state);
|
||||||
|
this.state.local = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initialReducer = new InitialReducer();
|
||||||
|
this.configReducer = new ConfigReducer();
|
||||||
this.updateReducer = new UpdateReducer();
|
this.updateReducer = new UpdateReducer();
|
||||||
this.setState = () => {};
|
this.setState = () => {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setStateHandler(setState) {
|
setStateHandler(setState) {
|
||||||
@ -51884,16 +51940,20 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleEvent(data) {
|
handleEvent(data) {
|
||||||
|
console.log(data);
|
||||||
let json = data.data;
|
let json = data.data;
|
||||||
|
|
||||||
this.chatReducer.reduce(json, this.state);
|
this.initialReducer.reduce(json, this.state);
|
||||||
|
this.configReducer.reduce(json, this.state);
|
||||||
this.updateReducer.reduce(json, this.state);
|
this.updateReducer.reduce(json, this.state);
|
||||||
|
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
localStorage.setItem('store', JSON.stringify(this.state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let store = new Store();
|
let store = new Store();
|
||||||
|
window.store = store;
|
||||||
|
|
||||||
const _jsxFileName = "/Users/logan/Dev/interface/apps/chat/src/js/components/skeleton.js";
|
const _jsxFileName = "/Users/logan/Dev/interface/apps/chat/src/js/components/skeleton.js";
|
||||||
|
|
||||||
@ -56957,20 +57017,56 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
|
const { props, state } = this;
|
||||||
|
/*let closure = () => {
|
||||||
|
let aud, sep;
|
||||||
|
let wen = Date.now();
|
||||||
|
let uid = uuid();
|
||||||
|
let aut = window.ship;
|
||||||
|
|
||||||
|
let config = props.configs[state.station];
|
||||||
|
|
||||||
|
aud = [props.station];
|
||||||
|
sep = {
|
||||||
|
lin: {
|
||||||
|
msg: Date.now().toString(),
|
||||||
|
pat: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = {
|
||||||
|
uid,
|
||||||
|
aut,
|
||||||
|
wen,
|
||||||
|
aud,
|
||||||
|
sep,
|
||||||
|
};
|
||||||
|
|
||||||
|
props.api.hall({
|
||||||
|
convey: [message]
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(closure, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
closure();*/
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
react.createElement('div', { className: "mt2 pa3 cf flex black bt" , __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 109}}
|
react.createElement('div', { className: "mt2 pa3 cf flex black bt" , __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 145}}
|
||||||
, react.createElement('div', { className: "fl", style: { flexBasis: 35, height: 40 }, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 110}}
|
, react.createElement('div', { className: "fl", style: { flexBasis: 35, height: 40 }, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 146}}
|
||||||
, react.createElement(Sigil, { ship: window.ship, size: 32, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 111}} )
|
, react.createElement(Sigil, { ship: window.ship, size: 32, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 147}} )
|
||||||
)
|
)
|
||||||
, react.createElement('div', { className: "fr h-100 flex" , style: { flexGrow: 1, height: 40 }, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 113}}
|
, react.createElement('div', { className: "fr h-100 flex" , style: { flexGrow: 1, height: 40 }, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 149}}
|
||||||
, react.createElement('input', { className: "ml2 bn" ,
|
, react.createElement('input', { className: "ml2 bn" ,
|
||||||
style: { flexGrow: 1 },
|
style: { flexGrow: 1 },
|
||||||
ref: this.textareaRef,
|
ref: this.textareaRef,
|
||||||
placeholder: this.props.placeholder,
|
placeholder: props.placeholder,
|
||||||
value: this.state.message,
|
value: state.message,
|
||||||
onChange: this.messageChange, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 114}} )
|
onChange: this.messageChange, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 150}} )
|
||||||
, react.createElement('div', { className: "pointer", onClick: this.messageSubmit, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 120}}
|
, react.createElement('div', { className: "pointer", onClick: this.messageSubmit, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 156}}
|
||||||
, react.createElement(IconSend, {__self: this, __source: {fileName: _jsxFileName$9, lineNumber: 121}} )
|
, react.createElement(IconSend, {__self: this, __source: {fileName: _jsxFileName$9, lineNumber: 157}} )
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -56987,14 +57083,47 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
station: props.match.params.ship + "/" + props.match.params.station,
|
station: props.match.params.ship + "/" + props.match.params.station,
|
||||||
circle: props.match.params.station,
|
circle: props.match.params.station,
|
||||||
host: props.match.params.ship,
|
host: props.match.params.ship,
|
||||||
numPeople: 0
|
numPeople: 0,
|
||||||
|
numPages: 1,
|
||||||
|
scrollLocked: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.topMessage = {};
|
||||||
this.buildMessage = this.buildMessage.bind(this);
|
this.buildMessage = this.buildMessage.bind(this);
|
||||||
|
this.onScroll = this.onScroll.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.updateNumPeople();
|
this.updateNumPeople();
|
||||||
|
this.scrollElement.scrollIntoView(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToBottom() {
|
||||||
|
if (!this.state.scrollLocked) {
|
||||||
|
console.log('scroll to bottom');
|
||||||
|
this.scrollElement.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onScroll(e) {
|
||||||
|
if (e.target.scrollTop === 0) {
|
||||||
|
let topMessage = this.topMessage;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
numPages: this.state.numPages + 1,
|
||||||
|
scrollLocked: true
|
||||||
|
}, () => {
|
||||||
|
this.topMessage[1].scrollIntoView(true);
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
(e.target.scrollHeight - Math.round(e.target.scrollTop)) ===
|
||||||
|
e.target.clientHeight
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
numPages: 1,
|
||||||
|
scrollLocked: false
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
@ -57012,6 +57141,7 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
this.updateReadNumber();
|
this.updateReadNumber();
|
||||||
this.updateNumPeople();
|
this.updateNumPeople();
|
||||||
this.updateNumMessagesLoaded(prevProps, prevState);
|
this.updateNumMessagesLoaded(prevProps, prevState);
|
||||||
|
this.scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateReadNumber() {
|
updateReadNumber() {
|
||||||
@ -57048,42 +57178,62 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildMessage(msg) {
|
buildMessage(msg, index) {
|
||||||
let details = msg.printship ? null : getMessageContent(msg.gam);
|
let details = msg.printship ? null : getMessageContent(msg.gam);
|
||||||
|
|
||||||
if (msg.printship) {
|
if (msg.printship) {
|
||||||
return (
|
return (
|
||||||
react.createElement('a', {
|
react.createElement('a', {
|
||||||
className: "vanilla hoverline text-600 text-mono" ,
|
className: "vanilla hoverline text-600 text-mono" ,
|
||||||
href: prettyShip(msg.gam.aut)[1], __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 85}}
|
href: prettyShip(msg.gam.aut)[1], __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 119}}
|
||||||
, prettyShip(`~${msg.gam.aut}`)[0]
|
, prettyShip(`~${msg.gam.aut}`)[0]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
|
||||||
react.createElement(Message, { key: msg.gam.uid, msg: msg.gam, details: details, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 93}} )
|
if (index % 50 === 0) {
|
||||||
);
|
let pageNum = index / 50;
|
||||||
|
return (
|
||||||
|
react.createElement('div', { ref: el => { this.topMessage[pageNum] = el; }, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 130}}
|
||||||
|
, react.createElement(Message, {
|
||||||
|
key: msg.gam.uid, msg: msg.gam, details: details, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 131}} )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
react.createElement(Message, { key: msg.gam.uid, msg: msg.gam, details: details, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 137}} )
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { props, state } = this;
|
||||||
let messages = this.props.messages[this.state.station] || [];
|
let messages = this.props.messages[this.state.station] || [];
|
||||||
|
if (messages.length > 50 * state.numPages) {
|
||||||
|
messages =
|
||||||
|
messages.slice(messages.length - (50 * state.numPages), messages.length);
|
||||||
|
}
|
||||||
let chatMessages = messages.map(this.buildMessage);
|
let chatMessages = messages.map(this.buildMessage);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
react.createElement('div', { className: "h-100 w-100 overflow-hidden flex flex-column" , __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 102}}
|
react.createElement('div', { className: "h-100 w-100 overflow-hidden flex flex-column" , __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 152}}
|
||||||
, react.createElement('div', { className: "pl2 pt2 bb mb3" , __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 103}}
|
, react.createElement('div', { className: "pl2 pt2 bb mb3" , __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 153}}
|
||||||
, react.createElement('h2', {__self: this, __source: {fileName: _jsxFileName$a, lineNumber: 104}}, this.state.circle)
|
, react.createElement('h2', {__self: this, __source: {fileName: _jsxFileName$a, lineNumber: 154}}, this.state.circle)
|
||||||
, react.createElement(ChatTabBar, { ...this.props, station: this.state.station, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 105}} )
|
, react.createElement(ChatTabBar, { ...this.props, station: this.state.station, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 155}} )
|
||||||
)
|
)
|
||||||
, react.createElement('div', { className: "overflow-y-scroll", style: { flexGrow: 1 }, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 107}}
|
, react.createElement('div', {
|
||||||
|
className: "overflow-y-scroll",
|
||||||
|
style: { flexGrow: 1 },
|
||||||
|
onScroll: this.onScroll, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 157}}
|
||||||
, chatMessages
|
, chatMessages
|
||||||
|
, react.createElement('div', { ref: el => { this.scrollElement = el; }, __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 162}})
|
||||||
)
|
)
|
||||||
, react.createElement(ChatInput, {
|
, react.createElement(ChatInput, {
|
||||||
api: this.props.api,
|
api: this.props.api,
|
||||||
configs: this.props.configs,
|
configs: this.props.configs,
|
||||||
station: this.state.station,
|
station: this.state.station,
|
||||||
circle: this.state.circle,
|
circle: this.state.circle,
|
||||||
placeholder: "Message...", __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 110}} )
|
placeholder: "Message...", __self: this, __source: {fileName: _jsxFileName$a, lineNumber: 164}} )
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -57545,33 +57695,32 @@ lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes\
|
|||||||
start() {
|
start() {
|
||||||
if (api.authTokens) {
|
if (api.authTokens) {
|
||||||
this.initializeChat();
|
this.initializeChat();
|
||||||
//this.setCleanupTasks();
|
|
||||||
} else {
|
} else {
|
||||||
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*setCleanupTasks() {
|
|
||||||
window.addEventListener("beforeunload", e => {
|
|
||||||
api.bindPaths.forEach(p => {
|
|
||||||
this.wipeSubscription(p);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
wipeSubscription(path) {
|
|
||||||
api.hall({
|
|
||||||
wipe: {
|
|
||||||
sub: [{
|
|
||||||
hos: api.authTokens.ship,
|
|
||||||
pax: path
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}*/
|
|
||||||
|
|
||||||
initializeChat() {
|
initializeChat() {
|
||||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'chat',
|
if (store.state.local) {
|
||||||
|
let path = [];
|
||||||
|
let msg = Object.keys(store.state.messages);
|
||||||
|
for (let i = 0; i < msg.length; i++) {
|
||||||
|
let cir = msg[i];
|
||||||
|
let len = store.state.messages[cir].length;
|
||||||
|
path.push(`${cir}/${len}`);
|
||||||
|
}
|
||||||
|
path = path.join('/');
|
||||||
|
|
||||||
|
api.bind(`/primary/${path}`, 'PUT', api.authTokens.ship, 'chat',
|
||||||
|
this.handleEvent.bind(this),
|
||||||
|
this.handleError.bind(this));
|
||||||
|
} else {
|
||||||
|
api.bind('/primary', 'PUT', api.authTokens.ship, 'chat',
|
||||||
|
this.handleEvent.bind(this),
|
||||||
|
this.handleError.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
api.bind('/updates', 'PUT', api.authTokens.ship, 'chat',
|
||||||
this.handleEvent.bind(this),
|
this.handleEvent.bind(this),
|
||||||
this.handleError.bind(this));
|
this.handleError.bind(this));
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,9 @@
|
|||||||
::
|
::
|
||||||
+$ diff
|
+$ diff
|
||||||
$% [%hall-rumor rumor:hall]
|
$% [%hall-rumor rumor:hall]
|
||||||
[%chat-streams streams]
|
[%chat-initial streams]
|
||||||
[%chat-update update]
|
[%chat-update update]
|
||||||
|
[%chat-config streams]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ poke
|
+$ poke
|
||||||
@ -49,6 +50,7 @@
|
|||||||
+$ update
|
+$ update
|
||||||
$% [%inbox con=config:hall]
|
$% [%inbox con=config:hall]
|
||||||
[%message cir=circle:hall env=envelope:hall]
|
[%message cir=circle:hall env=envelope:hall]
|
||||||
|
[%messages cir=circle:hall start=@ud end=@ud env=(list envelope:hall)]
|
||||||
[%config cir=circle:hall con=config:hall]
|
[%config cir=circle:hall con=config:hall]
|
||||||
[%circles cir=(set name:hall)]
|
[%circles cir=(set name:hall)]
|
||||||
[%peers cir=circle:hall per=(set @p)]
|
[%peers cir=circle:hall per=(set @p)]
|
||||||
|
@ -24,19 +24,20 @@
|
|||||||
^- [@t ^json]
|
^- [@t ^json]
|
||||||
:- (crip (circ:en-tape:hall-json cir))
|
:- (crip (circ:en-tape:hall-json cir))
|
||||||
?~(con ~ (conf:enjs:hall-json u.con))
|
?~(con ~ (conf:enjs:hall-json u.con))
|
||||||
::
|
|
||||||
:- %messages
|
|
||||||
%- pairs
|
|
||||||
%+ turn ~(tap by messages.str)
|
|
||||||
|= [cir=circle:hall lis=(list envelope:hall)]
|
|
||||||
^- [@t ^json]
|
|
||||||
:- (crip (circ:en-tape:hall-json cir))
|
|
||||||
[%a (turn lis enve:enjs:hall-json)]
|
|
||||||
::
|
::
|
||||||
:- %circles :- %a
|
:- %circles :- %a
|
||||||
%+ turn ~(tap in circles.str)
|
%+ turn ~(tap in circles.str)
|
||||||
|= nom=name:hall
|
|= nom=name:hall
|
||||||
[%s nom]
|
[%s nom]
|
||||||
|
::
|
||||||
|
:- %peers
|
||||||
|
%- pairs
|
||||||
|
%+ turn ~(tap by peers.str)
|
||||||
|
|= [cir=circle:hall per=(set @p)]
|
||||||
|
^- [@t ^json]
|
||||||
|
:- (crip (circ:en-tape:hall-json cir))
|
||||||
|
[%a (turn ~(tap in per) ship)]
|
||||||
|
::
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
::
|
::
|
56
apps/chat/urbit/mar/chat/initial.hoon
Normal file
56
apps/chat/urbit/mar/chat/initial.hoon
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
::
|
||||||
|
::
|
||||||
|
/? 309
|
||||||
|
::
|
||||||
|
/- hall
|
||||||
|
/+ chat, hall-json
|
||||||
|
::
|
||||||
|
|_ str=streams:chat
|
||||||
|
++ grow
|
||||||
|
|%
|
||||||
|
++ json
|
||||||
|
=, enjs:format
|
||||||
|
^- ^json
|
||||||
|
%+ frond %initial
|
||||||
|
%- pairs
|
||||||
|
:~
|
||||||
|
::
|
||||||
|
[%inbox (conf:enjs:hall-json inbox.str)]
|
||||||
|
::
|
||||||
|
:- %configs
|
||||||
|
%- pairs
|
||||||
|
%+ turn ~(tap by configs.str)
|
||||||
|
|= [cir=circle:hall con=(unit config:hall)]
|
||||||
|
^- [@t ^json]
|
||||||
|
:- (crip (circ:en-tape:hall-json cir))
|
||||||
|
?~(con ~ (conf:enjs:hall-json u.con))
|
||||||
|
::
|
||||||
|
:- %messages
|
||||||
|
%- pairs
|
||||||
|
%+ turn ~(tap by messages.str)
|
||||||
|
|= [cir=circle:hall lis=(list envelope:hall)]
|
||||||
|
^- [@t ^json]
|
||||||
|
:- (crip (circ:en-tape:hall-json cir))
|
||||||
|
[%a (turn lis enve:enjs:hall-json)]
|
||||||
|
::
|
||||||
|
:- %circles :- %a
|
||||||
|
%+ turn ~(tap in circles.str)
|
||||||
|
|= nom=name:hall
|
||||||
|
[%s nom]
|
||||||
|
::
|
||||||
|
:- %peers
|
||||||
|
%- pairs
|
||||||
|
%+ turn ~(tap by peers.str)
|
||||||
|
|= [cir=circle:hall per=(set @p)]
|
||||||
|
^- [@t ^json]
|
||||||
|
:- (crip (circ:en-tape:hall-json cir))
|
||||||
|
[%a (turn ~(tap in per) ship)]
|
||||||
|
::
|
||||||
|
==
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ grab
|
||||||
|
|%
|
||||||
|
++ noun streams:chat
|
||||||
|
--
|
||||||
|
--
|
@ -30,6 +30,18 @@
|
|||||||
[%envelope (enve:enjs:hall-json env.upd)]
|
[%envelope (enve:enjs:hall-json env.upd)]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
:: %messages
|
||||||
|
?: =(%messages -.upd)
|
||||||
|
?> ?=(%messages -.upd)
|
||||||
|
:- %messages
|
||||||
|
%- pairs
|
||||||
|
:~
|
||||||
|
[%circle (circ:enjs:hall-json cir.upd)]
|
||||||
|
[%start (numb start.upd)]
|
||||||
|
[%end (numb end.upd)]
|
||||||
|
[%envelopes [%a (turn env.upd enve:enjs:hall-json)]]
|
||||||
|
==
|
||||||
|
::
|
||||||
:: %config
|
:: %config
|
||||||
?: =(%config -.upd)
|
?: =(%config -.upd)
|
||||||
?> ?=(%config -.upd)
|
?> ?=(%config -.upd)
|
||||||
@ -39,6 +51,8 @@
|
|||||||
[%circle (circ:enjs:hall-json cir.upd)]
|
[%circle (circ:enjs:hall-json cir.upd)]
|
||||||
[%config (conf:enjs:hall-json con.upd)]
|
[%config (conf:enjs:hall-json con.upd)]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
|
:: %circles
|
||||||
?: =(%circles -.upd)
|
?: =(%circles -.upd)
|
||||||
?> ?=(%circles -.upd)
|
?> ?=(%circles -.upd)
|
||||||
:- %circles
|
:- %circles
|
||||||
@ -51,6 +65,16 @@
|
|||||||
[%s nom]
|
[%s nom]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
:: %peers
|
||||||
|
?: =(%peers -.upd)
|
||||||
|
?> ?=(%peers -.upd)
|
||||||
|
:- %peers
|
||||||
|
%- pairs
|
||||||
|
:~
|
||||||
|
[%circle (circ:enjs:hall-json cir.upd)]
|
||||||
|
[%peers [%a (turn ~(tap in per.upd) ship:enjs:format)]]
|
||||||
|
==
|
||||||
|
::
|
||||||
:: %noop
|
:: %noop
|
||||||
[*@t *^json]
|
[*@t *^json]
|
||||||
==
|
==
|
||||||
|
Loading…
Reference in New Issue
Block a user