here comes talk

This commit is contained in:
Galen Wolfe-Pauly 2015-03-26 14:00:45 -07:00
commit 70e73f4f03
21 changed files with 1234 additions and 886 deletions

View File

@ -1989,7 +1989,7 @@ try to get the aeon referred to by the starting case. If it doesn't
exist yet, then we can't do anything interesting with this subscription, exist yet, then we can't do anything interesting with this subscription,
so we move on to the next one. so we move on to the next one.
Otherwise, we try to get the aeon referrred to by the ending case. If it Otherwise, we try to get the aeon referred to by the ending case. If it
doesn't exist yet, then we produce all the information we can. We call doesn't exist yet, then we produce all the information we can. We call
`++lobes-at-path` at the given aeon and path to see if the requested `++lobes-at-path` at the given aeon and path to see if the requested
path has actually changed. If it hasn't, then we don't produce anything; path has actually changed. If it hasn't, then we don't produce anything;

View File

@ -0,0 +1,12 @@
# installing
`npm install`
# building
in `src/js/`:
`watchify -v -t coffeeify -o main.js main.coffee`
in `src/css/`:
`stylus -w main.styl`

View File

@ -9,8 +9,7 @@
;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"); ;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js");
;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"); ;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js");
;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/react/0.12.1/react.js"); ;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/react/0.12.1/react.js");
;script(type "text/javascript", src "/main/pub/talk/src/js/dep/director.js"); ;meta(name "viewport", content "width=device-width, height=device-height, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0");
;meta(name "viewport", content "width=432, initial-scale=1");
;link(type "text/css", rel "stylesheet", href "/main/pub/talk/src/css/main.css"); ;link(type "text/css", rel "stylesheet", href "/main/pub/talk/src/css/main.css");
;script(type "text/javascript", src "/gop/hart.js"); ;script(type "text/javascript", src "/gop/hart.js");
;title: Radio ;title: Radio

View File

