moved talk, example module

This commit is contained in:
Galen Wolfe-Pauly 2016-01-24 16:54:30 -08:00
parent e2924c2396
commit e5b8d19274
30 changed files with 12 additions and 27965 deletions

View File

@ -18,8 +18,8 @@
;head
;title: Bootstrap Test - ~2016.1
;meta(name "viewport", content "width=device-width, initial-scale=1");
;link(rel "stylesheet", href "/home/lib/fonts.css");
;link(rel "stylesheet", href "/home/lib/bootstrap.css");
;link(rel "stylesheet", href "/home/lib/css/fonts.css");
;link(rel "stylesheet", href "/home/lib/css/bootstrap.css");
;script(src "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js");
==
;body

6
pub/module/main.js Normal file
View File

@ -0,0 +1,6 @@
main = {
mount: function() { console.log('mount.') },
unmount: function() { console.log('unmount.') }
}
window.tree.modules.talk = main

1
pub/module/mod.md Normal file
View File

@ -0,0 +1 @@
<module path="/home/pub/module/main.js" name="talk" />

View File

@ -31,10 +31,10 @@
"lodash.js/2.4.1/lodash.min.js"
"react/0.13.1/react.js"
==
;script(type "text/javascript", src "{?:(aut "/~~" "")}/~/at/home/lib/urb.js");
;script(type "text/javascript", src "{?:(aut "/~~" "")}/~/at/home/lib/js/urb.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");
;link(type "text/css", rel "stylesheet", href "/home/pub/talk/src/css/main.css");
;link(type "text/css", rel "stylesheet", href "/home/pub/talk/main.css");
;title: Talk
==
;body
@ -45,6 +45,6 @@
;div#scrolling: BOTTOM
==
;script: window.talk = {(pojo (joba 'mainStation' s/man))}
;script(type "text/javascript", src "/home/pub/talk/src/js/main.js");
;script(type "text/javascript", src "/home/pub/talk/main.js");
==
==

View File

