diff --git a/docs/pub/doc/arvo/clay/commentary.md b/docs/pub/doc/arvo/clay/commentary.md index d0edfea2d..daf8bc7df 100644 --- a/docs/pub/doc/arvo/clay/commentary.md +++ b/docs/pub/doc/arvo/clay/commentary.md @@ -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, 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 `++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; diff --git a/docs/pub/tree/src/readme.md b/docs/pub/tree/src/readme.md new file mode 100644 index 000000000..b6776e98d --- /dev/null +++ b/docs/pub/tree/src/readme.md @@ -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` + diff --git a/main/pub/talk/fab/hymn.hook b/main/pub/talk/fab/hymn.hook index 0c50e4eb5..ae13f148e 100644 --- a/main/pub/talk/fab/hymn.hook +++ b/main/pub/talk/fab/hymn.hook @@ -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/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 "/main/pub/talk/src/js/dep/director.js"); - ;meta(name "viewport", content "width=432, initial-scale=1"); + ;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"); ;link(type "text/css", rel "stylesheet", href "/main/pub/talk/src/css/main.css"); ;script(type "text/javascript", src "/gop/hart.js"); ;title: Radio diff --git a/main/pub/talk/src/css/fonts.styl b/main/pub/talk/src/css/fonts.styl index 8048040a3..1e64aa386 100644 --- a/main/pub/talk/src/css/fonts.styl +++ b/main/pub/talk/src/css/fonts.styl @@ -69,4 +69,16 @@ src: url("http://storage.googleapis.com/urbit-extra/scp-medium.woff"); font-weight: 500; 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; } \ No newline at end of file diff --git a/main/pub/talk/src/css/main.css b/main/pub/talk/src/css/main.css index ba91bd6a2..ff92ff80d 100644 --- a/main/pub/talk/src/css/main.css +++ b/main/pub/talk/src/css/main.css @@ -70,10 +70,25 @@ font-weight: 500; 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, .audi, .time, -#length { +#length, +#where, +#who, +.station { font-family: "scp"; } .join-ctrl input { @@ -100,6 +115,9 @@ input.join, #station { font-size: 0.7rem; } +.iden { + font-weight: 600; +} html, body { font-size: 18px; @@ -113,124 +131,152 @@ body { display: none; } #c { - top: 0; - background-color: #fff; -} -#stations-container { position: absolute; - top: 1rem; + top: 0rem; left: 50%; - width: 24rem; - margin-left: -12rem; - font-size: 4rem; + width: 58rem; + margin-left: -29rem; + margin-bottom: 12rem; } #station-container { position: fixed; - top: 0; - left: 50%; - width: 28rem; - max-height: 2.6rem; + width: 58rem; + max-height: 2.7rem; + background-color: #fff; + border-bottom: 0.3rem solid #000; + padding-bottom: 1rem; overflow: hidden; - margin-left: -14rem; - padding-top: 1rem; - background-color: #f5f5f5; - border-bottom: 3px solid #ededed; - transition: max-height 0.15s ease-out; + z-index: 10; + -webkit-transition: max-height 0.2s; } #station-container:hover { - max-height: 12rem; - transition: max-height 0.25s ease-in; + max-height: 30rem; + height: auto; + -webkit-transition: max-height 0.2s; } -#stations-container, -#messages-container { - vertical-align: top; +#station #station-container { + padding-top: 1rem; + min-width: 30rem; + text-align: right; } -#messaging-container { - position: absolute; - top: 4rem; - left: 50%; - width: 24rem; - margin-left: -12rem; - margin-bottom: 4rem; -} -#station > div { - display: inline-block; -} -#station-meta { - margin-right: 1rem; +#writing-container { + bottom: 4rem; margin-bottom: 1rem; } -#sources-container { - width: 6rem; - float: right; - margin: 1rem -6rem 0 0; +#messages-container { + vertical-align: top; + margin-top: 4rem; } -#members { - margin-left: 2rem; -} -#station .iden { - display: block; -} -.station { +.caret, +.circle { display: inline-block; - width: 9rem; - margin-bottom: 0.3rem; - cursor: pointer; - font-weight: 200; } -#stations .station { - display: block; - width: 24rem; -} -.station .name { - padding: 0.3rem; +.caret { + width: 0; + height: 0; + border-top: 6px solid transparent; + border-right: 6px solid transparent; border-bottom: 6px solid transparent; + border-left: 6px solid #000; } -.station .name:hover { - background-color: #f5f5f5; - border-bottom: 6px solid #ededed; +.circle { + width: 6px; + 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; } -.toggle { - width: 0.4rem; - height: 0.4rem; - border: 2px solid #000; - margin-right: 0.6rem; +#members .audi { + margin-right: 0.3rem; } -.toggle.active { - background-color: #000; +#members .iden { + min-width: 6rem; +} +.station div { + display: inline-block; } .station .remove { - display: none; - float: right; - margin-left: 1rem; + opacity: 0; + cursor: pointer; + width: 0.6rem; + margin-right: 0.6rem; font-weight: 600; color: #f00; } .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 { + font-family: "scp"; border: none; font-weight: 400; + text-align: right; + line-height: 1rem; + outline: none; + cursor: pointer; } .sour-ctrl input::-webkit-input-placeholder { - font-family: "bau"; + font-family: "scp"; font-size: 1rem; - font-weight: 200; + font-weight: 600; margin-left: 0.6rem; - color: #0003ff; + color: #000; +} +.sour-ctrl input:focus::-webkit-input-placeholder { + color: #fff; } .message { padding-top: 0.3rem; @@ -245,8 +291,9 @@ body { #messages .message:hover .time { opacity: 1; } -.time { - margin-right: 0.6rem; +#messages .message .ship, +#messages .message .audi > div { + cursor: pointer; } .member { width: 12rem; @@ -255,55 +302,82 @@ body { #messages { height: auto; } +.message.pending { + color: #ccc; +} +.message.say .mess { + font-style: italic; +} .mess, .iden, -.attr > div, #station .member div, #writing { display: inline-block; } -.iden > div { - display: inline; -} .mess, #writing, #length { vertical-align: top; } +.attr > div { + max-width: 16rem; +} .attr { - color: #d7d7d7; + text-align: right; + display: inline-block; + margin-right: 0.3rem; + min-width: 16rem; } .attr .iden { - color: #000; + margin-left: 0.3rem; } -.attr > div { +.audi { + white-space: nowrap; +} +.audi > div { 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 { font-size: 0.9rem; - line-height: 1.6rem; letter-spacing: 0.03rem; word-wrap: break-word; - max-width: 31rem; + max-width: 30rem; + margin-left: 0.3rem; } -.ship { - font-weight: 600; +#writing { + 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 { - content: "..."; - 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:focus { + background-color: #fff; } .writing { padding-top: 0.3rem; @@ -313,60 +387,25 @@ body { margin-left: 1rem; margin-top: 1.2rem; } -#writing { - font-size: 0.9rem; - min-height: 1.6rem; - line-height: 1.6rem; - min-width: 1.3rem; - padding: 0; - outline: none; +.writing .iden { + display: block; + text-align: right; + width: 100%; +} +.writing .iden .ship { + margin-right: 0.3rem; +} +#audi { + display: inline-block; background-color: #eee; -} -#writing:focus { - background-color: #fff; -} -#station h1 { - display: inline-block; - margin: 0; - font-weight: 200; - font-size: 2rem; - text-transform: lowercase; -} -input.join { - font-size: 4rem; - background-color: #fff; + padding: 0.3rem 0.1rem; + margin-top: -0.3rem; + margin-right: -0.2rem; outline: none; - width: 24rem; + overflow: hidden; } -#station input.join { - font-family: "scp"; - 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; +#audi.valid-false { + color: #ff2f2f; } #scrolling { display: none; @@ -383,67 +422,45 @@ a.up { font-size: 0.8rem; text-transform: uppercase; } -@media (max-width: 40rem) { - #c { +@media only screen and (max-width: 1170px) { + #c, + #station-container { + width: 96%; left: 0; - margin-left: 0; - width: 24rem; + margin-left: 2%; + margin-right: 2%; } - #messages-container, - #writing-container { - margin-left: 1rem; + .mess, + #writing { + max-width: 40%; + line-height: 1.2rem; } - #stations-container, - #station-container { - position: relative; - float: left; + .attr, + #stations, + #where { + width: 20%; + min-width: 20%; } - #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: 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; + #audience, + #who { + width: 60%; } #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; } } diff --git a/main/pub/talk/src/css/main.styl b/main/pub/talk/src/css/main.styl index c478b2031..4d56f565c 100644 --- a/main/pub/talk/src/css/main.styl +++ b/main/pub/talk/src/css/main.styl @@ -1,9 +1,16 @@ +// +// fonts first +// + @import 'fonts' .iden .audi .time #length +#where +#who +.station font-family "scp" .join-ctrl input @@ -30,10 +37,17 @@ input.join #station font-size .7rem +.iden + font-weight 600 + html body font-size 18px +// +// containers +// + body background-color #fefefe padding 0 @@ -43,125 +57,165 @@ body display none #c - top 0 - background-color #fff - -#stations-container position absolute - top 1rem + top 0rem left 50% - width 24rem - margin-left -12rem - font-size 4rem - + width 58rem + margin-left -29rem + margin-bottom 12rem + #station-container position fixed - top 0 - left 50% - width 28rem - max-height 2.6rem + width 58rem + max-height 2.7rem + background-color white + border-bottom .3rem solid black + padding-bottom 1rem overflow hidden - margin-left -14rem - padding-top 1rem - background-color #f5f5f5 - border-bottom 3px solid #ededed - transition max-height 0.15s ease-out + z-index 10 + -webkit-transition max-height .2s #station-container:hover - max-height 12rem - transition max-height 0.25s ease-in + max-height 30rem + height auto + -webkit-transition max-height .2s + +#station #station-container + padding-top 1rem + min-width 30rem + text-align right -#stations-container -#messages-container - vertical-align top - -#messaging-container - position absolute - top 4rem - left 50% - width 24rem - margin-left -12rem - margin-bottom 4rem - -#station > div - display inline-block - -#station-meta - margin-right 1rem +#writing-container + bottom 4rem margin-bottom 1rem -#sources-container - width 6rem - float right - margin 1rem -6rem 0 0 +#messages-container + vertical-align top + margin-top 4rem -#members - margin-left 2rem +// +// components +// -#station .iden - display block - -.station +.caret +.circle display inline-block - width 9rem - margin-bottom .3rem - cursor pointer - font-weight 200 -#stations .station - display block - width 24rem - -.station .name - padding .3rem +.caret + width 0 + height 0 + border-top 6px solid transparent + border-right 6px solid transparent border-bottom 6px solid transparent + border-left 6px solid #000 -.station .name:hover - background-color #f5f5f5 - border-bottom 6px solid #ededed +.circle + width 6px + 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 -.toggle - width .4rem - height .4rem - border 2px solid #000 - margin-right .6rem +#members .audi + margin-right .3rem -.toggle.active - background-color #000 +#members .iden + min-width 6rem + +.station div + display inline-block .station .remove - display none - float right - margin-left 1rem + opacity 0 + cursor pointer + width .6rem + margin-right .6rem font-weight 600 color #ff0000 .station:hover .remove - display inline + opacity 1 -#sources-container .station - font-family "scp" - font-weight 500 - text-transform lowercase - -// hate this. -.sour-ctrl - margin-bottom .16rem - -.join-ctrl input +// add source .sour-ctrl input + font-family "scp" border none font-weight 400 + text-align right + line-height 1rem + outline none + cursor pointer .sour-ctrl input::-webkit-input-placeholder - font-family "bau" + font-family "scp" font-size 1rem - font-weight 200 + font-weight 600 margin-left .6rem - color #0003FF + color #000 + +.sour-ctrl input:focus::-webkit-input-placeholder + color white + +// +// messages +// .message padding-top .3rem @@ -176,8 +230,9 @@ body #messages .message:hover .time opacity 1 -.time - margin-right .6rem +#messages .message .ship +#messages .message .audi > div + cursor pointer .member width 12rem @@ -186,55 +241,86 @@ body #messages height auto +.message.pending + color #ccc + +.message.say .mess + font-style italic + .mess .iden -.attr > div #station .member div #writing display inline-block -.iden > div - display inline - .mess #writing #length vertical-align top +.attr > div + max-width 16rem + .attr - color #D7D7D7 + text-align right + display inline-block + margin-right .3rem + min-width 16rem .attr .iden - color #000 + margin-left .3rem -.attr > div +.audi + white-space nowrap + +.audi > div 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 font-size .9rem - line-height 1.6rem letter-spacing .03rem word-wrap break-word - max-width 31rem + max-width 30rem + margin-left .3rem -.ship - font-weight 600 +// +// writing +// -.ship.talk:before - content "..." - margin-left -1.3rem - margin-right .3rem - width 1rem - margin-top -.4rem - vertical-align middle - display inline-block - line-height .2rem - letter-spacing -.1rem +#writing + font-size .9rem + min-height 1.6rem + min-width 1.3rem + outline none + background-color #eee + padding .3rem .1rem + margin-left .2rem + margin-top -.3rem -#writing-container - bottom 4rem - margin-bottom 1rem - float left +#writing:focus + background-color #fff .writing padding-top .3rem @@ -244,60 +330,29 @@ body margin-left 1rem margin-top 1.2rem -#writing - font-size .9rem - min-height 1.6rem - line-height 1.6rem - min-width 1.3rem - padding 0 - outline none +.writing .iden + display block + text-align right + width 100% + +.writing .iden .ship + margin-right .3rem + +#audi + display inline-block background-color #eee - -#writing:focus - background-color #fff - -#station h1 - display inline-block - margin 0 - font-weight 200 - font-size 2rem - text-transform lowercase - -input.join - font-size 4rem - background-color #fff + padding .3rem .1rem + margin-top -.3rem + margin-right -.2rem outline none - width 24rem + overflow hidden -#station input.join - font-family "scp" - font-size .7rem - line-height 1rem - width 12rem +#audi.valid-false + color #ff2f2f -input.join::-webkit-input-placeholder - color #0003FF - -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 @@ -314,66 +369,4 @@ a.up font-size .8rem text-transform uppercase -@media (max-width: 40rem) - #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 - \ No newline at end of file +@import 'mobile' \ No newline at end of file diff --git a/main/pub/talk/src/css/mobile.styl b/main/pub/talk/src/css/mobile.styl new file mode 100644 index 000000000..af1a03336 --- /dev/null +++ b/main/pub/talk/src/css/mobile.styl @@ -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 \ No newline at end of file diff --git a/main/pub/talk/src/js/actions/MessageActions.coffee b/main/pub/talk/src/js/actions/MessageActions.coffee index d904fadcd..d8b83c6e6 100644 --- a/main/pub/talk/src/js/actions/MessageActions.coffee +++ b/main/pub/talk/src/js/actions/MessageActions.coffee @@ -1,7 +1,5 @@ MessageDispatcher = require '../dispatcher/Dispatcher.coffee' -# hm - module.exports = loadMessages: (grams,get) -> MessageDispatcher.handleServerAction @@ -29,12 +27,11 @@ module.exports = type:"messages-fetch" window.chat.MessagePersistence.get station,start,end - sendMessage: (station,message,audience) -> + sendMessage: (message,audience) -> serial = window.util.uuid32() - if station[0] isnt "~" then station = "~"+window.urb.ship+"/"+station - - if audience.length is 0 then audience.push station + audience.push window.util.mainStationPath window.urb.user + audience = _.uniq audience _audi = {} for k,v of audience @@ -53,9 +50,13 @@ module.exports = bouquet:[] speech: lin: - say:false + say:true txt:message 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 type:"message-send" diff --git a/main/pub/talk/src/js/actions/StationActions.coffee b/main/pub/talk/src/js/actions/StationActions.coffee index 55ac7c54a..f7bac708d 100644 --- a/main/pub/talk/src/js/actions/StationActions.coffee +++ b/main/pub/talk/src/js/actions/StationActions.coffee @@ -17,6 +17,11 @@ module.exports = type:"station-set-audience" audience:audience + setValidAudience: (valid) -> + StationDispatcher.handleViewAction + type:"station-set-valid-audience" + valid:valid + toggleAudience: (station) -> StationDispatcher.handleViewAction type:"station-audience-toggle" @@ -53,11 +58,10 @@ module.exports = type:"stations-load" stations:stations - loadMembers: (station,members) -> + loadMembers: (members) -> StationDispatcher.handleServerAction type:"members-load" members:members - station:station createStation: (station) -> StationDispatcher.handleViewAction diff --git a/main/pub/talk/src/js/components/MessagesComponent.coffee b/main/pub/talk/src/js/components/MessagesComponent.coffee index f721e7659..75d78d593 100644 --- a/main/pub/talk/src/js/components/MessagesComponent.coffee +++ b/main/pub/talk/src/js/components/MessagesComponent.coffee @@ -1,13 +1,13 @@ moment = require 'moment-timezone' 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' +MessageStore = require '../stores/MessageStore.coffee' StationActions = require '../actions/StationActions.coffee' -Member = require './MemberComponent.coffee' +StationStore = require '../stores/StationStore.coffee' +Member = require './MemberComponent.coffee' Message = recl lz: (n) -> if n<10 then "0#{n}" else "#{n}" @@ -19,24 +19,31 @@ Message = recl s = @lz d.getSeconds() "~#{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: -> # pendingClass = if @props.pending isnt "received" then "pending" else "" delivery = _.uniq _.pluck @props.thought.audience, "delivery" - pendingClass = if delivery.indexOf("received") isnt -1 then "received" else "pending" - - if pendingClass is "pending" - console.log @props.thought - console.log delivery + klass = if delivery.indexOf("received") isnt -1 then " received" else " pending" + if @props.thought.statement.speech.lin.say is false then klass += " say" name = if @props.name then @props.name else "" - audi = _.remove _.keys(@props.thought.audience), (stat) => - stat isnt "~"+window.urb.ship+"/"+@props.station - audi = audi.join " " + audi = _.keys @props.thought.audience + audi = _.without audi,window.util.mainStationPath window.urb.user + audi = window.util.clipAudi audi + audi = audi.map (_audi) -> (div {}, _audi) - div {className:"message "+pendingClass}, [ + div {className:"message #{klass}"}, [ (div {className:"attr"}, [ - (Member {ship:@props.ship}, "") - div {className:"audi"}, "#{audi}" + div {onClick:@_handleAudi,className:"audi"}, audi + (div {onClick:@_handlePm}, (Member {ship:@props.ship}, "")) div {className:"time"}, @convTime @props.thought.statement.date ]) div {className:"mess"}, @props.thought.statement.speech.lin.txt @@ -51,7 +58,7 @@ module.exports = recl last:MessageStore.getLast() fetching:MessageStore.getFetching() listening:MessageStore.getListening() - station:StationStore.getStation() + station:window.util.mainStation() stations:StationStore.getStations() configs:StationStore.getConfigs() typing:MessageStore.getTyping() @@ -78,7 +85,8 @@ module.exports = recl componentDidMount: -> MessageStore.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 checkMore = @checkMore $(window).on 'scroll', checkMore @@ -101,14 +109,25 @@ module.exports = recl _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: -> station = @state.station _station = "~"+window.urb.ship+"/"+station sources = _.clone @state.configs[@state.station]?.sources ? [] sources.push _station - _messages = _.filter @state.messages, (_message) -> - audience = _.keys(_message.thought.audience) - _.intersection(sources,audience).length > 0 + _messages = @state.messages + # _messages = _.filter @state.messages, (_message) -> + # audience = _.keys(_message.thought.audience) + # _.intersection(sources,audience).length > 0 _messages = _.sortBy _messages, (_message) -> _message.pending = _message.thought.audience[station] _message.thought.statement.time @@ -122,5 +141,7 @@ module.exports = recl messages = _messages.map (_message) => _message.station = @state.station + _message._handlePm = @_handlePm + _message._handleAudi = @_handleAudi Message _message, "" div {id: "messages"}, messages \ No newline at end of file diff --git a/main/pub/talk/src/js/components/PageComponent.coffee b/main/pub/talk/src/js/components/PageComponent.coffee deleted file mode 100644 index ca8898d83..000000000 --- a/main/pub/talk/src/js/components/PageComponent.coffee +++ /dev/null @@ -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 {}, "")) - # ] \ No newline at end of file diff --git a/main/pub/talk/src/js/components/StationComponent.coffee b/main/pub/talk/src/js/components/StationComponent.coffee index 0d6546bf4..27ed79455 100644 --- a/main/pub/talk/src/js/components/StationComponent.coffee +++ b/main/pub/talk/src/js/components/StationComponent.coffee @@ -15,7 +15,7 @@ module.exports = recl stateFromStore: -> { audi:StationStore.getAudience() members:StationStore.getMembers() - station:StationStore.getStation() + station:window.util.mainStation() stations:StationStore.getStations() configs:StationStore.getConfigs() typing:StationStore.getTyping() @@ -35,10 +35,6 @@ module.exports = recl componentWillUnmount: -> StationStore.removeChangeListener @_onChangeStore - _toggleAudi: (e) -> - $e = $(e.target).closest('.station') - station = $e.find('.path').text() - StationActions.toggleAudience station _onChangeStore: -> @setState @stateFromStore() @@ -51,51 +47,50 @@ module.exports = recl _sources.push v StationActions.setSources @state.station,_sources @$input.val('') + @$input.blur() _remove: (e) -> e.stopPropagation() e.preventDefault() _station = $(e.target).attr "data-station" _sources = _.clone @state.configs[@state.station].sources - _sources.slice _sources.indexOf(_station),1 + _sources.splice _sources.indexOf(_station),1 StationActions.setSources @state.station,_sources render: -> parts = [] members = [] - if @state.station and @state.members[@state.station] - members = _.map @state.members[@state.station], (state,member) -> - Member {ship:member,presence:state.presence} + if @state.station and @state.members + members = _.map @state.members, (stations,member) -> + audi = _.map stations,(presence,station) -> (div {className:"audi"}, station) + (div {}, [audi,Member {ship:member}]) else members = "" sourceInput = [(input {className:"join",onKeyUp:@_keyUp,placeholder:"+"}, "")] - sourceCtrl = div {className:"sour-ctrl"}, sourceInput + sourceCtrl = div {className:"sour-ctrl"},sourceInput sources = [] if @state.station and @state.configs[@state.station] _remove = @_remove _sources = _.clone @state.configs[@state.station].sources - _sources.push "twitter/hoontap" sources = _.map _sources,(source) => - toggleClass = "toggle " - if @state.audi.indexOf(source) isnt -1 then toggleClass += "active" - (div {className:"station",onClick:@_toggleAudi}, [ - (div {className:toggleClass}) - (div {className:"path"}, source), - (div {className:"remove",onClick:_remove,"data-station":source},"×") + (div {className:"station"}, [ + (div {className:"remove",onClick:_remove,"data-station":source},"×"), + (div {className:"path"}, source) ]) - else - sources = "" + sources = "" - station = [] - station.push (a {className:"up",href:"\#/"}, [(div {className:"arow-up"}, "")]) - station.push (h1 {},@state.station) - station.push (div {id:"members"},members) + head = (div {id:"head"}, + [(div {id:"where"},["/talk",(div {className:"caret"},"")]), + (div {id:"who"},[(div {className:"circle"},""),"~#{window.urb.user}"]) + ] + ) - parts.push (div {id:"station-container"}, (div {id:"station-meta"},station)) - parts.push (div {id:"sources-container"}, [(div {class:"sources-list"},sources),sourceCtrl]) + parts.push head + 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 \ No newline at end of file diff --git a/main/pub/talk/src/js/components/StationsComponent.coffee b/main/pub/talk/src/js/components/StationsComponent.coffee index df5a5411d..7940a2aae 100644 --- a/main/pub/talk/src/js/components/StationsComponent.coffee +++ b/main/pub/talk/src/js/components/StationsComponent.coffee @@ -7,15 +7,15 @@ StationActions = require '../actions/StationActions.coffee' module.exports = recl stateFromStore: -> { stations: StationStore.getStations() - station: StationStore.getStation() + station: "~zod/court" } getInitialState: -> @stateFromStore() componentDidMount: -> - @$el = $(@getDOMNode()) - @$add = $('#stations .add') - @$input = @$el.find('input') + @$el = $ @getDOMNode() + @$add = $ '#stations .add' + @$input = @$el.find 'input' StationStore.addChangeListener @_onChangeStore componentWillUnmount: -> diff --git a/main/pub/talk/src/js/components/WritingComponent.coffee b/main/pub/talk/src/js/components/WritingComponent.coffee index f6888e543..c0a1d3443 100644 --- a/main/pub/talk/src/js/components/WritingComponent.coffee +++ b/main/pub/talk/src/js/components/WritingComponent.coffee @@ -1,10 +1,11 @@ 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' +MessageStore = require '../stores/MessageStore.coffee' StationActions = require '../actions/StationActions.coffee' -StationStore = require '../stores/StationStore.coffee' -Member = require './MemberComponent.coffee' +StationStore = require '../stores/StationStore.coffee' +Member = require './MemberComponent.coffee' module.exports = recl set: -> @@ -13,12 +14,16 @@ module.exports = recl get: -> if window.localStorage then window.localStorage.getItem 'writing' - stateFromStore: -> { - audi:StationStore.getAudience() - members:StationStore.getMembers() - typing:StationStore.getTyping() - station:StationStore.getStation() - } + stateFromStore: -> + s = + audi:StationStore.getAudience() + ludi:MessageStore.getLastAudience() + members:StationStore.getMembers() + typing:StationStore.getTyping() + 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() @@ -35,13 +40,30 @@ module.exports = recl @typing true 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" @$writing.text('') @set() @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 e.preventDefault() @sendMessage() @@ -67,6 +89,40 @@ module.exports = recl _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: -> d = new Date() seconds = d.getSeconds() @@ -85,6 +141,7 @@ module.exports = recl componentDidMount: -> window.util.sendMessage = @sendMessage StationStore.addChangeListener @_onChangeStore + MessageStore.addChangeListener @_onChangeStore @$el = $ @getDOMNode() @$length = $('#length') @$writing = $('#writing') @@ -108,11 +165,20 @@ module.exports = recl ship = if iden then iden.ship else user name = if iden then iden.name else "" - k = "writing" - k+= " hidden" if not @state?.station + audi = if @state.audi.length is 0 then @state.ludi else @state.audi + audi = window.util.clipAudi audi - div {className:k,onClick:@_setFocus}, [ + k = "writing" + + div {className:k}, [ (div {className:"attr"}, [ + (div { + id:"audi" + className:"audi valid-#{@state.valid}" + contentEditable:true + onKeyDown: @_audiKeyDown + onBlur:@_setAudi + }, audi.join(" ")) (Member iden, "") (div {className:"time"}, @getTime()) ]) @@ -123,7 +189,7 @@ module.exports = recl onBlur: @_blur onInput: @_input onPaste: @_input - onKeyDown: @_keyDown + onKeyDown: @_writingKeyDown onFocus: @cursorAtEnd }, "") div {id:"length"}, "0/69" diff --git a/main/pub/talk/src/js/main.coffee b/main/pub/talk/src/js/main.coffee index 1610d6025..704e25e88 100644 --- a/main/pub/talk/src/js/main.coffee +++ b/main/pub/talk/src/js/main.coffee @@ -8,15 +8,33 @@ $(() -> window.chat.StationPersistence = require './persistence/StationPersistence.coffee' window.util = - mainStation: -> - switch window.urb.user.length + mainStations: ["court","floor","porch"] + + mainStationPath: (user) -> "~#{user}/#{window.util.mainStation(user)}" + + mainStation: (user) -> + if not user then user = window.urb.user + switch user.length when 3 return "court" - when 5 + when 6 return "floor" when 13 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) -> window.chat.StationPersistence.createStation name, (err,res) -> @@ -54,8 +72,7 @@ $(() -> send() getScroll: -> - @writingPosition = $('#messaging-container').outerHeight(true)+$('#messaging-container').offset().top-$(window).height() - #@writingPosition = $('#writing-container').position().top-$(window).height()+$('#writing-container').outerHeight(true) + @writingPosition = $('#c').outerHeight(true)+$('#c').offset().top-$(window).height() setScroll: -> window.util.getScroll() @@ -68,44 +85,93 @@ $(() -> $('body').addClass 'scrolling' else $('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.chat.StationPersistence.listen() StationComponent = require './components/StationComponent.coffee' - StationsComponent = require './components/StationsComponent.coffee' MessagesComponent = require './components/MessagesComponent.coffee' WritingComponent = require './components/WritingComponent.coffee' $c = $('#c') clean = -> - React.unmountComponentAtNode $('#stations-container')[0] - React.unmountComponentAtNode $('#station-parts-container')[0] - React.unmountComponentAtNode $('#writing-container')[0] + React.unmountComponentAtNode $('#station-container')[0] React.unmountComponentAtNode $('#messages-container')[0] + React.unmountComponentAtNode $('#writing-container')[0] - routes = - '': -> - clean() - $c.html "
" - rend (StationsComponent {}, ""),$('#stations-container')[0] - '/:station': (station) -> - clean() - StationActions.switchStation station - $c.html "" - $c.append("
") - $d = $('#messaging-container') - $d.append("
") - $d.append("
") - $d.append("
") - $c.append("
BOTTOM
") - rend (StationComponent {}, ""),$('#station-parts-container')[0] - rend (MessagesComponent {}, ""),$('#messages-container')[0] - rend (WritingComponent {}, ""),$('#writing-container')[0] - - router = Router routes - if not window.location.hash then window.location.hash = "/" - router.init() + $c.append "
" + $c.append "
" + $c.append "
" + $c.append "
BOTTOM
" + rend (StationComponent {}, ""),$('#station-container')[0] + rend (MessagesComponent {}, ""),$('#messages-container')[0] + rend (WritingComponent {}, ""),$('#writing-container')[0] ) \ No newline at end of file diff --git a/main/pub/talk/src/js/main.js b/main/pub/talk/src/js/main.js index dd718dae3..df508ee89 100644 --- a/main/pub/talk/src/js/main.js +++ b/main/pub/talk/src/js/main.js @@ -36,15 +36,11 @@ module.exports = { }); return window.chat.MessagePersistence.get(station, start, end); }, - sendMessage: function(station, message, audience) { - var k, serial, v, _audi, _message; + sendMessage: function(message, audience) { + var _audi, _message, k, serial, v; serial = window.util.uuid32(); - if (station[0] !== "~") { - station = "~" + window.urb.ship + "/" + station; - } - if (audience.length === 0) { - audience.push(station); - } + audience.push(window.util.mainStationPath(window.urb.user)); + audience = _.uniq(audience); _audi = {}; for (k in audience) { v = audience[k]; @@ -65,7 +61,7 @@ module.exports = { bouquet: [], speech: { lin: { - say: false, + say: true, txt: message } }, @@ -73,6 +69,10 @@ module.exports = { } } }; + if (message[0] === "@") { + _message.thought.statement.speech.lin.txt = _message.thought.statement.speech.lin.txt.slice(1).trim(); + _message.thought.statement.speech.lin.say = false; + } MessageDispatcher.handleViewAction({ type: "message-send", message: _message @@ -108,6 +108,12 @@ module.exports = { audience: audience }); }, + setValidAudience: function(valid) { + return StationDispatcher.handleViewAction({ + type: "station-set-valid-audience", + valid: valid + }); + }, toggleAudience: function(station) { return StationDispatcher.handleViewAction({ type: "station-audience-toggle", @@ -148,11 +154,10 @@ module.exports = { stations: stations }); }, - loadMembers: function(station, members) { + loadMembers: function(members) { return StationDispatcher.handleServerAction({ type: "members-load", - members: members, - station: station + members: members }); }, createStation: function(station) { @@ -167,11 +172,11 @@ module.exports = { },{"../dispatcher/Dispatcher.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/dispatcher/Dispatcher.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MemberComponent.coffee":[function(require,module,exports){ -var div, input, recl, textarea, _ref; +var div, input, recl, ref, textarea; recl = React.createClass; -_ref = [React.DOM.div, React.DOM.input, React.DOM.textarea], div = _ref[0], input = _ref[1], textarea = _ref[2]; +ref = [React.DOM.div, React.DOM.input, React.DOM.textarea], div = ref[0], input = ref[1], textarea = ref[2]; module.exports = recl({ render: function() { @@ -196,22 +201,22 @@ module.exports = recl({ },{}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MessagesComponent.coffee":[function(require,module,exports){ -var Member, Message, MessageActions, MessageStore, StationActions, StationStore, div, input, moment, recl, textarea, _ref; +var Member, Message, MessageActions, MessageStore, StationActions, StationStore, br, div, input, moment, recl, ref, textarea; moment = require('moment-timezone'); recl = React.createClass; -_ref = [React.DOM.div, React.DOM.input, React.DOM.textarea], div = _ref[0], input = _ref[1], textarea = _ref[2]; - -MessageStore = require('../stores/MessageStore.coffee'); - -StationStore = require('../stores/StationStore.coffee'); +ref = [React.DOM.div, React.DOM.br, React.DOM.input, React.DOM.textarea], div = ref[0], br = ref[1], input = ref[2], textarea = ref[3]; MessageActions = require('../actions/MessageActions.coffee'); +MessageStore = require('../stores/MessageStore.coffee'); + StationActions = require('../actions/StationActions.coffee'); +StationStore = require('../stores/StationStore.coffee'); + Member = require('./MemberComponent.coffee'); Message = recl({ @@ -230,32 +235,49 @@ Message = recl({ s = this.lz(d.getSeconds()); return "~" + h + "." + m + "." + s; }, + _handleAudi: function(e) { + var audi; + audi = _.map($(e.target).closest('.audi').find('div'), function(div) { + return $(div).text(); + }); + return this.props._handleAudi(audi); + }, + _handlePm: function(e) { + var user; + if (!this.props._handlePm) { + return; + } + user = $(e.target).closest('.iden').text().slice(1); + return this.props._handlePm(user); + }, render: function() { - var audi, delivery, name, pendingClass; + var audi, delivery, klass, name; delivery = _.uniq(_.pluck(this.props.thought.audience, "delivery")); - pendingClass = delivery.indexOf("received") !== -1 ? "received" : "pending"; - if (pendingClass === "pending") { - console.log(this.props.thought); - console.log(delivery); + klass = delivery.indexOf("received") !== -1 ? " received" : " pending"; + if (this.props.thought.statement.speech.lin.say === false) { + klass += " say"; } name = this.props.name ? this.props.name : ""; - audi = _.remove(_.keys(this.props.thought.audience), (function(_this) { - return function(stat) { - return stat !== "~" + window.urb.ship + "/" + _this.props.station; - }; - })(this)); - audi = audi.join(" "); + audi = _.keys(this.props.thought.audience); + audi = _.without(audi, window.util.mainStationPath(window.urb.user)); + audi = window.util.clipAudi(audi); + audi = audi.map(function(_audi) { + return div({}, _audi); + }); return div({ - className: "message " + pendingClass + className: "message " + klass }, [ div({ className: "attr" }, [ - Member({ - ship: this.props.ship - }, ""), div({ + div({ + onClick: this._handleAudi, className: "audi" - }, "" + audi), div({ + }, audi), div({ + onClick: this._handlePm + }, Member({ + ship: this.props.ship + }, "")), div({ className: "time" }, this.convTime(this.props.thought.statement.date)) ]), div({ @@ -274,7 +296,7 @@ module.exports = recl({ last: MessageStore.getLast(), fetching: MessageStore.getFetching(), listening: MessageStore.getListening(), - station: StationStore.getStation(), + station: window.util.mainStation(), stations: StationStore.getStations(), configs: StationStore.getConfigs(), typing: MessageStore.getTyping() @@ -334,17 +356,24 @@ module.exports = recl({ _onChangeStore: function() { return this.setState(this.stateFromStore()); }, + _handlePm: function(user) { + var audi; + audi = [window.util.mainStationPath(user), window.util.mainStationPath(window.urb.user)]; + if (user === window.urb.user) { + audi.pop(); + } + return StationActions.setAudience(audi); + }, + _handleAudi: function(audi) { + return StationActions.setAudience(audi); + }, render: function() { - var messages, sources, station, _messages, _ref1, _ref2, _station; + var _messages, _station, messages, ref1, ref2, sources, station; station = this.state.station; _station = "~" + window.urb.ship + "/" + station; - sources = _.clone((_ref1 = (_ref2 = this.state.configs[this.state.station]) != null ? _ref2.sources : void 0) != null ? _ref1 : []); + sources = _.clone((ref1 = (ref2 = this.state.configs[this.state.station]) != null ? ref2.sources : void 0) != null ? ref1 : []); sources.push(_station); - _messages = _.filter(this.state.messages, function(_message) { - var audience; - audience = _.keys(_message.thought.audience); - return _.intersection(sources, audience).length > 0; - }); + _messages = this.state.messages; _messages = _.sortBy(_messages, function(_message) { _message.pending = _message.thought.audience[station]; return _message.thought.statement.time; @@ -361,6 +390,8 @@ module.exports = recl({ messages = _messages.map((function(_this) { return function(_message) { _message.station = _this.state.station; + _message._handlePm = _this._handlePm; + _message._handleAudi = _this._handleAudi; return Message(_message, ""); }; })(this)); @@ -373,11 +404,11 @@ module.exports = recl({ },{"../actions/MessageActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/MessageActions.coffee","../actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee","../stores/MessageStore.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/MessageStore.coffee","../stores/StationStore.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/StationStore.coffee","./MemberComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MemberComponent.coffee","moment-timezone":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/node_modules/moment-timezone/index.js"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/StationComponent.coffee":[function(require,module,exports){ -var Member, StationActions, StationStore, a, div, h1, input, recl, textarea, _ref; +var Member, StationActions, StationStore, a, div, h1, input, recl, ref, textarea; recl = React.createClass; -_ref = [React.DOM.div, React.DOM.input, React.DOM.textarea, React.DOM.h1, React.DOM.a], div = _ref[0], input = _ref[1], textarea = _ref[2], h1 = _ref[3], a = _ref[4]; +ref = [React.DOM.div, React.DOM.input, React.DOM.textarea, React.DOM.h1, React.DOM.a], div = ref[0], input = ref[1], textarea = ref[2], h1 = ref[3], a = ref[4]; StationStore = require('../stores/StationStore.coffee'); @@ -390,7 +421,7 @@ module.exports = recl({ return { audi: StationStore.getAudience(), members: StationStore.getMembers(), - station: StationStore.getStation(), + station: window.util.mainStation(), stations: StationStore.getStations(), configs: StationStore.getConfigs(), typing: StationStore.getTyping(), @@ -411,24 +442,19 @@ module.exports = recl({ componentWillUnmount: function() { return StationStore.removeChangeListener(this._onChangeStore); }, - _toggleAudi: function(e) { - var $e, station; - $e = $(e.target).closest('.station'); - station = $e.find('.path').text(); - return StationActions.toggleAudience(station); - }, _onChangeStore: function() { return this.setState(this.stateFromStore()); }, _keyUp: function(e) { - var v, _sources; + var _sources, v; if (e.keyCode === 13) { v = this.$input.val(); if (this.state.configs[this.state.station].sources.indexOf(v) === -1) { _sources = _.clone(this.state.configs[this.state.station].sources); _sources.push(v); StationActions.setSources(this.state.station, _sources); - return this.$input.val(''); + this.$input.val(''); + return this.$input.blur(); } } }, @@ -438,19 +464,26 @@ module.exports = recl({ e.preventDefault(); _station = $(e.target).attr("data-station"); _sources = _.clone(this.state.configs[this.state.station].sources); - _sources.slice(_sources.indexOf(_station), 1); + _sources.splice(_sources.indexOf(_station), 1); return StationActions.setSources(this.state.station, _sources); }, render: function() { - var members, parts, sourceCtrl, sourceInput, sources, station, _remove, _sources; + var _remove, _sources, head, members, parts, sourceCtrl, sourceInput, sources; parts = []; members = []; - if (this.state.station && this.state.members[this.state.station]) { - members = _.map(this.state.members[this.state.station], function(state, member) { - return Member({ - ship: member, - presence: state.presence + if (this.state.station && this.state.members) { + members = _.map(this.state.members, function(stations, member) { + var audi; + audi = _.map(stations, function(presence, station) { + return div({ + className: "audi" + }, station); }); + return div({}, [ + audi, Member({ + ship: member + }) + ]); }); } else { members = ""; @@ -469,58 +502,52 @@ module.exports = recl({ if (this.state.station && this.state.configs[this.state.station]) { _remove = this._remove; _sources = _.clone(this.state.configs[this.state.station].sources); - _sources.push("twitter/hoontap"); sources = _.map(_sources, (function(_this) { return function(source) { - var toggleClass; - toggleClass = "toggle "; - if (_this.state.audi.indexOf(source) !== -1) { - toggleClass += "active"; - } return div({ - className: "station", - onClick: _this._toggleAudi + className: "station" }, [ div({ - className: toggleClass - }), div({ - className: "path" - }, source), div({ className: "remove", onClick: _remove, "data-station": source - }, "×") + }, "×"), div({ + className: "path" + }, source) ]); }; })(this)); } else { sources = ""; } - station = []; - station.push(a({ - className: "up", - href: "\#/" + head = div({ + id: "head" }, [ div({ - className: "arow-up" - }, "") - ])); - station.push(h1({}, this.state.station)); - station.push(div({ - id: "members" - }, members)); + id: "where" + }, [ + "/talk", div({ + className: "caret" + }, "") + ]), div({ + id: "who" + }, [ + div({ + className: "circle" + }, ""), "~" + window.urb.user + ]) + ]); + parts.push(head); parts.push(div({ - id: "station-container" - }, div({ - id: "station-meta" - }, station))); + id: "stations" + }, [h1({}, "Sources"), div({}, sources), sourceCtrl])); parts.push(div({ - id: "sources-container" - }, [ - div({ - "class": "sources-list" - }, sources), sourceCtrl - ])); + id: "audience" + }, div({}, [ + h1({}, "Audience"), div({ + id: "members" + }, members) + ]))); return div({ id: "station" }, parts); @@ -529,117 +556,17 @@ module.exports = recl({ -},{"../actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee","../stores/StationStore.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/StationStore.coffee","./MemberComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MemberComponent.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/StationsComponent.coffee":[function(require,module,exports){ -var StationActions, StationStore, div, input, recl, _ref; +},{"../actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee","../stores/StationStore.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/StationStore.coffee","./MemberComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MemberComponent.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/WritingComponent.coffee":[function(require,module,exports){ +var Member, MessageActions, MessageStore, StationActions, StationStore, br, div, input, recl, ref, textarea; recl = React.createClass; -_ref = [React.DOM.div, React.DOM.input], div = _ref[0], input = _ref[1]; - -StationStore = require('../stores/StationStore.coffee'); - -StationActions = require('../actions/StationActions.coffee'); - -module.exports = recl({ - stateFromStore: function() { - return { - stations: StationStore.getStations(), - station: StationStore.getStation() - }; - }, - getInitialState: function() { - return this.stateFromStore(); - }, - componentDidMount: function() { - this.$el = $(this.getDOMNode()); - this.$add = $('#stations .add'); - this.$input = this.$el.find('input'); - return StationStore.addChangeListener(this._onChangeStore); - }, - componentWillUnmount: function() { - return StationStore.removeChangeListener(this._onChangeStore); - }, - _onChangeStore: function() { - return this.setState(this.stateFromStore()); - }, - _click: function(e) { - var s; - s = $(e.target).closest('.station').find('.name').text(); - return window.location.hash = "/" + (s.toLowerCase()); - }, - _keyUp: function(e) { - var v; - if (e.keyCode === 13) { - v = this.$input.val().toLowerCase(); - if (this.state.stations.indexOf(v) === -1) { - StationActions.createStation(v); - this.$input.val(''); - return this.$input.blur(); - } - } - }, - _remove: function(e) { - var _station, _stations; - _station = $(e.target).parent().find('.name').text(); - _stations = _.without(this.state.stations, _station); - StationActions.removeStation(_station, _stations); - e.stopPropagation(); - return e.preventDefault(); - }, - render: function() { - var station, stations, _click, _remove; - station = this.state.station; - _click = this._click; - _remove = this._remove; - stations = this.state.stations.map(function(_station) { - var k, parts; - k = "station"; - parts = [ - div({ - className: "name" - }, _station.name) - ]; - if (_station.name !== window.util.mainStation()) { - parts.push(div({ - className: "remove", - onClick: _remove, - dataStation: _station.name - }, "×")); - } - return div({ - className: k, - onClick: _click - }, parts); - }); - return div({ - id: "stations" - }, [ - div({ - className: "stations" - }, stations), div({ - className: "join-ctrl" - }, [ - input({ - className: "join", - onKeyUp: this._keyUp, - placeholder: "+" - }, "") - ]) - ]); - } -}); - - - -},{"../actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee","../stores/StationStore.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/StationStore.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/WritingComponent.coffee":[function(require,module,exports){ -var Member, MessageActions, StationActions, StationStore, div, input, recl, textarea, _ref; - -recl = React.createClass; - -_ref = [React.DOM.div, React.DOM.input, React.DOM.textarea], div = _ref[0], input = _ref[1], textarea = _ref[2]; +ref = [React.DOM.div, React.DOM.br, React.DOM.input, React.DOM.textarea], div = ref[0], br = ref[1], input = ref[2], textarea = ref[3]; MessageActions = require('../actions/MessageActions.coffee'); +MessageStore = require('../stores/MessageStore.coffee'); + StationActions = require('../actions/StationActions.coffee'); StationStore = require('../stores/StationStore.coffee'); @@ -658,12 +585,17 @@ module.exports = recl({ } }, stateFromStore: function() { - return { + var s; + s = { audi: StationStore.getAudience(), + ludi: MessageStore.getLastAudience(), members: StationStore.getMembers(), 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)); + return s; }, getInitialState: function() { return this.stateFromStore(); @@ -682,13 +614,34 @@ module.exports = recl({ return this.typing(true); }, sendMessage: function() { - MessageActions.sendMessage(this.state.station, this.$writing.text(), this.state.audi); + var audi; + if (this._validateAudi() === false) { + $('#audi').focus(); + return; + } + if (this.state.audi.length === 0 && $('#audi').text().trim().length > 0) { + audi = this.state.ludi; + this._setAudi(); + } else { + audi = this.state.audi; + } + audi = window.util.expandAudi(audi); + MessageActions.sendMessage(this.$writing.text().trim(), audi); this.$length.text("0/69"); this.$writing.text(''); this.set(); return this.typing(false); }, - _keyDown: function(e) { + _audiKeyDown: function(e) { + if (e.keyCode === 13) { + e.preventDefault(); + setTimeout(function() { + return $('#writing').focus(); + }, 0); + return false; + } + }, + _writingKeyDown: function(e) { if (e.keyCode === 13) { e.preventDefault(); this.sendMessage(); @@ -698,14 +651,14 @@ module.exports = recl({ return this.set(); }, _input: function(e) { - var geturl, length, text, url, urls, _i, _len; + var geturl, i, len, length, text, url, urls; text = this.$writing.text(); length = text.length; geturl = new RegExp("(^|[ \t\r\n])((ftp|http|https|gopher|mailto|news|nntp|telnet|wais|file|prospero|aim|webcal):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-]))", "g"); urls = text.match(geturl); if (urls !== null && urls.length > 0) { - for (_i = 0, _len = urls.length; _i < _len; _i++) { - url = urls[_i]; + for (i = 0, len = urls.length; i < len; i++) { + url = urls[i]; length -= url.length; length += 10; } @@ -723,6 +676,51 @@ module.exports = recl({ _setFocus: function() { return this.$writing.focus(); }, + _validateAudiPart: function(a) { + var _a, ship; + if (a[0] !== "~") { + return false; + } + if (a.indexOf("/") !== -1) { + _a = a.split("/"); + if (_a[1].length === 0) { + return false; + } + ship = _a[0]; + } else { + ship = a; + } + if (ship.length < 3) { + return false; + } + return true; + }, + _validateAudi: function() { + var a, i, len, v, valid; + v = $('#audi').text(); + v = v.trim(); + if (v.length === 0) { + return true; + } + v = v.split(" "); + for (i = 0, len = v.length; i < len; i++) { + a = v[i]; + a = a.trim(); + valid = this._validateAudiPart(a); + } + return valid; + }, + _setAudi: function() { + var v, valid; + valid = this._validateAudi(); + StationActions.setValidAudience(valid); + if (valid === true) { + v = $('#audi').text(); + v = v.split(" "); + v = window.util.expandAudi(v); + return StationActions.setAudience(v); + } + }, getTime: function() { var d, seconds; d = new Date(); @@ -744,6 +742,7 @@ module.exports = recl({ componentDidMount: function() { window.util.sendMessage = this.sendMessage; StationStore.addChangeListener(this._onChangeStore); + MessageStore.addChangeListener(this._onChangeStore); this.$el = $(this.getDOMNode()); this.$length = $('#length'); this.$writing = $('#writing'); @@ -766,23 +765,27 @@ module.exports = recl({ return this.setState(this.stateFromStore()); }, render: function() { - var iden, k, name, ship, user, _ref1; + var audi, iden, k, name, ship, user; user = "~" + window.urb.user; iden = StationStore.getMember(user); ship = iden ? iden.ship : user; name = iden ? iden.name : ""; + audi = this.state.audi.length === 0 ? this.state.ludi : this.state.audi; + audi = window.util.clipAudi(audi); k = "writing"; - if (!((_ref1 = this.state) != null ? _ref1.station : void 0)) { - k += " hidden"; - } return div({ - className: k, - onClick: this._setFocus + className: k }, [ div({ className: "attr" }, [ - Member(iden, ""), div({ + div({ + id: "audi", + className: "audi valid-" + this.state.valid, + contentEditable: true, + onKeyDown: this._audiKeyDown, + onBlur: this._setAudi + }, audi.join(" ")), Member(iden, ""), div({ className: "time" }, this.getTime()) ]), div({ @@ -792,7 +795,7 @@ module.exports = recl({ onBlur: this._blur, onInput: this._input, onPaste: this._input, - onKeyDown: this._keyDown, + onKeyDown: this._writingKeyDown, onFocus: this.cursorAtEnd }, ""), div({ id: "length" @@ -803,7 +806,7 @@ module.exports = recl({ -},{"../actions/MessageActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/MessageActions.coffee","../actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee","../stores/StationStore.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/StationStore.coffee","./MemberComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MemberComponent.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/dispatcher/Dispatcher.coffee":[function(require,module,exports){ +},{"../actions/MessageActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/MessageActions.coffee","../actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee","../stores/MessageStore.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/MessageStore.coffee","../stores/StationStore.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/StationStore.coffee","./MemberComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MemberComponent.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/dispatcher/Dispatcher.coffee":[function(require,module,exports){ var Dispatcher; Dispatcher = require('flux').Dispatcher; @@ -827,23 +830,51 @@ module.exports = _.merge(new Dispatcher(), { },{"flux":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/node_modules/flux/index.js"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/main.coffee":[function(require,module,exports){ $(function() { - var $c, MessagesComponent, StationActions, StationComponent, StationsComponent, WritingComponent, clean, rend, router, routes; + var $c, MessagesComponent, StationActions, StationComponent, WritingComponent, clean, rend, setSo, so; StationActions = require('./actions/StationActions.coffee'); rend = React.render; window.chat = {}; window.chat.MessagePersistence = require('./persistence/MessagePersistence.coffee'); window.chat.StationPersistence = require('./persistence/StationPersistence.coffee'); window.util = { - mainStation: function() { - switch (window.urb.user.length) { + mainStations: ["court", "floor", "porch"], + mainStationPath: function(user) { + return "~" + user + "/" + (window.util.mainStation(user)); + }, + mainStation: function(user) { + if (!user) { + user = window.urb.user; + } + switch (user.length) { case 3: return "court"; - case 5: + case 6: return "floor"; case 13: return "porch"; } }, + clipAudi: function(audi) { + var j, len, ref, regx, v; + audi = audi.join(" "); + ref = window.util.mainStations; + for (j = 0, len = ref.length; j < len; j++) { + v = ref[j]; + regx = new RegExp("/" + v, "g"); + audi = audi.replace(regx, ""); + } + return audi.split(" "); + }, + expandAudi: function(audi) { + var k, v; + for (k in audi) { + v = audi[k]; + if (v.indexOf("/") === -1) { + audi[k] = v + "/" + (window.util.mainStation(v.slice(1))); + } + } + return audi; + }, create: function(name) { return window.chat.StationPersistence.createStation(name, function(err, res) {}); }, @@ -851,10 +882,10 @@ $(function() { return window.chat.StationPersistence.addSource("main", window.urb.ship, ["~zod/" + name]); }, uuid32: function() { - var i, str, _i, _str; + var _str, i, j, str; str = "0v"; str += Math.ceil(Math.random() * 8) + "."; - for (i = _i = 0; _i <= 5; i = ++_i) { + for (i = j = 0; j <= 5; i = ++j) { _str = Math.ceil(Math.random() * 10000000).toString(32); _str = ("00000" + _str).substr(-5, 5); str += _str + "."; @@ -890,7 +921,7 @@ $(function() { return send(); }, getScroll: function() { - return this.writingPosition = $('#messaging-container').outerHeight(true) + $('#messaging-container').offset().top - $(window).height(); + return this.writingPosition = $('#c').outerHeight(true) + $('#c').offset().top - $(window).height(); }, setScroll: function() { window.util.getScroll(); @@ -907,51 +938,105 @@ $(function() { } } }; + 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 = function() { + so.$n = $('#station-container'); + return so.w = $(window).width(); + }; + setInterval(setSo, 200); + $(window).on('resize', function(e) { + if (so.w > 1170) { + return so.$n.removeClass('m-up m-down m-fixed'); + } + }); + $(window).on('scroll', function(e) { + var dy, sto, top; + 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' && so.w < 1024)) { + so.$n.css({ + left: -1 * $(window).scrollLeft() + }); + } + if (dy > 0) { + if (!so.$n.hasClass('m-down')) { + so.$n.removeClass('m-up').addClass('m-down'); + top = so.cs - so.nh; + if (top < 0) { + top = 0; + } + so.$n.offset({ + top: top + }); + } + if (so.$n.hasClass('m-down') && !so.$n.hasClass('m-fixed') && so.$n.offset().top >= so.cs) { + so.$n.addClass('m-fixed'); + so.$n.attr({ + style: '' + }); + } + } + if (dy < 0) { + if (!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) { + top = 0; + } + if (top > sto && top < sto + so.nh) { + top = sto; + } + return so.$n.offset({ + top: top + }); + } + } + } + }); + so.ls = so.cs; $(window).on('scroll', window.util.checkScroll); window.chat.StationPersistence.listen(); StationComponent = require('./components/StationComponent.coffee'); - StationsComponent = require('./components/StationsComponent.coffee'); MessagesComponent = require('./components/MessagesComponent.coffee'); WritingComponent = require('./components/WritingComponent.coffee'); $c = $('#c'); clean = function() { - React.unmountComponentAtNode($('#stations-container')[0]); - React.unmountComponentAtNode($('#station-parts-container')[0]); - React.unmountComponentAtNode($('#writing-container')[0]); - return React.unmountComponentAtNode($('#messages-container')[0]); + React.unmountComponentAtNode($('#station-container')[0]); + React.unmountComponentAtNode($('#messages-container')[0]); + return React.unmountComponentAtNode($('#writing-container')[0]); }; - routes = { - '': function() { - clean(); - $c.html("
"); - return rend(StationsComponent({}, ""), $('#stations-container')[0]); - }, - '/:station': function(station) { - var $d; - clean(); - StationActions.switchStation(station); - $c.html(""); - $c.append("
"); - $d = $('#messaging-container'); - $d.append("
"); - $d.append("
"); - $d.append("
"); - $c.append("
BOTTOM
"); - rend(StationComponent({}, ""), $('#station-parts-container')[0]); - rend(MessagesComponent({}, ""), $('#messages-container')[0]); - return rend(WritingComponent({}, ""), $('#writing-container')[0]); - } - }; - router = Router(routes); - if (!window.location.hash) { - window.location.hash = "/"; - } - return router.init(); + $c.append("
"); + $c.append("
"); + $c.append("
"); + $c.append("
BOTTOM
"); + rend(StationComponent({}, ""), $('#station-container')[0]); + rend(MessagesComponent({}, ""), $('#messages-container')[0]); + return rend(WritingComponent({}, ""), $('#writing-container')[0]); }); -},{"./actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee","./components/MessagesComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MessagesComponent.coffee","./components/StationComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/StationComponent.coffee","./components/StationsComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/StationsComponent.coffee","./components/WritingComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/WritingComponent.coffee","./persistence/MessagePersistence.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/persistence/MessagePersistence.coffee","./persistence/StationPersistence.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/persistence/StationPersistence.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/node_modules/flux/index.js":[function(require,module,exports){ +},{"./actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee","./components/MessagesComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/MessagesComponent.coffee","./components/StationComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/StationComponent.coffee","./components/WritingComponent.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/components/WritingComponent.coffee","./persistence/MessagePersistence.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/persistence/MessagePersistence.coffee","./persistence/StationPersistence.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/persistence/StationPersistence.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/node_modules/flux/index.js":[function(require,module,exports){ /** * Copyright (c) 2014, Facebook, Inc. * All rights reserved. @@ -5325,13 +5410,13 @@ module.exports = { appl: "radio", path: "/f/" + station + "/" + since }, function(err, res) { - var _ref, _ref1; + var ref, ref1; console.log('m subscription updates'); console.log(res.data); if (res.data.ok === true) { MessageActions.listeningStation(station); } - if ((_ref = res.data) != null ? (_ref1 = _ref.grams) != null ? _ref1.tele : void 0 : void 0) { + if ((ref = res.data) != null ? (ref1 = ref.grams) != null ? ref1.tele : void 0 : void 0) { return MessageActions.loadMessages(res.data.grams); } }); @@ -5341,10 +5426,10 @@ module.exports = { appl: "radio", path: "/f/" + station + "/" + end + "/" + start }, function(err, res) { - var _ref, _ref1; + var ref, ref1; console.log('get'); console.log(res); - if ((_ref = res.data) != null ? (_ref1 = _ref.grams) != null ? _ref1.tele : void 0 : void 0) { + if ((ref = res.data) != null ? (ref1 = ref.grams) != null ? ref1.tele : void 0 : void 0) { MessageActions.loadMessages(res.data.grams, true); return window.urb.unsubscribe({ appl: "radio", @@ -5441,10 +5526,10 @@ module.exports = { appl: "radio", path: "/a/court" }, function(err, res) { - var _ref, _ref1; + var ref, ref1; console.log('membership updates'); console.log(res.data); - if ((_ref = res.data) != null ? (_ref1 = _ref.group) != null ? _ref1.global : void 0 : void 0) { + if ((ref = res.data) != null ? (ref1 = ref.group) != null ? ref1.global : void 0 : void 0) { return StationActions.loadMembers(res.data.group.global); } }); @@ -5466,14 +5551,14 @@ module.exports = { appl: "radio", path: "/ax/" + station }, function(err, res) { - var _ref; console.log('station subscription updates'); console.log(res.data); if (res.data.ok === true) { StationActions.listeningStation(station); } - if ((_ref = res.data.group) != null ? _ref.local : void 0) { - StationActions.loadMembers(station, res.data.group.local); + if (res.data.group) { + res.data.group.global[window.util.mainStationPath(window.urb.user)] = res.data.group.local; + StationActions.loadMembers(res.data.group.global); } if (res.data.config) { return StationActions.loadConfig(station, res.data.config); @@ -5485,7 +5570,7 @@ module.exports = { },{"../actions/StationActions.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/actions/StationActions.coffee"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/MessageStore.coffee":[function(require,module,exports){ -var EventEmitter, MessageDispatcher, MessageStore, moment, _fetching, _last, _listening, _messages, _station, _typing; +var EventEmitter, MessageDispatcher, MessageStore, _fetching, _last, _listening, _messages, _station, _typing, moment; moment = require('moment-timezone'); @@ -5537,6 +5622,16 @@ MessageStore = _.merge(new EventEmitter, { getTyping: function() { return _typing; }, + getLastAudience: function() { + var messages; + if (_.keys(_messages).length === 0) { + return []; + } + messages = _.sortBy(_messages, function(_message) { + return _message.thought.statement.time; + }); + return _.keys(messages[messages.length - 1].thought.audience); + }, setTyping: function(state) { return _typing = state; }, @@ -5621,7 +5716,7 @@ module.exports = MessageStore; },{"../dispatcher/Dispatcher.coffee":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/dispatcher/Dispatcher.coffee","events":"/usr/local/lib/node_modules/watchify/node_modules/browserify/node_modules/events/events.js","moment-timezone":"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/node_modules/moment-timezone/index.js"}],"/Users/galen/Documents/src/urbit-test/urb/zod/main/pub/talk/src/js/stores/StationStore.coffee":[function(require,module,exports){ -var EventEmitter, StationDispatcher, StationStore, _audience, _config, _listening, _members, _station, _stations, _typing; +var EventEmitter, StationDispatcher, StationStore, _audience, _config, _listening, _members, _station, _stations, _typing, _validAudience; EventEmitter = require('events').EventEmitter; @@ -5641,6 +5736,8 @@ _config = {}; _typing = {}; +_validAudience = true; + StationStore = _.merge(new EventEmitter, { removeChangeListener: function(cb) { return this.removeListener("change", cb); @@ -5657,6 +5754,12 @@ StationStore = _.merge(new EventEmitter, { setAudience: function(audience) { return _audience = audience; }, + getValidAudience: function() { + return _validAudience; + }, + setValidAudience: function(valid) { + return _validAudience = valid; + }, toggleAudience: function(station) { if (_audience.indexOf(station) !== -1) { return _audience.splice(_audience.indexOf(station), 1); @@ -5678,21 +5781,26 @@ StationStore = _.merge(new EventEmitter, { ship: ship }; }, - changeMember: function(dir, name, ship) { - if (dir === "out") { - _members = _.filter(_members, function(_member) { - return _member.ship !== ship; - }); + loadMembers: function(members) { + var list, member, presence, results, station; + _members = {}; + results = []; + for (station in members) { + list = members[station]; + results.push((function() { + var results1; + results1 = []; + for (member in list) { + presence = list[member]; + if (!_members[member]) { + _members[member] = {}; + } + results1.push(_members[member][station] = presence); + } + return results1; + })()); } - if (dir === "in") { - return _members.push({ - name: name, - ship: ship - }); - } - }, - loadMembers: function(station, members) { - return _members[station] = members; + return results; }, getMembers: function() { return _members; @@ -5730,8 +5838,8 @@ StationStore = _.merge(new EventEmitter, { return _station; }, joinStation: function(station) { - var _ref; - if (((_ref = _config.court) != null ? _ref.sources.indexOf(station) : void 0) === -1) { + var ref; + if (((ref = _config.court) != null ? ref.sources.indexOf(station) : void 0) === -1) { return _config.court.sources.push(station); } }, @@ -5762,6 +5870,10 @@ StationStore.dispatchToken = StationDispatcher.register(function(payload) { StationStore.setAudience(action.audience); StationStore.emitChange(); break; + case 'station-set-valid-audience': + StationStore.setValidAudience(action.valid); + StationStore.emitChange(); + break; case 'station-switch': StationStore.setAudience([]); StationStore.setStation(action.station); @@ -5789,7 +5901,7 @@ StationStore.dispatchToken = StationDispatcher.register(function(payload) { StationStore.emitChange(); break; case "members-load": - StationStore.loadMembers(action.station, action.members); + StationStore.loadMembers(action.members); StationStore.emitChange(); break; case "typing-set": diff --git a/main/pub/talk/src/js/package.json b/main/pub/talk/src/js/package.json index b5f836ae1..dbb272bee 100644 --- a/main/pub/talk/src/js/package.json +++ b/main/pub/talk/src/js/package.json @@ -1,6 +1,10 @@ { "name": "urbit-radio", "version": "0.0.0", + "repository": { + "type":"git", + "url":"https://github.com/urbit/urbit" + }, "description": "urbit radio frontend", "main": "main.js", "dependencies": { diff --git a/main/pub/talk/src/js/persistence/MessagePersistence.coffee b/main/pub/talk/src/js/persistence/MessagePersistence.coffee index 379b25216..18f9bf58e 100644 --- a/main/pub/talk/src/js/persistence/MessagePersistence.coffee +++ b/main/pub/talk/src/js/persistence/MessagePersistence.coffee @@ -3,7 +3,7 @@ MessageActions = require '../actions/MessageActions.coffee' module.exports = listenStation: (station,since) -> window.urb.subscribe { - appl:"rodeo" + appl:"radio" path:"/f/#{station}/#{since}" }, (err,res) -> console.log('m subscription updates') @@ -15,7 +15,7 @@ module.exports = get: (station,start,end) -> window.urb.subscribe { - appl:"rodeo" + appl:"radio" path:"/f/#{station}/#{end}/#{start}" }, (err,res) -> console.log 'get' @@ -23,7 +23,7 @@ module.exports = if res.data?.grams?.tele MessageActions.loadMessages res.data.grams,true window.urb.unsubscribe { - appl:"rodeo" + appl:"radio" path:"/f/#{station}/#{end}/#{start}" }, (err,res) -> console.log 'done' @@ -31,8 +31,8 @@ module.exports = sendMessage: (message,cb) -> window.urb.send { - appl:"rodeo" - mark:"rodeo-command" + appl:"radio" + mark:"radio-command" data: publish: [ message diff --git a/main/pub/talk/src/js/persistence/StationPersistence.coffee b/main/pub/talk/src/js/persistence/StationPersistence.coffee index d774bf63b..aba591952 100644 --- a/main/pub/talk/src/js/persistence/StationPersistence.coffee +++ b/main/pub/talk/src/js/persistence/StationPersistence.coffee @@ -3,8 +3,8 @@ StationActions = require '../actions/StationActions.coffee' module.exports = createStation: (name,cb) -> window.urb.send { - appl:"rodeo" - mark:"rodeo-command" + appl:"radio" + mark:"radio-command" data: design: party:name @@ -16,8 +16,8 @@ module.exports = removeStation: (name,cb) -> window.urb.send { - appl:"rodeo" - mark:"rodeo-command" + appl:"radio" + mark:"radio-command" data: design: party:name @@ -26,8 +26,8 @@ module.exports = setSources: (station,ship,sources) -> send = - appl:"rodeo" - mark:"rodeo-command" + appl:"radio" + mark:"radio-command" data: design: party:station @@ -41,7 +41,7 @@ module.exports = members: -> window.urb.subscribe { - appl:"rodeo" + appl:"radio" path:"/a/court" }, (err,res) -> console.log 'membership updates' @@ -51,7 +51,7 @@ module.exports = listen: -> window.urb.subscribe { - appl:"rodeo" + appl:"radio" path:"/" }, (err,res) -> console.log 'house updates' @@ -61,14 +61,15 @@ module.exports = listenStation: (station) -> window.urb.subscribe { - appl:"rodeo" + appl:"radio" path:"/ax/#{station}" }, (err,res) -> console.log('station subscription updates') console.log(res.data) if res.data.ok is true StationActions.listeningStation station - if res.data.group?.local - StationActions.loadMembers station,res.data.group.local + if res.data.group + res.data.group.global[window.util.mainStationPath(window.urb.user)] = res.data.group.local + StationActions.loadMembers res.data.group.global if res.data.config StationActions.loadConfig station,res.data.config \ No newline at end of file diff --git a/main/pub/talk/src/js/stores/MessageStore.coffee b/main/pub/talk/src/js/stores/MessageStore.coffee index ef533599f..1bd902a29 100644 --- a/main/pub/talk/src/js/stores/MessageStore.coffee +++ b/main/pub/talk/src/js/stores/MessageStore.coffee @@ -33,6 +33,11 @@ MessageStore = _.merge new EventEmitter,{ 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 setListening: (station) -> diff --git a/main/pub/talk/src/js/stores/StationStore.coffee b/main/pub/talk/src/js/stores/StationStore.coffee index 77c3f6085..27a16970f 100644 --- a/main/pub/talk/src/js/stores/StationStore.coffee +++ b/main/pub/talk/src/js/stores/StationStore.coffee @@ -1,14 +1,16 @@ -EventEmitter = require('events').EventEmitter +EventEmitter = require('events').EventEmitter StationDispatcher = require '../dispatcher/Dispatcher.coffee' -_audience = [] -_members = {} -_stations = [] -_listening = [] -_station = null -_config = {} -_typing = {} +_audience = [] +_members = {} +_stations = [] +_listening = [] +_station = null +_config = {} +_typing = {} + +_validAudience = true StationStore = _.merge new EventEmitter,{ removeChangeListener: (cb) -> @removeListener "change", cb @@ -21,6 +23,10 @@ StationStore = _.merge new EventEmitter,{ setAudience: (audience) -> _audience = audience + getValidAudience: -> _validAudience + + setValidAudience: (valid) -> _validAudience = valid + toggleAudience: (station) -> if _audience.indexOf(station) isnt -1 _audience.splice _audience.indexOf(station), 1 @@ -35,14 +41,12 @@ StationStore = _.merge new EventEmitter,{ getMember: (ship) -> {ship:ship} - changeMember: (dir,name,ship) -> - if dir is "out" - _members = _.filter _members, (_member) -> - return (_member.ship isnt ship) - if dir is "in" - _members.push {name:name, ship:ship} - - loadMembers: (station,members) -> _members[station] = members + loadMembers: (members) -> + _members = {} + for station,list of members + for member,presence of list + _members[member] = {} if not _members[member] + _members[member][station] = presence getMembers: -> _members @@ -94,6 +98,10 @@ StationStore.dispatchToken = StationDispatcher.register (payload) -> StationStore.setAudience action.audience StationStore.emitChange() break + when 'station-set-valid-audience' + StationStore.setValidAudience action.valid + StationStore.emitChange() + break when 'station-switch' StationStore.setAudience [] StationStore.setStation action.station @@ -103,7 +111,7 @@ StationStore.dispatchToken = StationDispatcher.register (payload) -> StationStore.setListening action.station StationStore.emitChange() break - when "config-load" + when "config-load" #[name:'loadConfig', args:['station', 'config']] StationStore.loadConfig action.station,action.config StationStore.emitChange() break @@ -111,7 +119,10 @@ StationStore.dispatchToken = StationDispatcher.register (payload) -> StationStore.loadStations action.stations StationStore.emitChange() 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.unsetStation action.station StationStore.emitChange() @@ -121,7 +132,7 @@ StationStore.dispatchToken = StationDispatcher.register (payload) -> StationStore.emitChange() break when "members-load" - StationStore.loadMembers action.station,action.members + StationStore.loadMembers action.members StationStore.emitChange() break when "typing-set"