@ -70,3 +70,15 @@
font-weight: 500; font-weight: 500;
font-style: normal; font-style: normal;
} }
@font-face {
font-family: "scp";
src: url("http://storage.googleapis.com/urbit-extra/scp-bold.woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("http://storage.googleapis.com/urbit-extra/scp-black.woff");
font-weight: 700;
font-style: normal;
}

View File

@ -70,10 +70,25 @@
font-weight: 500; font-weight: 500;
font-style: normal; font-style: normal;
} }
@font-face {
font-family: "scp";
src: url("http://storage.googleapis.com/urbit-extra/scp-bold.woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("http://storage.googleapis.com/urbit-extra/scp-black.woff");
font-weight: 700;
font-style: normal;
}
.iden, .iden,
.audi, .audi,
.time, .time,
#length { #length,
#where,
#who,
.station {
font-family: "scp"; font-family: "scp";
} }
.join-ctrl input { .join-ctrl input {
@ -100,6 +115,9 @@ input.join,
#station { #station {
font-size: 0.7rem; font-size: 0.7rem;
} }
.iden {
font-weight: 600;
}
html, html,
body { body {
font-size: 18px; font-size: 18px;
@ -113,124 +131,152 @@ body {
display: none; display: none;
} }
#c { #c {
top: 0;
background-color: #fff;
}
#stations-container {
position: absolute; position: absolute;
top: 1rem; top: 0rem;
left: 50%; left: 50%;
width: 24rem; width: 58rem;
margin-left: -12rem; margin-left: -29rem;
font-size: 4rem; margin-bottom: 12rem;
} }
#station-container { #station-container {
position: fixed; position: fixed;
top: 0; width: 58rem;
left: 50%; max-height: 2.7rem;
width: 28rem; background-color: #fff;
max-height: 2.6rem; border-bottom: 0.3rem solid #000;
padding-bottom: 1rem;
overflow: hidden; overflow: hidden;
margin-left: -14rem; z-index: 10;
padding-top: 1rem; -webkit-transition: max-height 0.2s;
background-color: #f5f5f5;
border-bottom: 3px solid #ededed;
transition: max-height 0.15s ease-out;
} }
#station-container:hover { #station-container:hover {
max-height: 12rem; max-height: 30rem;
transition: max-height 0.25s ease-in; height: auto;
-webkit-transition: max-height 0.2s;
} }
#stations-container, #station #station-container {
#messages-container { padding-top: 1rem;
vertical-align: top; min-width: 30rem;
text-align: right;
} }
#messaging-container { #writing-container {
position: absolute; bottom: 4rem;
top: 4rem;
left: 50%;
width: 24rem;
margin-left: -12rem;
margin-bottom: 4rem;
}
#station > div {
display: inline-block;
}
#station-meta {
margin-right: 1rem;
margin-bottom: 1rem; margin-bottom: 1rem;
} }
#sources-container { #messages-container {
width: 6rem; vertical-align: top;
float: right; margin-top: 4rem;
margin: 1rem -6rem 0 0;
} }
#members { .caret,
margin-left: 2rem; .circle {
}
#station .iden {
display: block;
}
.station {
display: inline-block; display: inline-block;
width: 9rem;
margin-bottom: 0.3rem;
cursor: pointer;
font-weight: 200;
} }
#stations .station { .caret {
display: block; width: 0;
width: 24rem; height: 0;
} border-top: 6px solid transparent;
.station .name { border-right: 6px solid transparent;
padding: 0.3rem;
border-bottom: 6px solid transparent; border-bottom: 6px solid transparent;
border-left: 6px solid #000;
} }
.station .name:hover { .circle {
background-color: #f5f5f5; width: 6px;
border-bottom: 6px solid #ededed; height: 6px;
border: 3px solid #000;
border-radius: 6px;
} }
.station > div { #station-container #where .caret {
-webkit-transform: rotate(0deg);
-webkit-transform-origin: 0 50%;
-webkit-transition: -webkit-transform 0.2s;
}
#station-container:hover #where .caret {
transform: rotate(90deg);
transform-origin: 0 50%;
-webkit-transform: rotate(90deg);
-webkit-transition: -webkit-transform 0.2s;
}
#head {
width: 100%;
height: 4rem;
}
#station-container h1 {
font-weight: 500;
font-size: 0.6rem;
letter-spacing: 0.06rem;
display: inline-block;
line-height: 1.2rem;
}
#audience,
#who {
width: 34.6rem;
}
#stations,
#where {
width: 17.3rem;
}
#stations,
#audience,
#head > div {
display: inline-block;
text-align: right;
vertical-align: top;
}
#head > div {
height: 2rem;
margin-top: 1.5rem;
}
#where .caret {
border-left-color: #f00;
margin-left: 1rem;
}
#who > span {
margin-left: 1rem;
}
#members > div {
display: block;
}
#members > div div {
display: inline-block; display: inline-block;
} }
.toggle { #members .audi {
width: 0.4rem; margin-right: 0.3rem;
height: 0.4rem;
border: 2px solid #000;
margin-right: 0.6rem;
} }
.toggle.active { #members .iden {
background-color: #000; min-width: 6rem;
}
.station div {
display: inline-block;
} }
.station .remove { .station .remove {
display: none; opacity: 0;
float: right; cursor: pointer;
margin-left: 1rem; width: 0.6rem;
margin-right: 0.6rem;
font-weight: 600; font-weight: 600;
color: #f00; color: #f00;
} }
.station:hover .remove { .station:hover .remove {
display: inline; opacity: 1;
} }
#sources-container .station {
font-family: "scp";
font-weight: 500;
text-transform: lowercase;
}
.sour-ctrl {
margin-bottom: 0.16rem;
}
.join-ctrl input,
.sour-ctrl input { .sour-ctrl input {
font-family: "scp";
border: none; border: none;
font-weight: 400; font-weight: 400;
text-align: right;
line-height: 1rem;
outline: none;
cursor: pointer;
} }
.sour-ctrl input::-webkit-input-placeholder { .sour-ctrl input::-webkit-input-placeholder {
font-family: "bau"; font-family: "scp";
font-size: 1rem; font-size: 1rem;
font-weight: 200; font-weight: 600;
margin-left: 0.6rem; margin-left: 0.6rem;
color: #0003ff; color: #000;
}
.sour-ctrl input:focus::-webkit-input-placeholder {
color: #fff;
} }
.message { .message {
padding-top: 0.3rem; padding-top: 0.3rem;
@ -245,8 +291,9 @@ body {
#messages .message:hover .time { #messages .message:hover .time {
opacity: 1; opacity: 1;
} }
.time { #messages .message .ship,
margin-right: 0.6rem; #messages .message .audi > div {
cursor: pointer;
} }
.member { .member {
width: 12rem; width: 12rem;
@ -255,55 +302,82 @@ body {
#messages { #messages {
height: auto; height: auto;
} }
.message.pending {
color: #ccc;
}
.message.say .mess {
font-style: italic;
}
.mess, .mess,
.iden, .iden,
.attr > div,
#station .member div, #station .member div,
#writing { #writing {
display: inline-block; display: inline-block;
} }
.iden > div {
display: inline;
}
.mess, .mess,
#writing, #writing,
#length { #length {
vertical-align: top; vertical-align: top;
} }
.attr > div {
max-width: 16rem;
}
.attr { .attr {
color: #d7d7d7; text-align: right;
display: inline-block;
margin-right: 0.3rem;
min-width: 16rem;
} }
.attr .iden { .attr .iden {
color: #000; margin-left: 0.3rem;
} }
.attr > div { .audi {
white-space: nowrap;
}
.audi > div {
margin-right: 0.3rem; margin-right: 0.3rem;
max-width: 8rem;
}
.iden > div {
max-width: 16rem;
}
.iden > div,
.audi > div {
display: inline-block;
background-color: #fff;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-webkit-transition: max-height 0.2s;
}
.audi > div:last-child {
margin-right: 0;
}
.iden > div:hover,
.audi > div:hover {
position: relative;
max-width: 30rem;
-webkit-transition: max-height 0.2s;
} }
.mess { .mess {
font-size: 0.9rem; font-size: 0.9rem;
line-height: 1.6rem;
letter-spacing: 0.03rem; letter-spacing: 0.03rem;
word-wrap: break-word; word-wrap: break-word;
max-width: 31rem; max-width: 30rem;
margin-left: 0.3rem;
} }
.ship { #writing {
font-weight: 600; font-size: 0.9rem;
min-height: 1.6rem;
min-width: 1.3rem;
outline: none;
background-color: #eee;
padding: 0.3rem 0.1rem;
margin-left: 0.2rem;
margin-top: -0.3rem;
} }
.ship.talk:before { #writing:focus {
content: "..."; background-color: #fff;
margin-left: -1.3rem;
margin-right: 0.3rem;
width: 1rem;
margin-top: -0.4rem;
vertical-align: middle;
display: inline-block;
line-height: 0.2rem;
letter-spacing: -0.1rem;
}
#writing-container {
bottom: 4rem;
margin-bottom: 1rem;
float: left;
} }
.writing { .writing {
padding-top: 0.3rem; padding-top: 0.3rem;
@ -313,60 +387,25 @@ body {
margin-left: 1rem; margin-left: 1rem;
margin-top: 1.2rem; margin-top: 1.2rem;
} }
#writing { .writing .iden {
font-size: 0.9rem; display: block;
min-height: 1.6rem; text-align: right;
line-height: 1.6rem; width: 100%;
min-width: 1.3rem; }
padding: 0; .writing .iden .ship {
outline: none; margin-right: 0.3rem;
}
#audi {
display: inline-block;
background-color: #eee; background-color: #eee;
} padding: 0.3rem 0.1rem;
#writing:focus { margin-top: -0.3rem;
background-color: #fff; margin-right: -0.2rem;
}
#station h1 {
display: inline-block;
margin: 0;
font-weight: 200;
font-size: 2rem;
text-transform: lowercase;
}
input.join {
font-size: 4rem;
background-color: #fff;
outline: none; outline: none;
width: 24rem; overflow: hidden;
} }
#station input.join { #audi.valid-false {
font-family: "scp"; color: #ff2f2f;
font-size: 0.7rem;
line-height: 1rem;
width: 12rem;
}
input.join::-webkit-input-placeholder {
color: #0003ff;
}
input.join:focus::-webkit-input-placeholder {
color: #fff;
}
.pending {
color: #ccc;
}
a.up {
height: 2rem;
margin-top: 0.6rem;
vertical-align: middle;
display: inline-block;
}
.arow-up {
display: inline-block;
margin: 0 0.5rem 0 0.5rem;
width: 0;
height: 0;
border-left: 9px solid transparent;
border-right: 9px solid transparent;
border-bottom: 9px solid #000;
} }
#scrolling { #scrolling {
display: none; display: none;
@ -383,67 +422,45 @@ a.up {
font-size: 0.8rem; font-size: 0.8rem;
text-transform: uppercase; text-transform: uppercase;
} }
@media (max-width: 40rem) { @media only screen and (max-width: 1170px) {
#c { #c,
#station-container {
width: 96%;
left: 0; left: 0;
margin-left: 0; margin-left: 2%;
width: 24rem; margin-right: 2%;
} }
#messages-container, .mess,
#writing-container { #writing {
margin-left: 1rem; max-width: 40%;
line-height: 1.2rem;
} }
#stations-container, .attr,
#station-container { #stations,
position: relative; #where {
float: left; width: 20%;
min-width: 20%;
} }
#stations-container { #audience,
width: 8rem; #who {
} width: 60%;
#station-container {
left: auto;
}
.station {
width: 5rem;
}
.attr {
display: block;
text-align: left;
width: 2rem;
margin-right: 1rem;
}
.message {
height: 1.6rem;
}
.stations,
.iden,
#station {
font-size: 0.5rem;
}
.station .remove {
display: inline;
font-size: 0.6rem;
line-height: 0.6rem;
}
.ship.talk:before {
margin-left: -0.3rem;
margin-right: 0;
}
.attr {
width: 4rem;
}
.iden > div {
display: block;
}
.attr > .time {
display: none;
}
.mess {
max-width: 12rem;
margin-bottom: 1rem;
} }
#writing { #writing {
max-width: 12rem; padding: 0.1rem;
}
.m-down,
.m-up {
position: absolute;
}
.m-down.m-fixed {
position: fixed;
top: 0;
}
}
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
.mess,
#writing {
max-width: 70%;
line-height: 1.2rem;
} }
} }