@ -1,84 +0,0 @@
@font-face {
font-family: "bau";
src: url("//storage.googleapis.com/urbit-extra/bau.woff");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "bau";
src: url("//storage.googleapis.com/urbit-extra/bau-italic.woff");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: "bau";
src: url("//storage.googleapis.com/urbit-extra/bau-medium.woff");
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: "bau";
src: url("//storage.googleapis.com/urbit-extra/bau-mediumitalic.woff");
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: "bau";
src: url("//storage.googleapis.com/urbit-extra/bau-bold.woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "bau";
src: url("//storage.googleapis.com/urbit-extra/bau-bolditalic.woff");
font-weight: 600;
font-style: italic;
}
@font-face {
font-family: "bau";
src: url("//storage.googleapis.com/urbit-extra/bau-super.woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "bau";
src: url("//storage.googleapis.com/urbit-extra/bau-superitalic.woff");
font-weight: 600;
font-style: italic;
}
@font-face {
font-family: "scp";
src: url("//storage.googleapis.com/urbit-extra/scp-extralight.woff");
font-weight: 200;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//storage.googleapis.com/urbit-extra/scp-light.woff");
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//storage.googleapis.com/urbit-extra/scp-regular.woff");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//storage.googleapis.com/urbit-extra/scp-medium.woff");
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//storage.googleapis.com/urbit-extra/scp-bold.woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//storage.googleapis.com/urbit-extra/scp-black.woff");
font-weight: 700;
font-style: normal;
}

View File

@ -1,565 +0,0 @@
//
// fonts first
//
@import 'fonts'
html
body
height 100%
font-family "bau"
.type
font-family "scp"
input
font-size 1rem
-webkit-appearance none
border-radius 0
font-family "bau"
#length
.time
letter-spacing 0
.time
font-weight 200
letter-spacing .1rem
color #555
#length
.audi
.time
.station
#audience .iden
font-size .8rem
line-height 1rem
#length
letter-spacing .1rem
#writing-container:focus #length
display inline
// input.join
// .iden
// .audi
// #station
// font-size .7rem
.ship
text-transform uppercase
letter-spacing .05rem
html
body
font-size 18px
//
// containers
//
body
background-color #fefefe
padding 0
margin 0
.hidden
display none
#c
position absolute
top 0rem
left 50%
width 58rem
margin-left -29rem
margin-bottom 6rem
#station-container
position fixed
width 58rem
max-height 4rem
background-color rgba(255,255,255,.95)
color #555
overflow hidden
z-index 10
border-bottom 1px solid #ddd
-webkit-transition max-height .2s
#station #station-container
padding-top 1rem
min-width 30rem
text-align right
#writing-container
margin-top 2rem
margin-bottom 1rem
#messages-container
vertical-align top
margin-top 5rem
//
// components
//
.caret
.circle
display inline-block
.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
margin-top 2px
.circle
width 6px
height 6px
border 3px solid black
border-radius 6px
margin-top 2px
//
// station
//
#station-container #where .caret
-webkit-transform rotate(0deg)
-webkit-transform-origin 0 50%
-webkit-transition -webkit-transform .2s
#station-container #where .caret
margin-top 9px
border-top 9px solid transparent
border-right 9px solid transparent
border-bottom 9px solid transparent
border-left 9px solid white
-webkit-transition border-left-color .2s
#head
width 100%
height 4rem
color #333
border-bottom 1px solid #ddd
#station-container h1
display none
color #555
font-weight 400
font-size 1rem
letter-spacing .06rem
display inline-block
line-height 1.2rem
#station-container h1:after
content ""
margin-left .6rem
#station-container .audi
#station-container .iden > div
background-color transparent
#who
width 16rem
#stations
width 15rem
padding-bottom 1rem
border-left 16rem solid transparent
#station-container #head .ship
font-size .9rem
font-weight 400
#station-container:hover #where
color white
-webkit-transition color .2s
#station-container:hover #where
color rgb(240,73,65)
-webkit-transition color .2s
#station-container:hover #where .caret
border-left-color rgb(240,73,65)
-webkit-transition border-left-color .2s
#stations
#audience
#head > div
#where > div
display inline-block
vertical-align top
#where > div
margin-right 1rem
text-transform capitalize
letter-spacing .05rem
font-size 1.6rem
#where .slat
font-weight 500
#where .slat:after
margin-left 1rem
content ""
#head > div
height 2rem
line-height 2rem
margin-top 1rem
#where .caret
border-left-color white
#who > div
vertical-align middle
#members
margin-bottom 1rem
#members > div
display block
max-width 24rem
overflow hidden
white-space nowrap
#members > div:hover
white-space normal
#members > div div
display inline-block
vertical-align bottom
#members .audi
margin-right .3rem
margin-top 0
#members .iden
min-width 10rem
.station div
display inline-block
.station .path
text-transform uppercase
.station .remove
opacity 0
cursor pointer
width .6rem
margin-left .6rem
line-height 1rem
font-size 1.2rem
font-weight 500
color #ff0000
vertical-align top
.station:hover .remove
opacity 1
// add source
.sour-ctrl input
color #555
background-color transparent
border none
font-size .8rem
line-height 1.2rem
letter-spacing .05rem
margin-top .6rem
font-weight 300
text-align left
outline none
cursor pointer
text-transform uppercase
border-bottom 2px solid transparent
.sour-ctrl input:focus
border-bottom 2px solid #fff
.sour-ctrl input::-webkit-input-placeholder
font-weight 400
font-size 1.2rem
margin-left .6rem
color #555
.sour-ctrl input:focus::-webkit-input-placeholder
color transparent
//
// messages
//
.message
padding-top .3rem
margin-bottom .6rem
#messages .message .time
#messages .message .audi
opacity 0
margin-left 2rem
#messages .message:hover .time
#messages .message:hover .audi
opacity 1
#messages .message .attr
position absolute
overflow hidden
max-height 1.6rem
white-space nowrap
// #writing-container
// #messages .message.first
// border-top 1px solid #ededed
#writing-container
padding-top .3rem
#messages .message.first
#messages .message.same .audi
margin-top 0
#messages .message.same .type
opacity 0
#messages .message.same .iden
display none
#messages .message:hover .type
color rgb(240,73,65)
#messages .message.attr
max-height 2rem
-webkit-transition max-height 2s, color .1s linear
#messages .message:hover .attr
max-height 6rem
padding-bottom 1rem
z-index 3
-webkit-transition max-height .2s, color .1s linear
#messages .message:hover .attr > div
max-width 48rem
#messages .message .ship
#messages .message .audi > div
cursor pointer
#messages .message.new
border-top 1px solid #e5e5e5
.member
width 12rem
margin .3rem .6rem .3rem 0
#messages
height auto
.message.pending
color #ccc
.message.say .mess
font-style italic
.message.exp .mess
font-family monospace
a
text-decoration underline
color inherit
.sig
.type
margin-left 1rem
float left
width 1rem
.type
height 2rem
.sig
font-size 2rem
margin-left .7rem
margin-right .3rem
.sig:before
content "~"
.type.private:before
content attr(data-glyph)
font-size 1rem
line-height 1.1rem
.type.public:before
content attr(data-glyph)
font-size .8rem
line-height 1.2rem
.mess
.iden
#station .member div
#writing
display inline-block
.mess
#writing
#length
vertical-align top
.attr > div
line-height 1.4rem
max-width 16rem
.attr
text-align left
display inline-block
max-height 1.2rem
margin-right .3rem
min-width 16rem
background-color white
.attr .iden
line-hieght 1.4rem
.audi
.station .path
white-space nowrap
overflow hidden
text-transform uppercase
letter-spacing .05rem
.audi
margin-top 1rem
background-color #fff
.audi > div
margin-right .3rem
max-width 16rem
display block
.iden > div
max-width 11rem
display inline-block
font-size .9rem
.iden > div
.audi > div
background-color white
overflow hidden
white-space nowrap
text-overflow ellipsis
-webkit-transition max-width .2s
.audi > div:last-child
margin-right 0
.iden > div:hover
.audi > div:hover
position relative
-webkit-transition max-width .2s
.mess
letter-spacing .03rem
word-wrap break-word
margin-left 16.3rem
.mess
#writing
.iden > div:hover
.audi > div:hover
max-width 42rem
.iden > div:hover
padding-right 3rem
.mess
#writing
font-size 1.2rem
//
// writing
//
#writing
min-height 1.6rem
min-width 1.3rem
max-width 32rem
line-height 2rem
outline none
padding .3rem .1rem
margin-top -.3rem
border-bottom 3px solid #555
.writing
padding-top .3rem
.writing #length
display inline
margin-left 1rem
margin-top 1.2rem
.writing .attr
line-height 1.6rem
vertical-align top
margin-left 2rem
min-width 14rem
.writing .iden
display block
width 100%
.writing .iden .ship
margin-right .3rem
#audi
display inline-block
margin-right -.2rem
margin-bottom .3rem
outline none
overflow hidden
max-width 12rem
min-width 1rem
padding .3rem .1rem .1rem 0
border-bottom 2px solid #555
.valid-false
color #ff2f2f !important
//
// scrolling
//
#scrolling
display none
.scrolling #scrolling
position fixed
bottom 3rem
left 2rem
height 1rem
padding 1rem
height 2rem
background-color #f9f9f9
font-weight 500
font-size .8rem
text-transform uppercase
//
// offline
//
body:not(.offline) #offline
display none
#offline
transition: color 0.25s ease
#offline.error
color: red
@import 'mobile'

View File

@ -1,91 +0,0 @@
/* computers --------*/
@media only screen and (min-width: 1024px)
#station-container:hover
max-height 30rem
height auto
-webkit-transition max-height .2s
#station-container:hover #where .caret
transform rotate(90deg)
transform-origin 0 50%
-webkit-transform rotate(90deg)
-webkit-transition -webkit-transform .2s
/* laptops / small screens ----------- */
@media only screen and (max-width: 1170px)
#station-container.open
max-height 30rem
height auto
-webkit-transition max-height .2s
#station-container.open #where .caret
transform rotate(90deg)
transform-origin 0 50%
-webkit-transform rotate(90deg)
-webkit-transition -webkit-transform .2s
#c
#station-container
width 96%
left 0
margin-left 2%
margin-right 2%
.mess
#writing
max-width 60%
line-height 1.6rem
.attr
#stations
#where
width 20%
min-width 20%
#audience
#who
width 60%
#writing
padding .1rem
#station-container.m-down
#station-container.m-up
position absolute
#station-container.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
#stations
#audience
width 96%
#stations
#audience
.sour-ctrl input
text-align left
#station
cursor pointer
#station-container.open
max-height 30rem
height auto
-webkit-transition max-height .2s
#station-container.open #where .caret
transform rotate(90deg)
transform-origin 0 50%
-webkit-transform rotate(90deg)
-webkit-transition -webkit-transform .2s

View File

@ -1,75 +0,0 @@
Dispatcher = require '../dispatcher/Dispatcher.coffee'
_persistence = require '../persistence/MessagePersistence.coffee'
Persistence = _persistence MessageActions: module.exports =
loadMessages: (messages,last,get) ->
Dispatcher.handleServerAction {messages,last,get,type:"messages-load"}
listenStation: (station,date) ->
if not date then date = window.urb.util.toDate(new Date())
Persistence.listenStation station,date
listeningStation: (station) ->
Dispatcher.handleViewAction {station,type:"messages-listen"}
setTyping: (state) ->
Dispatcher.handleViewAction {state,type:"messages-typing"}
getMore: (station,start,end) ->
Dispatcher.handleViewAction type:"messages-fetch"
Persistence.get station,start,end
sendMessage: (txt,audience) ->
serial = window.util.uuid32()
# audience.push window.util.mainStationPath window.urb.user
audience = _.uniq audience
_audi = {}
for k,v of audience
_audi[v] =
envelope:
visible:true
sender:null
delivery:"pending"
speech = lin: {txt, say:true}
if txt[0] is "@"
speech.lin.txt = speech.lin.txt.slice(1).trim()
speech.lin.say = false
else if txt[0] is "#"
speech = eval: speech.lin.txt.slice(1).trim()
else if window.urb.util.isURL(txt)
speech = url: txt
speeches =
if not (speech.lin?.txt.length > 64)
[speech]
else
{say,txt} = speech.lin
txt.match(/(.{1,64}$|.{0,64} |.{64}|.+$)/g).map (s,i)->
say ||= i isnt 0
lin: {say, txt:
if s.slice -1 isnt " "
s
else s.slice 0,-1
}
for speech in speeches
message =
ship:window.urb.ship
thought:
serial:window.util.uuid32()
audience:_audi
statement:
bouquet:[]
speech:speech
date: Date.now()
Dispatcher.handleViewAction {message,type:"message-send"}
Persistence.sendMessage message.thought

View File

@ -1,31 +0,0 @@
Dispatcher = require '../dispatcher/Dispatcher.coffee'
serverAction = (f)-> ()-> Dispatcher.handleServerAction f.apply this,arguments
viewAction = (f)-> ()-> Dispatcher.handleViewAction f.apply this,arguments
_persistence = require '../persistence/StationPersistence.coffee'
Persistence = _persistence StationActions: module.exports =
loadGlyphs: serverAction (glyphs) -> {glyphs,type:"glyphs-load"}
loadMembers: serverAction (members) -> {members,type:"members-load"}
loadStations: serverAction (stations) -> {stations,type:"stations-load"}
loadConfig: serverAction (station,config) -> {station,config,type:"config-load"}
setTyping: viewAction (station,state) -> {station,state,type:"typing-set"}
setAudience: viewAction (audience) -> {audience,type:"station-set-audience"}
setValidAudience: viewAction (valid) -> {valid,type:"station-set-valid-audience"}
toggleAudience: viewAction (station) -> {station,type:"station-audience-toggle"}
switchStation: viewAction (station) -> {station,type:"station-switch"}
listeningStation: viewAction (station) -> {station,type:"station-listen"}
createStation: (station) ->
Dispatcher.handleViewAction {station,type: "station-create"}
Persistence.createStation station
listen: () -> Persistence.listen()
ping: (_ping) -> Persistence.ping _ping
removeStation: (station) -> Persistence.removeStation station
listenStation: (station) -> Persistence.listenStation station
createStation: (name) -> Persistence.createStation name
setSources: (station,sources) ->
Persistence.setSources station,window.urb.ship,sources

View File

@ -1,12 +0,0 @@
recl = React.createClass
{div,input,textarea} = React.DOM
module.exports = recl
render: ->
if @props.ship[0] is "~" then @props.ship = @props.ship.slice(1)
k = "ship"
k+= " #{@props.presence}" if @props.presence
div {className:"iden"}, [
# div {}, @props.glyph || "*"
div {className:k}, @props.ship
]

View File

@ -1,213 +0,0 @@
moment = require 'moment-timezone'
clas = require 'classnames'
recl = React.createClass
{div,pre,br,span,input,textarea,a} = React.DOM
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
displayName: "Message"
lz: (n) -> if n<10 then "0#{n}" else "#{n}"
convTime: (time) ->
d = new Date time
h = @lz d.getHours()
m = @lz d.getMinutes()
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()
return if user.toLowerCase() is 'system'
@props._handlePm user
renderSpeech: (speech)-> switch
when (con = speech.lin) or (con = speech.app) or
(con = speech.exp) or (con = speech.tax)
con.txt
when (con = speech.url)
(a {href:con.txt,target:"_blank"}, con.txt)
when (con = speech.mor) then con.map @renderSpeech
else "Unknown speech type:" + (" %"+x for x of speech).join ''
render: ->
# pendingClass = clas pending: @props.pending isnt "received"
delivery = _.uniq _.pluck @props.thought.audience, "delivery"
speech = @props.thought.statement.speech
attachments = []
while speech.fat?
attachments.push pre {}, speech.fat.tor.tank.join("\n")
speech = speech.fat.taf # XX
if !speech? then return;
name = if @props.name then @props.name else ""
aude = _.keys @props.thought.audience
audi = window.util.clipAudi(aude).map (_audi) -> (div {}, _audi.slice(1))
mainStation = window.util.mainStationPath(window.urb.user)
type = if mainStation in aude then 'private' else 'public'
className = clas {message:true},
(if @props.sameAs then "same" else "first"),
(if delivery.indexOf("received") isnt -1 then "received" else "pending"),
{say: speech.lin?.say is false, url: speech.url, 'new': @props.unseen},
switch
when speech.app? then "say"
when speech.exp? then "exp"
div {className}, [
(div {className:"attr"}, [
div {className:"type #{type}", "data-glyph": @props.glyph || "*"}
(div {onClick:@_handlePm},
(React.createElement Member,{ship:@props.ship,glyph:@props.glyph}))
div {onClick:@_handleAudi,className:"audi"}, audi
div {className:"time"}, @convTime @props.thought.statement.date
])
div {className:"mess"},
(@renderSpeech speech)
if attachments.length
div {className:"fat"}, attachments
]
module.exports = recl
displayName: "Messages"
pageSize: 50
paddingTop: 100
stateFromStore: -> {
messages:MessageStore.getAll()
last:MessageStore.getLast()
fetching:MessageStore.getFetching()
listening:MessageStore.getListening()
station:window.talk.mainStation
stations:StationStore.getStations()
configs:StationStore.getConfigs()
typing:MessageStore.getTyping()
glyphs:StationStore.getGlyphMap()
}
getInitialState: -> @stateFromStore()
_blur: ->
@focussed = false
@lastSeen = @last
_focus: ->
@focussed = true
@lastSeen = null
$('.message.new').removeClass 'new'
document.title = document.title.replace /\ \([0-9]*\)/, ""
checkMore: ->
if $(window).scrollTop() < @paddingTop &&
@state.fetching is false &&
this.state.last &&
this.state.last > 0
end = @state.last-@pageSize
end = 0 if end < 0
@lastLength = @length
MessageActions.getMore @state.station,(@state.last+1),end
setAudience: ->
return if not @last
if _.keys(@last.thought.audience).length > 0 and @state.typing is false and
_.difference(_.keys(@last.thought.audience),@state.audi).length is 0
StationActions.setAudience _.keys(@last.thought.audience)
sortedMessages: (messages) ->
_.sortBy messages, (_message) ->
_message.pending = _message.thought.audience[station]
_message.key
#_message.thought.statement.date
componentDidMount: ->
MessageStore.addChangeListener @_onChangeStore
StationStore.addChangeListener @_onChangeStore
if @state.station and
@state.listening.indexOf(@state.station) is -1
MessageActions.listenStation @state.station
checkMore = @checkMore
$(window).on 'scroll', checkMore
@focussed = true
$(window).on 'blur', @_blur
$(window).on 'focus', @_focus
window.util.setScroll()
componentDidUpdate: ->
$window = $(window)
if @lastLength
st = $window.height()
$window.scrollTop st
@lastLength = null
else
if not window.util.isScrolling()
window.util.setScroll()
else
console.log 'scrolling'
if @focussed is false and @last isnt @lastSeen
_messages = @sortedMessages @state.messages
d = _messages.length-_messages.indexOf(@lastSeen)-1
t = document.title
if document.title.match(/\([0-9]*\)/)
document.title = document.title.replace /\([0-9]*\)/, "(#{d})"
else
document.title = document.title + " (#{d})"
componentWillUnmount: ->
MessageStore.removeChangeListener @_onChangeStore
StationStore.removeChangeListener @_onChangeStore
_onChangeStore: -> @setState @stateFromStore()
_handlePm: (user) ->
audi = [window.util.mainStationPath(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 = @sortedMessages @state.messages
@last = _messages[_messages.length-1]
if @last?.ship && @last.ship is window.urb.user then @lastSeen = @last
@length = _messages.length
setTimeout =>
@checkMore() if length < @pageSize
, 1
lastIndex = if @lastSeen then _messages.indexOf(@lastSeen)+1 else null
lastSaid = null
div {id: "messages"}, _messages.map (_message,k) =>
nowSaid = [_message.ship,_message.thought.audience]
glyph = window.util.getGlyph @state.glyphs, _.keys _message.thought.audience
{station} = @state
mess = {
glyph, station, @_handlePm, @_handleAudi,
unseen: lastIndex and lastIndex is k
sameAs: _.isEqual lastSaid, nowSaid
}
lastSaid = nowSaid
if _message.thought.statement.speech?.app
mess.ship = "system"
React.createElement Message, (_.extend {}, _message, mess)

View File

@ -1,119 +0,0 @@
recl = React.createClass
{div,style,input,textarea,h1,a} = React.DOM
StationStore = require '../stores/StationStore.coffee'
StationActions = require '../actions/StationActions.coffee'
Member = require './MemberComponent.coffee'
module.exports = recl
displayName: "Station"
stateFromStore: -> {
audi:StationStore.getAudience()
members:StationStore.getMembers()
station:window.talk.mainStation
stations:StationStore.getStations()
configs:StationStore.getConfigs()
typing:StationStore.getTyping()
listening:StationStore.getListening()
}
getInitialState: -> @stateFromStore()
componentDidMount: ->
@$el = $(@getDOMNode())
@$input = @$el.find('input')
StationStore.addChangeListener @_onChangeStore
if @state.listening.indexOf(@state.station) is -1
StationActions.listenStation @state.station
componentWillUnmount: ->
StationStore.removeChangeListener @_onChangeStore
_onChangeStore: ->
@setState @stateFromStore()
_toggleOpen: (e) ->
if $(e.target).closest('.sour-ctrl').length > 0
return
$("#station-container").toggleClass 'open'
validateSource: (s) ->
if @state.configs[@state.station].sources.indexOf(s) isnt -1
return false
if s.length < 5
return false
if s[0] isnt "~"
return false
if s.indexOf("/") is -1
return false
return true
_keyUp: (e) ->
$('.sour-ctrl .join').removeClass 'valid-false'
if e.keyCode is 13
v = @$input.val().toLowerCase()
if v[0] isnt "~" then v = "~#{v}"
if @validateSource v
_sources = _.clone @state.configs[@state.station].sources
_sources.push v
StationActions.setSources @state.station,_sources
@$input.val('')
@$input.blur()
else
$('.sour-ctrl .join').addClass 'valid-false'
_remove: (e) ->
e.stopPropagation()
e.preventDefault()
_station = $(e.target).attr "data-station"
_sources = _.clone @state.configs[@state.station].sources
_sources.splice _sources.indexOf(_station),1
StationActions.setSources @state.station,_sources
render: ->
if window.urb.user isnt window.urb.ship #foreign
return div {id:"station"}
parts = []
members = []
if @state.station and @state.members
members = _.map @state.members, (stations,member) ->
audi = _.map stations,(presence,station) -> (div {className:"audi"}, station.slice(1))
(div {}, [(React.createElement Member, {ship:member}),audi])
else
members = ""
sourceInput = [(input {className:"join",onKeyUp:@_keyUp,placeholder:"+"})]
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 = _.map _sources,(source) =>
(div {className:"station"}, [
(div {className:"path"}, source.slice(1))
(div {className:"remove",onClick:_remove,"data-station":source},"×"),
])
else
sources = ""
(div {id:"station",onClick:@_toggleOpen},
(div {id:"head"},
(div {id:"who"},
div {className:"sig"}
div {className:"ship"},"#{window.urb.user}"
)
(div {id:"where"},
div {className:"slat"},"talk"
div {className:"path"} #, window.util.mainStation(window.urb.user))
div {className:"caret"}
)
div {id:"offline"}, "Warning: no connection to server."
)
div {id:"stations"}, (h1 {}, "Listening to"),(div {},sources),sourceCtrl
div {id:"audience"}, div {}, (h1 {}, "Talking to"),(div {id:"members"},members)
)

View File

@ -1,61 +0,0 @@
recl = React.createClass
{div,input} = React.DOM
StationStore = require '../stores/StationStore.coffee'
StationActions = require '../actions/StationActions.coffee'
module.exports = recl
stateFromStore: -> {
stations: StationStore.getStations()
station: "~zod/court"
}
getInitialState: -> @stateFromStore()
componentDidMount: ->
@$el = $ @getDOMNode()
@$add = $ '#stations .add'
@$input = @$el.find 'input'
StationStore.addChangeListener @_onChangeStore
componentWillUnmount: ->
StationStore.removeChangeListener @_onChangeStore
_onChangeStore: -> @setState @stateFromStore()
_click: (e) ->
s = $(e.target).closest('.station').find('.name').text()
window.location.hash = "/#{s.toLowerCase()}"
_keyUp: (e) ->
if e.keyCode is 13
v = @$input.val().toLowerCase()
if @state.stations.indexOf(v) is -1
StationActions.createStation v
@$input.val('')
@$input.blur()
_remove: (e) ->
_station = $(e.target).parent().find('.name').text()
_stations = _.without @state.stations,_station
StationActions.removeStation _station,_stations
e.stopPropagation()
e.preventDefault()
render: ->
station = @state.station
_click = @_click
_remove = @_remove
stations = @state.stations.map (_station) ->
k = "station"
parts = [(div {className:"name"}, _station.name)]
if _station.name isnt window.util.mainStation()
parts.push (div {className:"remove",onClick:_remove,dataStation:_station.name},"×")
div {className:k,onClick:_click},parts
div {id:"stations"}, [
div {className:"stations"},stations
div {className:"join-ctrl"}, [
input {className:"join",onKeyUp:@_keyUp,placeholder:"+"}, ""
]
]

View File

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

View File

@ -1,284 +0,0 @@
recl = React.createClass
{div,br,input,textarea} = React.DOM
husl = require 'husl'
MessageActions = require '../actions/MessageActions.coffee'
MessageStore = require '../stores/MessageStore.coffee'
StationActions = require '../actions/StationActions.coffee'
StationStore = require '../stores/StationStore.coffee'
Member = require './MemberComponent.coffee'
SHIPSHAPE = ///
^~?( #preamble
[a-z]{3} # galaxy
| [a-z]{6}(-[a-z]{6}){0,3} # star - moon
| [a-z]{6}(-[a-z]{6}){3} # comet
(--[a-z]{6}(-[a-z]{6}){3})+ #
)$ #postamble
///
PO = '''
dozmarbinwansamlitsighidfidlissogdirwacsabwissib
rigsoldopmodfoglidhopdardorlorhodfolrintogsilmir
holpaslacrovlivdalsatlibtabhanticpidtorbolfosdot
losdilforpilramtirwintadbicdifrocwidbisdasmidlop
rilnardapmolsanlocnovsitnidtipsicropwitnatpanmin
ritpodmottamtolsavposnapnopsomfinfonbanporworsip
ronnorbotwicsocwatdolmagpicdavbidbaltimtasmallig
sivtagpadsaldivdactansidfabtarmonranniswolmispal
lasdismaprabtobrollatlonnodnavfignomnibpagsopral
bilhaddocridmocpacravripfaltodtiltinhapmicfanpat
taclabmogsimsonpinlomrictapfirhasbosbatpochactid
havsaplindibhosdabbitbarracparloddosbortochilmac
tomdigfilfasmithobharmighinradmashalraglagfadtop
mophabnilnosmilfopfamdatnoldinhatnacrisfotribhoc
nimlarfitwalrapsarnalmoslandondanladdovrivbacpol
laptalpitnambonrostonfodponsovnocsorlavmatmipfap
zodnecbudwessevpersutletfulpensytdurwepserwylsun
rypsyxdyrnuphebpeglupdepdysputlughecryttyvsydnex
lunmeplutseppesdelsulpedtemledtulmetwenbynhexfeb
pyldulhetmevruttylwydtepbesdexsefwycburderneppur
rysrebdennutsubpetrulsynregtydsupsemwynrecmegnet
secmulnymtevwebsummutnyxrextebfushepbenmuswyxsym
selrucdecwexsyrwetdylmynmesdetbetbeltuxtugmyrpel
syptermebsetdutdegtexsurfeltudnuxruxrenwytnubmed
lytdusnebrumtynseglyxpunresredfunrevrefmectedrus
bexlebduxrynnumpyxrygryxfeptyrtustyclegnemfermer
tenlusnussyltecmexpubrymtucfyllepdebbermughuttun
bylsudpemdevlurdefbusbeprunmelpexdytbyttyplevmyl
wedducfurfexnulluclennerlexrupnedlecrydlydfenwel
nydhusrelrudneshesfetdesretdunlernyrsebhulryllud
remlysfynwerrycsugnysnyllyndyndemluxfedsedbecmun
lyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes
'''
Audience = recl
displayName: "Audience"
onKeyDown: (e) ->
if e.keyCode is 13
e.preventDefault()
setTimeout () ->
$('#writing').focus()
,0
return false
render: ->
div {
id:"audi"
className:"audi valid-#{@props.valid}"
contentEditable:true
@onKeyDown
onBlur:@props.onBlur
}, @props.audi.join(" ")
module.exports = recl
displayName: "Writing"
set: ->
if window.localStorage and @$writing then window.localStorage.setItem 'writing', @$writing.text()
get: ->
if window.localStorage then window.localStorage.getItem 'writing'
stateFromStore: ->
s =
audi:StationStore.getAudience()
ludi:MessageStore.getLastAudience()
config:StationStore.getConfigs()
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: -> _.extend @stateFromStore(), length:0, lengthy: false
typing: (state) ->
if @state.typing[@state.station] isnt state
StationActions.setTyping @state.station,state
onBlur: ->
@$writing.text @$writing.text()
MessageActions.setTyping false
@typing false
onFocus: ->
MessageActions.setTyping true
@typing true
@cursorAtEnd
addCC: (audi) ->
if window.urb.user isnt window.urb.ship #foreign
return audi
listening = @state.config[window.util.mainStation(window.urb.user)]?.sources ? []
cc = false
for s in audi
if listening.indexOf(s) is -1
cc = true
if listening.length is 0 then cc = true
if cc is true
audi.push window.util.mainStationPath(window.urb.user)
audi
sendMessage: ->
if @_validateAudi() is false
$('#audi').focus()
return
if @state.audi.length is 0 and $('#audi').text().trim().length > 0
audi = if @_setAudi() then @_setAudi() else @state.ludi
else
audi = @state.audi
audi = @addCC audi
txt = @$writing.text().trim().replace(/\xa0/g,' ')
MessageActions.sendMessage txt,audi
@$writing.text('')
@setState length:0
@set()
@typing false
onKeyUp: (e) ->
if not window.urb.util.isURL @$writing.text()
@setState lengthy: (@$writing.text().length > 62)
# r = window.getSelection().getRangeAt(0).cloneRange()
# @$writing.text @$writing.text()
# setTimeout =>
# s = window.getSelection()
# s.removeAllRanges()
# s.addRange r
# console.log r
# ,0
onKeyDown: (e) ->
if e.keyCode is 13
txt = @$writing.text()
e.preventDefault()
if txt.length > 0
if window.talk.online
@sendMessage()
else
#@errHue = ((@errHue || 0) + (Math.random() * 300) + 30) % 360
#$('#offline').css color: husl.toHex @errHue, 90, 50
$('#offline').addClass('error').one 'transitionend',
-> $('#offline').removeClass 'error'
return false
@onInput()
@set()
onInput: (e) ->
text = @$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$_+!*();/?:~-]))'
# ].join() , "g"
# urls = text.match(geturl)
# if urls isnt null and urls.length > 0
# for url in urls
# length -= url.length
# length += 10
@setState {length}
_validateAudiPart: (a) ->
a = a.trim()
# 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
return (SHIPSHAPE.test ship) and
_.all (ship.match /[a-z]{3}/g), (a)-> -1 isnt PO.indexOf a
_validateAudi: ->
v = $('#audi').text()
v = v.trim()
if v.length is 0
return true
if v.length < 5 # zod/a is shortest
return false
_.all (v.split /\ +/), @_validateAudiPart
_setAudi: ->
valid = @_validateAudi()
StationActions.setValidAudience valid
if valid is true
stan = $('#audi').text() || window.util.mainStationPath window.urb.user
stan = (stan.split /\ +/).map (v)->
if v[0] is "~" then v else "~"+v
StationActions.setAudience stan
stan
else
false
getTime: ->
d = new Date()
seconds = d.getSeconds()
if seconds < 10
seconds = "0" + seconds
"~"+d.getHours() + "." + d.getMinutes() + "." + seconds
cursorAtEnd: ->
range = document.createRange()
range.selectNodeContents @$writing[0]
range.collapse(false)
selection = window.getSelection()
selection.removeAllRanges()
selection.addRange(range)
componentDidMount: ->
window.util.sendMessage = @sendMessage
StationStore.addChangeListener @_onChangeStore
MessageStore.addChangeListener @_onChangeStore
@$el = $ @getDOMNode()
@$writing = $('#writing')
@$writing.focus()
if @get()
@$writing.text @get()
@onInput()
@interval = setInterval =>
@$el.find('.time').text @getTime()
, 1000
componentWillUnmount: ->
StationStore.removeChangeListener @_onChangeStore
clearInterval @interval
_onChangeStore: -> @setState @stateFromStore()
render: ->
# if window.urb.user isnt window.urb.ship #foreign
# return div {className:"writing"}
user = "~"+window.urb.user
iden = StationStore.getMember(user)
ship = if iden then iden.ship else user
name = if iden then iden.name else ""
audi = if @state.audi.length is 0 then @state.ludi else @state.audi
audi = window.util.clipAudi audi
for k,v of audi
audi[k] = v.slice(1)
k = "writing"
div {className:k}, [
(div {className:"attr"}, [
(React.createElement Member, iden)
(React.createElement Audience, {audi,valid:@state.valid, onBlur:@_setAudi})
(div {className:"time"}, @getTime())
])
(div {
id:"writing"
contentEditable:true
onPaste: @onInput
@onInput, @onFocus, @onBlur, @onKeyDown, @onKeyUp
}, "")
(div {id:"length"}, "#{@state.length}/64 (#{Math.ceil @state.length / 64})")
]

File diff suppressed because one or more lines are too long

View File

@ -1,13 +0,0 @@
Dispatcher = require('flux').Dispatcher
module.exports = _.merge new Dispatcher(), {
handleServerAction: (action) ->
@dispatch
source: 'server'
action: action
handleViewAction: (action) ->
@dispatch
source: 'view'
action: action
}

View File

@ -1,42 +0,0 @@
$(() ->
StationActions = require './actions/StationActions.coffee' #start poll
rend = React.render
window.talk.online = yes
setInterval (->
window.talk.online = window.urb.poll.dely < 500
if window.talk.online
$('body').removeClass 'offline'
else $('body').addClass 'offline'
), 300
require './util.coffee'
require './move.coffee'
# checkScroll = ->
# if $(window).scrollTop() > 20
# $('#nav').addClass 'scrolling'
# else
# $('#nav').removeClass 'scrolling'
# setInterval checkScroll, 500
StationActions.listen()
StationComponent = require './components/StationComponent.coffee'
MessagesComponent = require './components/MessagesComponent.coffee'
WritingComponent = require './components/WritingComponent.coffee'
$c = $('#c')
# clean = -> # ??
# React.unmountComponentAtNode $('#station-container')[0]
# React.unmountComponentAtNode $('#messages-container')[0]
# React.unmountComponentAtNode $('#writing-container')[0]
rend (React.createElement(StationComponent, {})),$('#station-container')[0]
rend (React.createElement(MessagesComponent, {})),$('#messages-container')[0]
rend (React.createElement(WritingComponent, {})),$('#writing-container')[0]
)

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
so = {}
so.ls = $(window).scrollTop()
so.cs = $(window).scrollTop()
so.w = null
so.$d = $('#nav > div')
setSo = ->
so.$n = $('#station-container')
so.w = $(window).width()
so.h = $(window).height()
so.dh = $("#c").height()
so.nh = so.$n.outerHeight(true)
setSo()
setInterval setSo,200
$(window).on 'resize', (e) ->
if so.w > 1170
so.$n.removeClass 'm-up m-down m-fixed'
ldy = 0
$(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
if so.cs <= 0
so.$n.removeClass 'm-up'
so.$n.addClass 'm-down m-fixed'
return
if so.cs+so.h > so.dh then return
if so.$n.hasClass 'm-fixed' and
so.w < 1024
so.$n.css left:-1*$(window).scrollLeft()
if dy > 0 and ldy > 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 and ldy < 0
if not so.$n.hasClass 'm-up'
so.$n.removeClass 'open'
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
ldy = dy
so.ls = so.cs
$(window).on 'scroll', window.util.checkScroll

View File

@ -1,18 +0,0 @@
{
"name": "urbit-talk",
"version": "0.0.0",
"repository": {
"type": "git",
"url": "https://github.com/urbit/urbit"
},
"description": "urbit talk frontend",
"main": "main.js",
"dependencies": {
"classnames": "^2.2.0",
"coffeeify": "~0.7.0",
"flux": "~2.0.1",
"husl": "^6.0.1",
"lodash": "~2.4.1",
"moment-timezone": "~0.2.4"
}
}

View File

@ -1,45 +0,0 @@
window.urb.appl = "talk"
send = (data,cb)-> window.urb.send data, {mark:"talk-command"}, cb
module.exports = ({MessageActions}) ->
listenStation: (station,since) ->
console.log 'listen station'
console.log arguments
$this = this
window.urb.bind "/f/#{station}/#{since}", (err,res) ->
if err or not res.data
console.log '/f/ err!'
console.log err
console.log res
$this.listenStation station,since
return
console.log('/f/')
console.log(res.data)
if res.data.ok is true
MessageActions.listeningStation station
if res.data?.grams?.tele
{tele,num} = res.data?.grams
MessageActions.loadMessages tele, num
get: (station,start,end) ->
end = window.urb.util.numDot end
start = window.urb.util.numDot start
window.urb.bind "/f/#{station}/#{end}/#{start}", (err,res) ->
if err or not res.data
console.log '/f/ /e/s err'
console.log err
return
console.log '/f/ /e/s'
console.log res
if res.data?.grams?.tele
{tele,num} = res.data?.grams
MessageActions.loadMessages tele,num,true
window.urb.drop "/f/#{station}/#{end}/#{start}", (err,res) ->
console.log 'done'
console.log res
sendMessage: (message,cb) ->
send {publish: [message]}, (err,res) ->
console.log 'sent'
console.log arguments
cb(err,res) if cb

View File

@ -1,55 +0,0 @@
window.urb.appl = "talk"
send = (data,cb)-> window.urb.send data, {mark:"talk-command"}, cb
design = (party,config,cb)-> send {design:{party,config}}, cb
module.exports = ({StationActions})->
createStation: (name,cb) ->
design name, {
sources:[]
caption:""
cordon: posture:"white", list:[]
}, cb
removeStation: (name,cb) -> design name, null, cb
setSources: (station,ship,sources) ->
cordon = posture:"white", list:[]
design station, {sources,cordon,caption:""}, (err,res) ->
console.log 'talk-command'
console.log arguments
members: -> window.urb.bind "/a/court", (err,res) ->
if err or not res
console.log '/a/ err'
console.log err
return
console.log '/a/'
console.log res.data
if res.data?.group?.global
StationActions.loadMembers res.data.group.global
listen: -> window.urb.bind "/", (err,res) ->
if err or not res.data
console.log '/ err'
console.log err
return
console.log '/'
console.log res.data
if res.data.house
StationActions.loadStations res.data.house
listenStation: (station) -> window.urb.bind "/avx/#{station}", (err,res) ->
if err or not res
console.log '/avx/ err'
console.log err
return
console.log('/avx/')
console.log(res.data)
if res.data.ok is true
StationActions.listeningStation station
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.cabal?.loc
StationActions.loadConfig station,res.data.cabal.loc
if res.data.glyph
StationActions.loadGlyphs res.data.glyph

View File

@ -1,107 +0,0 @@
moment = require 'moment-timezone'
EventEmitter = require('events').EventEmitter
MessageDispatcher = require '../dispatcher/Dispatcher.coffee'
_messages = {}
_fetching = false
_last = null
_station = null
_listening = []
_typing = false
MessageStore = _.merge new EventEmitter,{
removeChangeListener: (cb) -> @removeListener "change", cb
emitChange: -> @emit 'change'
addChangeListener: (cb) -> @on 'change', cb
leadingZero: (str) ->
if Number(str) < 10 then "0"+str else str
convertDate: (time) ->
time = time.substr(1).split(".")
time[1] = @leadingZero time[1]
time[2] = @leadingZero time[2]
d = new moment "#{time[0]}-#{time[1]}-#{time[2]}T#{time[4]}:#{time[5]}:#{time[6]}Z"
d.tz "Europe/London"
d
getListening: -> _listening
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) ->
if _listening.indexOf(station) isnt -1
console.log 'already listening on that station (somehow).'
else
_listening.push station
setStation: (station) -> _station = station
sendMessage: (message) ->
_messages[message.thought.serial] = message
loadMessages: (messages,last,get) ->
key = last
for v in messages
serial = v.thought.serial
v.key = key++
# always overwrite with new
_messages[serial] = v
_last = last if last < _last or _last is null or get is true
_fetching = false
getAll: -> _.values _messages
getFetching: -> _fetching
setFetching: (state) -> _fetching = state
getLast: -> _last
}
MessageStore.setMaxListeners 100
MessageStore.dispatchToken = MessageDispatcher.register (payload) ->
action = payload.action
switch action.type
when 'station-switch'
MessageStore.setStation action.station
break
when 'messages-listen'
MessageStore.setListening action.station
MessageStore.emitChange()
break
when 'messages-typing'
MessageStore.setTyping action.state
MessageStore.emitChange()
break
when 'messages-fetch'
MessageStore.setFetching true
MessageStore.emitChange()
break
when 'messages-load'
MessageStore.loadMessages action.messages,action.last,action.get
MessageStore.emitChange()
break
when 'message-load'
MessageStore.loadMessage action.time,action.message,action.author
MessageStore.emitChange()
break
when 'message-send'
MessageStore.sendMessage action.message
MessageStore.emitChange()
break
module.exports = MessageStore

View File

@ -1,165 +0,0 @@
EventEmitter = require('events').EventEmitter
StationDispatcher = require '../dispatcher/Dispatcher.coffee'
_audience = []
_members = {}
_stations = []
_listening = []
_station = null
_config = {}
_typing = {}
_glyphs = {}
_shpylg = {}
_validAudience = true
StationStore = _.merge new EventEmitter,{
removeChangeListener: (cb) -> @removeListener "change", cb
emitChange: -> @emit 'change'
addChangeListener: (cb) -> @on 'change', cb
getAudience: -> _audience
setAudience: (audience) -> _audience = audience
getValidAudience: -> _validAudience
setValidAudience: (valid) -> _validAudience = valid
toggleAudience: (station) ->
if _audience.indexOf(station) isnt -1
_audience.splice _audience.indexOf(station), 1
else
_audience.push station
loadConfig: (station,config) -> _config[station] = config
getConfigs: -> _config
getConfig: (station) -> _config[station]
getGlyph: (station) -> _shpylg[station]
getGlyphMap: -> _shpylg
getGlyphAudience: (glyph) ->
aud = _glyphs[glyph] ? []
if aud.length is 1
aud[0]
getMember: (ship) -> {ship:ship}
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
getListening: -> _listening
setListening: (station) ->
if _listening.indexOf(station) isnt -1
console.log 'already listening on that station (somehow).'
else
_listening.push station
createStation: (station) ->
_stations.push(station) if _stations.indexOf(station) is -1
loadStations: (stations) -> _stations = stations
loadGlyphs: (glyphs) ->
_glyphs = glyphs
_shpylg = {}
for char,auds of glyphs
for aud in auds
_shpylg[aud.join " "] = char
getStations: -> _stations
setStation: (station) -> _station = station
unsetStation: (station) ->
_station = null if _station is station
getStation: -> _station
joinStation: (station) ->
if _config.court?.sources.indexOf(station) is -1
_config.court.sources.push station
getTyping: () -> _typing
setTyping: (station,state) ->
for k,v of _typing
_typing[k] = (k is station)
_typing[station] = state
}
StationStore.setMaxListeners 100
StationStore.dispatchToken = StationDispatcher.register (payload) ->
action = payload.action
switch action.type
when 'station-audience-toggle'
StationStore.toggleAudience action.station
StationStore.emitChange()
break
when 'station-set-audience'
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
StationStore.emitChange()
break
when 'station-listen'
StationStore.setListening action.station
StationStore.emitChange()
break
when "config-load" #[name:'loadConfig', args:['station', 'config']]
StationStore.loadConfig action.station,action.config
StationStore.emitChange()
break
when "glyphs-load" #[name:'loadConfig', args:['station', 'config']]
StationStore.loadGlyphs action.glyphs
StationStore.emitChange()
break
when "stations-load"
StationStore.loadStations action.stations
StationStore.emitChange()
break
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()
break
when "station-create"
StationStore.createStation action.station
StationStore.emitChange()
break
when "members-load"
StationStore.loadMembers action.members
StationStore.emitChange()
break
when "typing-set"
StationStore.setTyping action.station,action.state
StationStore.emitChange()
break
module.exports = StationStore

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +0,0 @@
if not window.util then window.util = {}
_.merge window.util,
mainStations: ["court","floor","porch"]
mainStationPath: (user = window.urb.user) ->
"~#{user}/#{window.util.mainStation(user)}"
mainStation: (user = window.urb.ship) ->
switch user.length
when 3
return "court"
when 6
return "floor"
when 13
return "porch"
getGlyph: (glyphs, audi)->
glyphs[audi.join " "] or switch
when not _.contains audi, window.util.mainStationPath()
"*"
when audi.length is 1
":"
else ";"
clipAudi: (audi) ->
audi = audi.join " "
ms = window.util.mainStationPath()
regx = new RegExp "/#{ms}","g"
audi = audi.replace regx,""
audi.split " "
expandAudi: (audi) ->
audi = audi.join " "
ms = window.util.mainStationPath()
if audi.indexOf(ms) is -1
if audi.length > 0
audi += " "
audi += "#{ms}"
audi.split " "
create: (name) ->
window.talk.StationPersistence.createStation name, (err,res) ->
subscribe: (name) ->
window.talk.StationPersistence.addSource "main",window.urb.ship,["~zod/#{name}"]
uuid32: ->
str = "0v"
str += Math.ceil(Math.random()*8)+"."
for i in [0..5]
_str = Math.ceil(Math.random()*10000000).toString(32)
_str = ("00000"+_str).substr(-5,5)
str += _str+"."
str.slice(0,-1)
populate: (station,number) ->
c = 0
send = ->
if c < number
c++
else
console.log 'done'
return true
_audi = {}
_audi[station] = "pending"
_message =
serial:window.util.uuid32()
audience:_audi
statement:
speech:
say:"Message "+c
time: Date.now()
now: Date.now()
window.talk.MessagePersistence.sendMessage _message,send
send()
getScroll: ->
@writingPosition = $('#c').outerHeight(true)+$('#c').offset().top-$(window).height()
setScroll: ->
window.util.getScroll()
$(window).scrollTop($("#c").height())
isScrolling: ->
if not window.util.writingPosition
window.util.getScroll()
return ($(window).scrollTop()+$('#writing').outerHeight() < window.util.writingPosition)
checkScroll: ->
if window.util.isScrolling()
$('body').addClass 'scrolling'
else
$('body').removeClass 'scrolling'