View File

@ -1,9 +1,16 @@
//
// fonts first
//
@import 'fonts' @import 'fonts'
.iden .iden
.audi .audi
.time .time
#length #length
#where
#who
.station
font-family "scp" font-family "scp"
.join-ctrl input .join-ctrl input
@ -30,10 +37,17 @@ input.join
#station #station
font-size .7rem font-size .7rem
.iden
font-weight 600
html html
body body
font-size 18px font-size 18px
//
// containers
//
body body
background-color #fefefe background-color #fefefe
padding 0 padding 0
@ -43,125 +57,165 @@ body
display none display none
#c #c
top 0
background-color #fff
#stations-container
position absolute position absolute
top 1rem top 0rem
left 50% left 50%
width 24rem width 58rem
margin-left -12rem margin-left -29rem
font-size 4rem margin-bottom 12rem
#station-container #station-container
position fixed position fixed
top 0 width 58rem
left 50% max-height 2.7rem
width 28rem background-color white
max-height 2.6rem border-bottom .3rem solid black
padding-bottom 1rem
overflow hidden overflow hidden
margin-left -14rem z-index 10
padding-top 1rem -webkit-transition max-height .2s
background-color #f5f5f5
border-bottom 3px solid #ededed
transition max-height 0.15s ease-out
#station-container:hover #station-container:hover
max-height 12rem max-height 30rem
transition max-height 0.25s ease-in height auto
-webkit-transition max-height .2s
#stations-container #station #station-container
#messages-container padding-top 1rem
vertical-align top min-width 30rem
text-align right
#messaging-container #writing-container
position absolute bottom 4rem
top 4rem
left 50%
width 24rem
margin-left -12rem
margin-bottom 4rem
#station > div
display inline-block
#station-meta
margin-right 1rem
margin-bottom 1rem margin-bottom 1rem
#sources-container #messages-container
width 6rem vertical-align top
float right margin-top 4rem
margin 1rem -6rem 0 0
#members //
margin-left 2rem // components
//
#station .iden .caret
display block .circle
.station
display inline-block display inline-block
width 9rem
margin-bottom .3rem
cursor pointer
font-weight 200
#stations .station .caret
display block width 0
width 24rem height 0
border-top 6px solid transparent
.station .name border-right 6px solid transparent
padding .3rem
border-bottom 6px solid transparent border-bottom 6px solid transparent
border-left 6px solid #000
.station .name:hover .circle
background-color #f5f5f5 width 6px
border-bottom 6px solid #ededed height 6px
border 3px solid black
border-radius 6px
.station > div //
// station
//
#station-container #where .caret
-webkit-transform rotate(0deg)
-webkit-transform-origin 0 50%
-webkit-transition -webkit-transform .2s
#station-container:hover #where .caret
transform rotate(90deg)
transform-origin 0 50%
-webkit-transform rotate(90deg)
-webkit-transition -webkit-transform .2s
#head
width 100%
height 4rem
#station-container h1
font-weight 500
font-size .6rem
letter-spacing .06rem
display inline-block
line-height 1.2rem
#audience
#who
width 34.6rem
#stations
#where
width 17.3rem
#stations
#audience
#head > div
display inline-block
text-align right
vertical-align top
#head > div
height 2rem
margin-top 1.5rem
#where .caret
border-left-color red
margin-left 1rem
#who > span
margin-left 1rem
#members > div
display block
#members > div div
display inline-block display inline-block
.toggle #members .audi
width .4rem margin-right .3rem
height .4rem
border 2px solid #000
margin-right .6rem
.toggle.active #members .iden
background-color #000 min-width 6rem
.station div
display inline-block
.station .remove .station .remove
display none opacity 0
float right cursor pointer
margin-left 1rem width .6rem
margin-right .6rem
font-weight 600 font-weight 600
color #ff0000 color #ff0000
.station:hover .remove .station:hover .remove
display inline opacity 1
#sources-container .station // add source
font-family "scp"
font-weight 500
text-transform lowercase
// hate this.
.sour-ctrl
margin-bottom .16rem
.join-ctrl input
.sour-ctrl input .sour-ctrl input
font-family "scp"
border none border none
font-weight 400 font-weight 400
text-align right
line-height 1rem
outline none
cursor pointer
.sour-ctrl input::-webkit-input-placeholder .sour-ctrl input::-webkit-input-placeholder
font-family "bau" font-family "scp"
font-size 1rem font-size 1rem
font-weight 200 font-weight 600
margin-left .6rem margin-left .6rem
color #0003FF color #000
.sour-ctrl input:focus::-webkit-input-placeholder
color white
//
// messages
//
.message .message
padding-top .3rem padding-top .3rem
@ -176,8 +230,9 @@ body
#messages .message:hover .time #messages .message:hover .time
opacity 1 opacity 1
.time #messages .message .ship
margin-right .6rem #messages .message .audi > div
cursor pointer
.member .member
width 12rem width 12rem
@ -186,55 +241,86 @@ body
#messages #messages
height auto height auto
.message.pending
color #ccc
.message.say .mess
font-style italic
.mess .mess
.iden .iden
.attr > div
#station .member div #station .member div
#writing #writing
display inline-block display inline-block
.iden > div
display inline
.mess .mess
#writing #writing
#length #length
vertical-align top vertical-align top
.attr > div
max-width 16rem
.attr .attr
color #D7D7D7 text-align right
display inline-block
margin-right .3rem
min-width 16rem
.attr .iden .attr .iden
color #000 margin-left .3rem
.attr > div .audi
white-space nowrap
.audi > div
margin-right .3rem margin-right .3rem
max-width 8rem
.iden > div
max-width 16rem
.iden > div
.audi > div
display inline-block
background-color white
overflow hidden
white-space nowrap
text-overflow ellipsis
-webkit-transition max-height .2s
.audi > div:last-child
margin-right 0
.iden > div:hover
.audi > div:hover
position relative
max-width 30rem
-webkit-transition max-height .2s
.mess .mess
font-size .9rem font-size .9rem
line-height 1.6rem
letter-spacing .03rem letter-spacing .03rem
word-wrap break-word word-wrap break-word
max-width 31rem max-width 30rem
margin-left .3rem
.ship //
font-weight 600 // writing
//
.ship.talk:before #writing
content "..." font-size .9rem
margin-left -1.3rem min-height 1.6rem
margin-right .3rem min-width 1.3rem
width 1rem outline none
margin-top -.4rem background-color #eee
vertical-align middle padding .3rem .1rem
display inline-block margin-left .2rem
line-height .2rem margin-top -.3rem
letter-spacing -.1rem
#writing-container #writing:focus
bottom 4rem background-color #fff
margin-bottom 1rem
float left
.writing .writing
padding-top .3rem padding-top .3rem
@ -244,60 +330,29 @@ body
margin-left 1rem margin-left 1rem
margin-top 1.2rem margin-top 1.2rem
#writing .writing .iden
font-size .9rem display block
min-height 1.6rem text-align right
line-height 1.6rem width 100%
min-width 1.3rem
padding 0 .writing .iden .ship
outline none margin-right .3rem
#audi
display inline-block
background-color #eee background-color #eee
padding .3rem .1rem
#writing:focus margin-top -.3rem
background-color #fff margin-right -.2rem
#station h1
display inline-block
margin 0
font-weight 200
font-size 2rem
text-transform lowercase
input.join
font-size 4rem
background-color #fff
outline none outline none
width 24rem overflow hidden
#station input.join #audi.valid-false
font-family "scp" color #ff2f2f
font-size .7rem
line-height 1rem
width 12rem
input.join::-webkit-input-placeholder //
color #0003FF // scrolling
//
input.join:focus::-webkit-input-placeholder
color #fff
.pending
color #ccc
a.up
height 2rem
margin-top .6rem
vertical-align middle
display inline-block
.arow-up
display inline-block
margin 0 .5rem 0 .5rem
width 0
height 0
border-left 9px solid transparent
border-right 9px solid transparent
border-bottom 9px solid #000
#scrolling #scrolling
display none display none
@ -314,66 +369,4 @@ a.up
font-size .8rem font-size .8rem
text-transform uppercase text-transform uppercase
@media (max-width: 40rem) @import 'mobile'
#c
left 0
margin-left 0
width 24rem
#messages-container
#writing-container
margin-left 1rem
#stations-container
#station-container
position relative
float left
#stations-container
width 8rem
#station-container
left auto
.station
width 5rem
.attr
display block
text-align left
width 2rem
margin-right 1rem
.message
height 1.6rem
.stations
.iden
#station
font-size .5rem
.station .remove
display inline
font-size .6rem
line-height .6rem
.ship.talk:before
margin-left -.3rem
margin-right 0
.attr
width 4rem
.iden > div
display block
.attr > .time
display none
.mess
max-width 12rem
margin-bottom 1rem
#writing
max-width 12rem

View File

@ -0,0 +1,44 @@
/* laptops / small screens ----------- */
@media only screen and (max-width: 1170px)
#c
#station-container
width 96%
left 0
margin-left 2%
margin-right 2%
.mess
#writing
max-width 40%
line-height 1.2rem
.attr
#stations
#where
width 20%
min-width 20%
#audience
#who
width 60%
#writing
padding .1rem
.m-down
.m-up
position absolute
.m-down.m-fixed
position fixed
top 0
/* tablets + phones ----------- */
// @media only screen and (min-width: 320px) and (max-width: 1024px)
/* phones portrait and landscape ----------- */
@media only screen and (min-device-width: 320px) and (max-device-width: 480px)
.mess
#writing
max-width 70%
line-height 1.2rem

View File

@ -1,7 +1,5 @@
MessageDispatcher = require '../dispatcher/Dispatcher.coffee' MessageDispatcher = require '../dispatcher/Dispatcher.coffee'
# hm
module.exports = module.exports =
loadMessages: (grams,get) -> loadMessages: (grams,get) ->
MessageDispatcher.handleServerAction MessageDispatcher.handleServerAction
@ -29,12 +27,11 @@ module.exports =
type:"messages-fetch" type:"messages-fetch"
window.chat.MessagePersistence.get station,start,end window.chat.MessagePersistence.get station,start,end
sendMessage: (station,message,audience) -> sendMessage: (message,audience) ->
serial = window.util.uuid32() serial = window.util.uuid32()
if station[0] isnt "~" then station = "~"+window.urb.ship+"/"+station audience.push window.util.mainStationPath window.urb.user
audience = _.uniq audience
if audience.length is 0 then audience.push station
_audi = {} _audi = {}
for k,v of audience for k,v of audience
@ -53,10 +50,14 @@ module.exports =
bouquet:[] bouquet:[]
speech: speech:
lin: lin:
say:false say:true
txt:message txt:message
date: Date.now() date: Date.now()
if message[0] is "@"
_message.thought.statement.speech.lin.txt = _message.thought.statement.speech.lin.txt.slice(1).trim()
_message.thought.statement.speech.lin.say = false
MessageDispatcher.handleViewAction MessageDispatcher.handleViewAction
type:"message-send" type:"message-send"
message:_message message:_message

View File

@ -17,6 +17,11 @@ module.exports =
type:"station-set-audience" type:"station-set-audience"
audience:audience audience:audience
setValidAudience: (valid) ->
StationDispatcher.handleViewAction
type:"station-set-valid-audience"
valid:valid
toggleAudience: (station) -> toggleAudience: (station) ->
StationDispatcher.handleViewAction StationDispatcher.handleViewAction
type:"station-audience-toggle" type:"station-audience-toggle"
@ -53,11 +58,10 @@ module.exports =
type:"stations-load" type:"stations-load"
stations:stations stations:stations
loadMembers: (station,members) -> loadMembers: (members) ->
StationDispatcher.handleServerAction StationDispatcher.handleServerAction
type:"members-load" type:"members-load"
members:members members:members
station:station
createStation: (station) -> createStation: (station) ->
StationDispatcher.handleViewAction StationDispatcher.handleViewAction

View File

@ -1,12 +1,12 @@
moment = require 'moment-timezone' moment = require 'moment-timezone'
recl = React.createClass recl = React.createClass
[div,input,textarea] = [React.DOM.div,React.DOM.input,React.DOM.textarea] [div,br,input,textarea] = [React.DOM.div,React.DOM.br,React.DOM.input,React.DOM.textarea]
MessageStore = require '../stores/MessageStore.coffee'
StationStore = require '../stores/StationStore.coffee'
MessageActions = require '../actions/MessageActions.coffee' MessageActions = require '../actions/MessageActions.coffee'
MessageStore = require '../stores/MessageStore.coffee'
StationActions = require '../actions/StationActions.coffee' StationActions = require '../actions/StationActions.coffee'
StationStore = require '../stores/StationStore.coffee'
Member = require './MemberComponent.coffee' Member = require './MemberComponent.coffee'
Message = recl Message = recl
@ -19,24 +19,31 @@ Message = recl
s = @lz d.getSeconds() s = @lz d.getSeconds()
"~#{h}.#{m}.#{s}" "~#{h}.#{m}.#{s}"
_handleAudi: (e) ->
audi = _.map $(e.target).closest('.audi').find('div'), (div) -> return $(div).text()
@props._handleAudi audi
_handlePm: (e) ->
return if not @props._handlePm
user = $(e.target).closest('.iden').text().slice(1)
@props._handlePm user
render: -> render: ->
# pendingClass = if @props.pending isnt "received" then "pending" else "" # pendingClass = if @props.pending isnt "received" then "pending" else ""
delivery = _.uniq _.pluck @props.thought.audience, "delivery" delivery = _.uniq _.pluck @props.thought.audience, "delivery"
pendingClass = if delivery.indexOf("received") isnt -1 then "received" else "pending" klass = if delivery.indexOf("received") isnt -1 then " received" else " pending"
if @props.thought.statement.speech.lin.say is false then klass += " say"
if pendingClass is "pending"
console.log @props.thought
console.log delivery
name = if @props.name then @props.name else "" name = if @props.name then @props.name else ""
audi = _.remove _.keys(@props.thought.audience), (stat) => audi = _.keys @props.thought.audience
stat isnt "~"+window.urb.ship+"/"+@props.station audi = _.without audi,window.util.mainStationPath window.urb.user
audi = audi.join " " audi = window.util.clipAudi audi
audi = audi.map (_audi) -> (div {}, _audi)
div {className:"message "+pendingClass}, [ div {className:"message #{klass}"}, [
(div {className:"attr"}, [ (div {className:"attr"}, [
(Member {ship:@props.ship}, "") div {onClick:@_handleAudi,className:"audi"}, audi
div {className:"audi"}, "#{audi}" (div {onClick:@_handlePm}, (Member {ship:@props.ship}, ""))
div {className:"time"}, @convTime @props.thought.statement.date div {className:"time"}, @convTime @props.thought.statement.date
]) ])
div {className:"mess"}, @props.thought.statement.speech.lin.txt div {className:"mess"}, @props.thought.statement.speech.lin.txt
@ -51,7 +58,7 @@ module.exports = recl
last:MessageStore.getLast() last:MessageStore.getLast()
fetching:MessageStore.getFetching() fetching:MessageStore.getFetching()
listening:MessageStore.getListening() listening:MessageStore.getListening()
station:StationStore.getStation() station:window.util.mainStation()
stations:StationStore.getStations() stations:StationStore.getStations()
configs:StationStore.getConfigs() configs:StationStore.getConfigs()
typing:MessageStore.getTyping() typing:MessageStore.getTyping()
@ -78,7 +85,8 @@ module.exports = recl
componentDidMount: -> componentDidMount: ->
MessageStore.addChangeListener @_onChangeStore MessageStore.addChangeListener @_onChangeStore
StationStore.addChangeListener @_onChangeStore StationStore.addChangeListener @_onChangeStore
if @state.station and @state.listening.indexOf(@state.station) is -1 if @state.station and
@state.listening.indexOf(@state.station) is -1
MessageActions.listenStation @state.station MessageActions.listenStation @state.station
checkMore = @checkMore checkMore = @checkMore
$(window).on 'scroll', checkMore $(window).on 'scroll', checkMore
@ -101,14 +109,25 @@ module.exports = recl
_onChangeStore: -> @setState @stateFromStore() _onChangeStore: -> @setState @stateFromStore()
_handlePm: (user) ->
audi = [
window.util.mainStationPath(user)
window.util.mainStationPath(window.urb.user)
]
if user is window.urb.user then audi.pop()
StationActions.setAudience audi
_handleAudi: (audi) -> StationActions.setAudience audi
render: -> render: ->
station = @state.station station = @state.station
_station = "~"+window.urb.ship+"/"+station _station = "~"+window.urb.ship+"/"+station
sources = _.clone @state.configs[@state.station]?.sources ? [] sources = _.clone @state.configs[@state.station]?.sources ? []
sources.push _station sources.push _station
_messages = _.filter @state.messages, (_message) -> _messages = @state.messages
audience = _.keys(_message.thought.audience) # _messages = _.filter @state.messages, (_message) ->
_.intersection(sources,audience).length > 0 # audience = _.keys(_message.thought.audience)
# _.intersection(sources,audience).length > 0
_messages = _.sortBy _messages, (_message) -> _messages = _.sortBy _messages, (_message) ->
_message.pending = _message.thought.audience[station] _message.pending = _message.thought.audience[station]
_message.thought.statement.time _message.thought.statement.time
@ -122,5 +141,7 @@ module.exports = recl
messages = _messages.map (_message) => messages = _messages.map (_message) =>
_message.station = @state.station _message.station = @state.station
_message._handlePm = @_handlePm
_message._handleAudi = @_handleAudi
Message _message, "" Message _message, ""
div {id: "messages"}, messages div {id: "messages"}, messages

View File

@ -1,15 +0,0 @@
recl = React.createClass
[div,input,textarea] = [React.DOM.div,React.DOM.input,React.DOM.textarea]
StationComponent = require './StationComponent.coffee'
MessagesComponent = require './MessagesComponent.coffee'
WritingComponent = require './WritingComponent.coffee'
module.exports = recl
render: ->
div {id:"d"}, "asdf"
# div {id:"d"}, [
# (div {id:'station-container'}, (StationComponent {}, ""))
# (div {id:'messages-container'}, (MessagesComponent {}, ""))
# (div {id:'writing-container'}, (WritingComponent {}, ""))
# ]

View File

@ -15,7 +15,7 @@ module.exports = recl
stateFromStore: -> { stateFromStore: -> {
audi:StationStore.getAudience() audi:StationStore.getAudience()
members:StationStore.getMembers() members:StationStore.getMembers()
station:StationStore.getStation() station:window.util.mainStation()
stations:StationStore.getStations() stations:StationStore.getStations()
configs:StationStore.getConfigs() configs:StationStore.getConfigs()
typing:StationStore.getTyping() typing:StationStore.getTyping()
@ -35,10 +35,6 @@ module.exports = recl
componentWillUnmount: -> componentWillUnmount: ->
StationStore.removeChangeListener @_onChangeStore StationStore.removeChangeListener @_onChangeStore
_toggleAudi: (e) ->
$e = $(e.target).closest('.station')
station = $e.find('.path').text()
StationActions.toggleAudience station
_onChangeStore: -> _onChangeStore: ->
@setState @stateFromStore() @setState @stateFromStore()
@ -51,22 +47,24 @@ module.exports = recl
_sources.push v _sources.push v
StationActions.setSources @state.station,_sources StationActions.setSources @state.station,_sources
@$input.val('') @$input.val('')
@$input.blur()
_remove: (e) -> _remove: (e) ->
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
_station = $(e.target).attr "data-station" _station = $(e.target).attr "data-station"
_sources = _.clone @state.configs[@state.station].sources _sources = _.clone @state.configs[@state.station].sources
_sources.slice _sources.indexOf(_station),1 _sources.splice _sources.indexOf(_station),1
StationActions.setSources @state.station,_sources StationActions.setSources @state.station,_sources
render: -> render: ->
parts = [] parts = []
members = [] members = []
if @state.station and @state.members[@state.station] if @state.station and @state.members
members = _.map @state.members[@state.station], (state,member) -> members = _.map @state.members, (stations,member) ->
Member {ship:member,presence:state.presence} audi = _.map stations,(presence,station) -> (div {className:"audi"}, station)
(div {}, [audi,Member {ship:member}])
else else
members = "" members = ""
@ -77,25 +75,22 @@ module.exports = recl
if @state.station and @state.configs[@state.station] if @state.station and @state.configs[@state.station]
_remove = @_remove _remove = @_remove
_sources = _.clone @state.configs[@state.station].sources _sources = _.clone @state.configs[@state.station].sources
_sources.push "twitter/hoontap"
sources = _.map _sources,(source) => sources = _.map _sources,(source) =>
toggleClass = "toggle " (div {className:"station"}, [
if @state.audi.indexOf(source) isnt -1 then toggleClass += "active" (div {className:"remove",onClick:_remove,"data-station":source},"×"),
(div {className:"station",onClick:@_toggleAudi}, [ (div {className:"path"}, source)
(div {className:toggleClass})
(div {className:"path"}, source),
(div {className:"remove",onClick:_remove,"data-station":source},"×")
]) ])
else else
sources = "" sources = ""
station = [] head = (div {id:"head"},
station.push (a {className:"up",href:"\#/"}, [(div {className:"arow-up"}, "")]) [(div {id:"where"},["/talk",(div {className:"caret"},"")]),
station.push (h1 {},@state.station) (div {id:"who"},[(div {className:"circle"},""),"~#{window.urb.user}"])
station.push (div {id:"members"},members) ]
)
parts.push (div {id:"station-container"}, (div {id:"station-meta"},station)) parts.push head
parts.push (div {id:"sources-container"}, [(div {class:"sources-list"},sources),sourceCtrl]) parts.push (div {id:"stations"}, [(h1 {}, "Sources"),(div {},sources),sourceCtrl])
parts.push (div {id:"audience"}, (div {},[(h1 {}, "Audience"),(div {id:"members"},members)]))
div {id:"station"},parts div {id:"station"},parts

View File

@ -7,15 +7,15 @@ StationActions = require '../actions/StationActions.coffee'
module.exports = recl module.exports = recl
stateFromStore: -> { stateFromStore: -> {
stations: StationStore.getStations() stations: StationStore.getStations()
station: StationStore.getStation() station: "~zod/court"
} }
getInitialState: -> @stateFromStore() getInitialState: -> @stateFromStore()
componentDidMount: -> componentDidMount: ->
@$el = $(@getDOMNode()) @$el = $ @getDOMNode()
@$add = $('#stations .add') @$add = $ '#stations .add'
@$input = @$el.find('input') @$input = @$el.find 'input'
StationStore.addChangeListener @_onChangeStore StationStore.addChangeListener @_onChangeStore
componentWillUnmount: -> componentWillUnmount: ->

View File

@ -1,7 +1,8 @@
recl = React.createClass recl = React.createClass
[div,input,textarea] = [React.DOM.div,React.DOM.input,React.DOM.textarea] [div,br,input,textarea] = [React.DOM.div,React.DOM.br,React.DOM.input,React.DOM.textarea]
MessageActions = require '../actions/MessageActions.coffee' MessageActions = require '../actions/MessageActions.coffee'
MessageStore = require '../stores/MessageStore.coffee'
StationActions = require '../actions/StationActions.coffee' StationActions = require '../actions/StationActions.coffee'
StationStore = require '../stores/StationStore.coffee' StationStore = require '../stores/StationStore.coffee'
Member = require './MemberComponent.coffee' Member = require './MemberComponent.coffee'
@ -13,12 +14,16 @@ module.exports = recl
get: -> get: ->
if window.localStorage then window.localStorage.getItem 'writing' if window.localStorage then window.localStorage.getItem 'writing'
stateFromStore: -> { stateFromStore: ->
s =
audi:StationStore.getAudience() audi:StationStore.getAudience()
ludi:MessageStore.getLastAudience()
members:StationStore.getMembers() members:StationStore.getMembers()
typing:StationStore.getTyping() typing:StationStore.getTyping()
station:StationStore.getStation() valid:StationStore.getValidAudience()
} s.audi = _.without s.audi, window.util.mainStationPath window.urb.user
s.ludi = _.without s.ludi, window.util.mainStationPath window.urb.user
s
getInitialState: -> @stateFromStore() getInitialState: -> @stateFromStore()
@ -35,13 +40,30 @@ module.exports = recl
@typing true @typing true
sendMessage: -> sendMessage: ->
MessageActions.sendMessage @state.station,@$writing.text(),@state.audi if @_validateAudi() is false
$('#audi').focus()
return
if @state.audi.length is 0 and $('#audi').text().trim().length > 0
audi = @state.ludi
@_setAudi()
else
audi = @state.audi
audi = window.util.expandAudi audi
MessageActions.sendMessage @$writing.text().trim(),audi
@$length.text "0/69" @$length.text "0/69"
@$writing.text('') @$writing.text('')
@set() @set()
@typing false @typing false
_keyDown: (e) -> _audiKeyDown: (e) ->
if e.keyCode is 13
e.preventDefault()
setTimeout () ->
$('#writing').focus()
,0
return false
_writingKeyDown: (e) ->
if e.keyCode is 13 if e.keyCode is 13
e.preventDefault() e.preventDefault()
@sendMessage() @sendMessage()
@ -67,6 +89,40 @@ module.exports = recl
_setFocus: -> @$writing.focus() _setFocus: -> @$writing.focus()
_validateAudiPart: (a) ->
if a[0] isnt "~"
return false
if a.indexOf("/") isnt -1
_a = a.split("/")
if _a[1].length is 0
return false
ship = _a[0]
else
ship = a
if ship.length < 3
return false
return true
_validateAudi: ->
v = $('#audi').text()
v = v.trim()
if v.length is 0
return true
v = v.split " "
for a in v
a = a.trim()
valid = @_validateAudiPart(a)
valid
_setAudi: ->
valid = @_validateAudi()
StationActions.setValidAudience valid
if valid is true
v = $('#audi').text()
v = v.split " "
v = window.util.expandAudi v
StationActions.setAudience v
getTime: -> getTime: ->
d = new Date() d = new Date()
seconds = d.getSeconds() seconds = d.getSeconds()
@ -85,6 +141,7 @@ module.exports = recl
componentDidMount: -> componentDidMount: ->
window.util.sendMessage = @sendMessage window.util.sendMessage = @sendMessage
StationStore.addChangeListener @_onChangeStore StationStore.addChangeListener @_onChangeStore
MessageStore.addChangeListener @_onChangeStore
@$el = $ @getDOMNode() @$el = $ @getDOMNode()
@$length = $('#length') @$length = $('#length')
@$writing = $('#writing') @$writing = $('#writing')
@ -108,11 +165,20 @@ module.exports = recl
ship = if iden then iden.ship else user ship = if iden then iden.ship else user
name = if iden then iden.name else "" name = if iden then iden.name else ""
k = "writing" audi = if @state.audi.length is 0 then @state.ludi else @state.audi
k+= " hidden" if not @state?.station audi = window.util.clipAudi audi
div {className:k,onClick:@_setFocus}, [ k = "writing"
div {className:k}, [
(div {className:"attr"}, [ (div {className:"attr"}, [
(div {
id:"audi"
className:"audi valid-#{@state.valid}"
contentEditable:true
onKeyDown: @_audiKeyDown
onBlur:@_setAudi
}, audi.join(" "))
(Member iden, "") (Member iden, "")
(div {className:"time"}, @getTime()) (div {className:"time"}, @getTime())
]) ])
@ -123,7 +189,7 @@ module.exports = recl
onBlur: @_blur onBlur: @_blur
onInput: @_input onInput: @_input
onPaste: @_input onPaste: @_input
onKeyDown: @_keyDown onKeyDown: @_writingKeyDown
onFocus: @cursorAtEnd onFocus: @cursorAtEnd
}, "") }, "")
div {id:"length"}, "0/69" div {id:"length"}, "0/69"

View File

@ -8,15 +8,33 @@ $(() ->
window.chat.StationPersistence = require './persistence/StationPersistence.coffee' window.chat.StationPersistence = require './persistence/StationPersistence.coffee'
window.util = window.util =
mainStation: -> mainStations: ["court","floor","porch"]
switch window.urb.user.length
mainStationPath: (user) -> "~#{user}/#{window.util.mainStation(user)}"
mainStation: (user) ->
if not user then user = window.urb.user
switch user.length
when 3 when 3
return "court" return "court"
when 5 when 6
return "floor" return "floor"
when 13 when 13
return "porch" return "porch"
clipAudi: (audi) ->
audi = audi.join " "
for v in window.util.mainStations
regx = new RegExp "/#{v}","g"
audi = audi.replace regx,""
audi.split " "
expandAudi: (audi) ->
for k,v of audi
if v.indexOf("/") is -1
audi[k] = "#{v}/#{window.util.mainStation(v.slice(1))}"
audi
create: (name) -> create: (name) ->
window.chat.StationPersistence.createStation name, (err,res) -> window.chat.StationPersistence.createStation name, (err,res) ->
@ -54,8 +72,7 @@ $(() ->
send() send()
getScroll: -> getScroll: ->
@writingPosition = $('#messaging-container').outerHeight(true)+$('#messaging-container').offset().top-$(window).height() @writingPosition = $('#c').outerHeight(true)+$('#c').offset().top-$(window).height()
#@writingPosition = $('#writing-container').position().top-$(window).height()+$('#writing-container').outerHeight(true)
setScroll: -> setScroll: ->
window.util.getScroll() window.util.getScroll()
@ -69,43 +86,92 @@ $(() ->
else else
$('body').removeClass 'scrolling' $('body').removeClass 'scrolling'
# checkScroll = ->
# if $(window).scrollTop() > 20
# $('#nav').addClass 'scrolling'
# else
# $('#nav').removeClass 'scrolling'
# setInterval checkScroll, 500
so = {}
so.ls = $(window).scrollTop()
so.cs = $(window).scrollTop()
so.w = null
so.$n = $('#station-container')
so.$d = $('#nav > div')
so.nh = so.$n.outerHeight(true)
setSo = ->
so.$n = $('#station-container')
so.w = $(window).width()
setInterval setSo,200
$(window).on 'resize', (e) ->
if so.w > 1170
so.$n.removeClass 'm-up m-down m-fixed'
$(window).on 'scroll', (e) ->
so.cs = $(window).scrollTop()
if so.w > 1170
so.$n.removeClass 'm-up m-down m-fixed'
if so.w < 1170
dy = so.ls-so.cs
so.$d.removeClass 'focus'
if so.cs <= 0
so.$n.removeClass 'm-up'
so.$n.addClass 'm-down m-fixed'
return
if so.$n.hasClass 'm-fixed' and
so.w < 1024
so.$n.css left:-1*$(window).scrollLeft()
if dy > 0
if not so.$n.hasClass 'm-down'
so.$n.removeClass('m-up').addClass 'm-down'
top = so.cs-so.nh
if top < 0 then top = 0
so.$n.offset top:top
if so.$n.hasClass('m-down') and
not so.$n.hasClass('m-fixed') and
so.$n.offset().top >= so.cs
so.$n.addClass 'm-fixed'
so.$n.attr {style:''}
if dy < 0
if not so.$n.hasClass 'm-up'
so.$n.removeClass('m-down m-fixed').addClass 'm-up'
so.$n.attr {style:''}
top = so.cs
sto = so.$n.offset().top
if top < 0 then top = 0
if top > sto and top < sto+so.nh then top = sto
so.$n.offset top:top
so.ls = so.cs
$(window).on 'scroll', window.util.checkScroll $(window).on 'scroll', window.util.checkScroll
window.chat.StationPersistence.listen() window.chat.StationPersistence.listen()
StationComponent = require './components/StationComponent.coffee' StationComponent = require './components/StationComponent.coffee'
StationsComponent = require './components/StationsComponent.coffee'
MessagesComponent = require './components/MessagesComponent.coffee' MessagesComponent = require './components/MessagesComponent.coffee'
WritingComponent = require './components/WritingComponent.coffee' WritingComponent = require './components/WritingComponent.coffee'
$c = $('#c') $c = $('#c')
clean = -> clean = ->
React.unmountComponentAtNode $('#stations-container')[0] React.unmountComponentAtNode $('#station-container')[0]
React.unmountComponentAtNode $('#station-parts-container')[0]
React.unmountComponentAtNode $('#writing-container')[0]
React.unmountComponentAtNode $('#messages-container')[0] React.unmountComponentAtNode $('#messages-container')[0]
React.unmountComponentAtNode $('#writing-container')[0]
routes = $c.append "<div id='station-container'></div>"
'': -> $c.append "<div id='messages-container'></div>"
clean() $c.append "<div id='writing-container'></div>"
$c.html "<div id='stations-container'></div>" $c.append "<div id='scrolling'>BOTTOM</div>"
rend (StationsComponent {}, ""),$('#stations-container')[0] rend (StationComponent {}, ""),$('#station-container')[0]
'/:station': (station) ->
clean()
StationActions.switchStation station
$c.html ""
$c.append("<div id='messaging-container'></div>")
$d = $('#messaging-container')
$d.append("<div id='messages-container'></div>")
$d.append("<div id='writing-container'></div>")
$d.append("<div id='station-parts-container'></div>")
$c.append("<div id='scrolling'>BOTTOM</div>")
rend (StationComponent {}, ""),$('#station-parts-container')[0]
rend (MessagesComponent {}, ""),$('#messages-container')[0] rend (MessagesComponent {}, ""),$('#messages-container')[0]
rend (WritingComponent {}, ""),$('#writing-container')[0] rend (WritingComponent {}, ""),$('#writing-container')[0]
router = Router routes
if not window.location.hash then window.location.hash = "/"
router.init()
) )

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,10 @@
{ {
"name": "urbit-radio", "name": "urbit-radio",
"version": "0.0.0", "version": "0.0.0",
"repository": {
"type":"git",
"url":"https://github.com/urbit/urbit"
},
"description": "urbit radio frontend", "description": "urbit radio frontend",
"main": "main.js", "main": "main.js",
"dependencies": { "dependencies": {

View File

@ -3,7 +3,7 @@ MessageActions = require '../actions/MessageActions.coffee'
module.exports = module.exports =
listenStation: (station,since) -> listenStation: (station,since) ->
window.urb.subscribe { window.urb.subscribe {
appl:"rodeo" appl:"radio"
path:"/f/#{station}/#{since}" path:"/f/#{station}/#{since}"
}, (err,res) -> }, (err,res) ->
console.log('m subscription updates') console.log('m subscription updates')
@ -15,7 +15,7 @@ module.exports =
get: (station,start,end) -> get: (station,start,end) ->
window.urb.subscribe { window.urb.subscribe {
appl:"rodeo" appl:"radio"
path:"/f/#{station}/#{end}/#{start}" path:"/f/#{station}/#{end}/#{start}"
}, (err,res) -> }, (err,res) ->
console.log 'get' console.log 'get'
@ -23,7 +23,7 @@ module.exports =
if res.data?.grams?.tele if res.data?.grams?.tele
MessageActions.loadMessages res.data.grams,true MessageActions.loadMessages res.data.grams,true
window.urb.unsubscribe { window.urb.unsubscribe {
appl:"rodeo" appl:"radio"
path:"/f/#{station}/#{end}/#{start}" path:"/f/#{station}/#{end}/#{start}"
}, (err,res) -> }, (err,res) ->
console.log 'done' console.log 'done'
@ -31,8 +31,8 @@ module.exports =
sendMessage: (message,cb) -> sendMessage: (message,cb) ->
window.urb.send { window.urb.send {
appl:"rodeo" appl:"radio"
mark:"rodeo-command" mark:"radio-command"
data: data:
publish: [ publish: [
message message

View File

@ -3,8 +3,8 @@ StationActions = require '../actions/StationActions.coffee'
module.exports = module.exports =
createStation: (name,cb) -> createStation: (name,cb) ->
window.urb.send { window.urb.send {
appl:"rodeo" appl:"radio"
mark:"rodeo-command" mark:"radio-command"
data: data:
design: design:
party:name party:name
@ -16,8 +16,8 @@ module.exports =
removeStation: (name,cb) -> removeStation: (name,cb) ->
window.urb.send { window.urb.send {
appl:"rodeo" appl:"radio"
mark:"rodeo-command" mark:"radio-command"
data: data:
design: design:
party:name party:name
@ -26,8 +26,8 @@ module.exports =
setSources: (station,ship,sources) -> setSources: (station,ship,sources) ->
send = send =
appl:"rodeo" appl:"radio"
mark:"rodeo-command" mark:"radio-command"
data: data:
design: design:
party:station party:station
@ -41,7 +41,7 @@ module.exports =
members: -> members: ->
window.urb.subscribe { window.urb.subscribe {
appl:"rodeo" appl:"radio"
path:"/a/court" path:"/a/court"
}, (err,res) -> }, (err,res) ->
console.log 'membership updates' console.log 'membership updates'
@ -51,7 +51,7 @@ module.exports =
listen: -> listen: ->
window.urb.subscribe { window.urb.subscribe {
appl:"rodeo" appl:"radio"
path:"/" path:"/"
}, (err,res) -> }, (err,res) ->
console.log 'house updates' console.log 'house updates'
@ -61,14 +61,15 @@ module.exports =
listenStation: (station) -> listenStation: (station) ->
window.urb.subscribe { window.urb.subscribe {
appl:"rodeo" appl:"radio"
path:"/ax/#{station}" path:"/ax/#{station}"
}, (err,res) -> }, (err,res) ->
console.log('station subscription updates') console.log('station subscription updates')
console.log(res.data) console.log(res.data)
if res.data.ok is true if res.data.ok is true
StationActions.listeningStation station StationActions.listeningStation station
if res.data.group?.local if res.data.group
StationActions.loadMembers station,res.data.group.local res.data.group.global[window.util.mainStationPath(window.urb.user)] = res.data.group.local
StationActions.loadMembers res.data.group.global
if res.data.config if res.data.config
StationActions.loadConfig station,res.data.config StationActions.loadConfig station,res.data.config

View File

@ -33,6 +33,11 @@ MessageStore = _.merge new EventEmitter,{
getTyping: -> _typing getTyping: -> _typing
getLastAudience: ->
if _.keys(_messages).length is 0 then return []
messages = _.sortBy _messages, (_message) -> _message.thought.statement.time
_.keys messages[messages.length-1].thought.audience
setTyping: (state) -> _typing = state setTyping: (state) -> _typing = state
setListening: (station) -> setListening: (station) ->

View File

@ -10,6 +10,8 @@ _station = null
_config = {} _config = {}
_typing = {} _typing = {}
_validAudience = true
StationStore = _.merge new EventEmitter,{ StationStore = _.merge new EventEmitter,{
removeChangeListener: (cb) -> @removeListener "change", cb removeChangeListener: (cb) -> @removeListener "change", cb
@ -21,6 +23,10 @@ StationStore = _.merge new EventEmitter,{
setAudience: (audience) -> _audience = audience setAudience: (audience) -> _audience = audience
getValidAudience: -> _validAudience
setValidAudience: (valid) -> _validAudience = valid
toggleAudience: (station) -> toggleAudience: (station) ->
if _audience.indexOf(station) isnt -1 if _audience.indexOf(station) isnt -1
_audience.splice _audience.indexOf(station), 1 _audience.splice _audience.indexOf(station), 1
@ -35,14 +41,12 @@ StationStore = _.merge new EventEmitter,{
getMember: (ship) -> {ship:ship} getMember: (ship) -> {ship:ship}
changeMember: (dir,name,ship) -> loadMembers: (members) ->
if dir is "out" _members = {}
_members = _.filter _members, (_member) -> for station,list of members
return (_member.ship isnt ship) for member,presence of list
if dir is "in" _members[member] = {} if not _members[member]
_members.push {name:name, ship:ship} _members[member][station] = presence
loadMembers: (station,members) -> _members[station] = members
getMembers: -> _members getMembers: -> _members
@ -94,6 +98,10 @@ StationStore.dispatchToken = StationDispatcher.register (payload) ->
StationStore.setAudience action.audience StationStore.setAudience action.audience
StationStore.emitChange() StationStore.emitChange()
break break
when 'station-set-valid-audience'
StationStore.setValidAudience action.valid
StationStore.emitChange()
break
when 'station-switch' when 'station-switch'
StationStore.setAudience [] StationStore.setAudience []
StationStore.setStation action.station StationStore.setStation action.station
@ -103,7 +111,7 @@ StationStore.dispatchToken = StationDispatcher.register (payload) ->
StationStore.setListening action.station StationStore.setListening action.station
StationStore.emitChange() StationStore.emitChange()
break break
when "config-load" when "config-load" #[name:'loadConfig', args:['station', 'config']]
StationStore.loadConfig action.station,action.config StationStore.loadConfig action.station,action.config
StationStore.emitChange() StationStore.emitChange()
break break
@ -111,7 +119,10 @@ StationStore.dispatchToken = StationDispatcher.register (payload) ->
StationStore.loadStations action.stations StationStore.loadStations action.stations
StationStore.emitChange() StationStore.emitChange()
break break
when "stations-leave" when "stations-leave" # stations-leave:[{name:'loadStations' args:['stations']} ['unsetStation' 'station']]
# ...
# for command in actionVtable[action.type]
# StationStore[command[0]].apply(command[1..].map(argname -> action[argname]))
StationStore.loadStations action.stations StationStore.loadStations action.stations
StationStore.unsetStation action.station StationStore.unsetStation action.station
StationStore.emitChange() StationStore.emitChange()
@ -121,7 +132,7 @@ StationStore.dispatchToken = StationDispatcher.register (payload) ->
StationStore.emitChange() StationStore.emitChange()
break break
when "members-load" when "members-load"
StationStore.loadMembers action.station,action.members StationStore.loadMembers action.members
StationStore.emitChange() StationStore.emitChange()
break break
when "typing-set" when "typing-set"