Merge remote-tracking branch 'anton/talkfix' into pending

This commit is contained in:
Philip C Monk 2015-10-28 15:26:42 -04:00
commit 73371fd88a
8 changed files with 311 additions and 201 deletions

View File

@ -307,6 +307,7 @@
[['[' ']'] u.active.she] [['[' ']'] u.active.she]
=+ cha=(~(get by nik) q.rew) =+ cha=(~(get by nik) q.rew)
?^ cha ~[u.cha ' '] ?^ cha ~[u.cha ' ']
:: ~& [rew nik nak]
=+ por=~(te-prom te man.she q.rew) =+ por=~(te-prom te man.she q.rew)
(weld `tape`[p.p.rew por] `tape`[q.p.rew ' ' ~]) (weld `tape`[p.p.rew por] `tape`[q.p.rew ' ' ~])
:: ::
@ -1872,12 +1873,12 @@
|- ^- tang |- ^- tang
=< ?+(. . [@ *] [.]~) ^- ?(tank tang) :: wrap single tanks =< ?+(. . [@ *] [.]~) ^- ?(tank tang) :: wrap single tanks
?+ -.sep [>sep<]~ ?+ -.sep [>sep<]~
%exp leaf/"# {(trip p.sep)}" %exp palm/[~ "#" " " ~]^~[leaf/(trip p.sep)]
%lin leaf/"{?:(p.sep "" "@ ")}{(trip q.sep)}" %lin leaf/"{?:(p.sep "" "@ ")}{(trip q.sep)}"
%non ~ %non ~
%app rose/[": " ~ ~]^~[leaf/"[{(trip p.sep)}]" leaf/(trip q.sep)] %app rose/[": " ~ ~]^~[leaf/"[{(trip p.sep)}]" leaf/(trip q.sep)]
%tax leaf/(rend-work-duty p.sep) %tax leaf/(rend-work-duty p.sep)
%url leaf/"/ {(earf p.sep)}" %url palm/[~ "/" " " ~]^~[leaf/(earf p.sep)]
%mor ?~(p.sep ~ (weld $(p.sep t.p.sep) $(sep i.p.sep))) %mor ?~(p.sep ~ (weld $(p.sep t.p.sep) $(sep i.p.sep)))
%fat (welp (tr-rend-tors p.sep) $(sep q.sep)) %fat (welp (tr-rend-tors p.sep) $(sep q.sep))
== ==
@ -1924,6 +1925,8 @@
:+ '/' '_' :+ '/' '_'
=+ hok=r.p.p.p.sep =+ hok=r.p.p.p.sep
~! hok ~! hok
=- (swag [(sub (max 64 (lent -)) 64) 64] -)
^- tape
=< ?~(-.hok (reel p.hok .) +:(scow %if p.hok)) =< ?~(-.hok (reel p.hok .) +:(scow %if p.hok))
|=([a=span b=tape] ?~(b (trip a) (welp b '.' (trip a)))) |=([a=span b=tape] ?~(b (trip a) (welp b '.' (trip a))))
:: ::

View File

@ -27,6 +27,13 @@
^- (unit (list ,_[(wonk *fel) (need *wit)])) ^- (unit (list ,_[(wonk *fel) (need *wit)]))
(zl (turn (~(tap by a)) (head-rush fel))) (zl (turn (~(tap by a)) (head-rush fel)))
:: ::
++ ke :: callbacks
|* [gar=* sef=_|.(fist)]
|= jon=json
^- (unit ,_gar)
=- ~! gar ~! (need -) -
((sef) jon)
::
++ as :: array as set ++ as :: array as set
:: |*(a=fist (cu sa (ar a))) :: XX types :: |*(a=fist (cu sa (ar a))) :: XX types
|* a=fist |* a=fist
@ -69,20 +76,31 @@
%+ sear (soft passport) %+ sear (soft passport)
;~((glue fas) sym urs:ab) :: XX [a-z0-9_]{1,15} ;~((glue fas) sym urs:ab) :: XX [a-z0-9_]{1,15}
:: ::
++ speeech ?(speech [%eval p=@t] [%mor p=(list speeech)])
++ eval ++ eval
|= a=(trel ,@da bouquet ?(speech [%eval p=@t])) ^- statement |= a=(trel ,@da bouquet speeech) ^- statement
?. ?=(%eval -.r.a) a %= a r ^- speech
=+ pax=[&1:% &2:% (scot %da p.a) |3:%] |-
=- a(r [%fat tank/- %exp p.r.a]) ?: ?=(%mor -.r.a)
p:(mule |.([(sell (slap !>(..zuse) (rain pax p.r.a)))]~)) [%mor (turn p.r.a |=(b=speeech ^$(r.a b)))]
?. ?=(%eval -.r.a) r.a
=- [%fat tank/- %exp p.r.a]
=+ pax=[&1:% &2:% (scot %da p.a) |3:%]
p:(mule |.([(sell (slap !>(..zuse) (rain pax p.r.a)))]~))
==
:: ::
++ stam ++ stam
^- $+(json (unit statement)) ^- $+(json (unit statement))
%+ cu eval %+ cu eval
=- (ot date/di bouquet/(as (ar so)) speech/(of -) ~) (ot date/di bouquet/(as (ar so)) speech/spec ~)
::
++ spec
%+ ke *speeech |.
%- of
:~ lin/(ot say/bo txt/so ~) :~ lin/(ot say/bo txt/so ~)
url/(su aurf:urlp) url/(su aurf:urlp)
eval/so eval/so
mor/(ar spec)
:: exp/(cu |=(a=cord [a ~]) so) :: exp/(cu |=(a=cord [a ~]) so)
:: inv/(ot ship/(su fed:ag) party/(su urs:ab) ~) :: inv/(ot ship/(su fed:ag) party/(su urs:ab) ~)
== ==

View File

@ -95,6 +95,7 @@
%tax (joba txt/(jape (rend-work-duty p.a))) %tax (joba txt/(jape (rend-work-duty p.a)))
%app (jobe txt/[%s q.a] src/[%s p.a] ~) %app (jobe txt/[%s q.a] src/[%s p.a] ~)
%fat (jobe tor/(tors p.a) taf/$(a q.a) ~) %fat (jobe tor/(tors p.a) taf/$(a q.a) ~)
%mor a/(turn p.a spec)
:: %inv (jobe ship/(jope p.a) party/[%s q.a] ~) :: %inv (jobe ship/(jope p.a) party/[%s q.a] ~)
== ==
:: ::

View File

@ -56,17 +56,30 @@ module.exports =
else if window.urb.util.isURL(message) else if window.urb.util.isURL(message)
speech = url: message speech = url: message
_message = speeches =
ship:window.urb.ship if speech.lin?.txt.length < 64
thought: [speech]
serial:serial else
audience:_audi {say,txt} = speech.lin
statement: txt.match(/(.{0,64} |.{64}|.+$)/g).map (s)->
bouquet:[] lin: {say, txt:
speech:speech if s.slice -1 isnt " "
date: Date.now() s
else s.slice 0,-1
MessageDispatcher.handleViewAction }
type:"message-send"
message:_message for speech in speeches
window.talk.MessagePersistence.sendMessage _message.thought _message =
ship:window.urb.ship
thought:
serial:window.util.uuid32()
audience:_audi
statement:
bouquet:[]
speech:speech
date: Date.now()
MessageDispatcher.handleViewAction
type:"message-send"
message:_message
window.talk.MessagePersistence.sendMessage _message.thought

View File

@ -29,6 +29,15 @@ Message = recl
return if user.toLowerCase() is 'system' return if user.toLowerCase() is 'system'
@props._handlePm user @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: -> render: ->
# pendingClass = if @props.pending isnt "received" then "pending" else "" # pendingClass = if @props.pending isnt "received" then "pending" else ""
delivery = _.uniq _.pluck @props.thought.audience, "delivery" delivery = _.uniq _.pluck @props.thought.audience, "delivery"
@ -50,14 +59,8 @@ Message = recl
type = ['private','public'] type = ['private','public']
type = type[Number(aude.indexOf(window.util.mainStationPath(window.urb.user)) is -1)] type = type[Number(aude.indexOf(window.util.mainStationPath(window.urb.user)) is -1)]
mess = switch mess = @renderSpeech speech
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)
else "Unknown speech type:" + (" %"+x for x of speech).join ''
klass += switch klass += switch
when speech.app? then " say" when speech.app? then " say"
@ -77,6 +80,7 @@ Message = recl
] ]
module.exports = recl module.exports = recl
displayName: "Messages"
pageSize: 50 pageSize: 50
paddingTop: 100 paddingTop: 100
@ -122,7 +126,8 @@ module.exports = recl
sortedMessages: (messages) -> sortedMessages: (messages) ->
_.sortBy messages, (_message) -> _.sortBy messages, (_message) ->
_message.pending = _message.thought.audience[station] _message.pending = _message.thought.audience[station]
_message.thought.statement.date _message.key
#_message.thought.statement.date
componentDidMount: -> componentDidMount: ->
MessageStore.addChangeListener @_onChangeStore MessageStore.addChangeListener @_onChangeStore

View File

@ -7,7 +7,70 @@ StationActions = require '../actions/StationActions.coffee'
StationStore = require '../stores/StationStore.coffee' StationStore = require '../stores/StationStore.coffee'
Member = require './MemberComponent.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 module.exports = recl
displayName: "Writing"
set: -> set: ->
if window.localStorage and @$writing then window.localStorage.setItem 'writing', @$writing.text() if window.localStorage and @$writing then window.localStorage.setItem 'writing', @$writing.text()
@ -26,20 +89,21 @@ module.exports = recl
s.ludi = _.without s.ludi, window.util.mainStationPath window.urb.user s.ludi = _.without s.ludi, window.util.mainStationPath window.urb.user
s s
getInitialState: -> @stateFromStore() getInitialState: -> _.extend @stateFromStore(), length:0, lengthy: false
typing: (state) -> typing: (state) ->
if @state.typing[@state.station] isnt state if @state.typing[@state.station] isnt state
StationActions.setTyping @state.station,state StationActions.setTyping @state.station,state
_blur: -> onBlur: ->
@$writing.text @$writing.text() @$writing.text @$writing.text()
MessageActions.setTyping false MessageActions.setTyping false
@typing false @typing false
_focus: -> onFocus: ->
MessageActions.setTyping true MessageActions.setTyping true
@typing true @typing true
@cursorAtEnd
addCC: (audi) -> addCC: (audi) ->
listening = @state.config[window.util.mainStation(window.urb.user)].sources listening = @state.config[window.util.mainStation(window.urb.user)].sources
@ -61,23 +125,16 @@ module.exports = recl
else else
audi = @state.audi audi = @state.audi
audi = @addCC audi audi = @addCC audi
MessageActions.sendMessage @$writing.text().trim(),audi txt = @$writing.text().trim().replace(/\xa0/g,' ')
@$length.text "0/62" MessageActions.sendMessage txt,audi
@$writing.text('') @$writing.text('')
@setState length:0
@set() @set()
@typing false @typing false
_audiKeyDown: (e) -> onKeyUp: (e) ->
if e.keyCode is 13
e.preventDefault()
setTimeout () ->
$('#writing').focus()
,0
return false
_writingKeyUp: (e) ->
if not window.urb.util.isURL @$writing.text() if not window.urb.util.isURL @$writing.text()
@$length.toggleClass('valid-false',(@$writing.text().length > 62)) @setState lengthy: (@$writing.text().length > 62)
# r = window.getSelection().getRangeAt(0).cloneRange() # r = window.getSelection().getRangeAt(0).cloneRange()
# @$writing.text @$writing.text() # @$writing.text @$writing.text()
# setTimeout => # setTimeout =>
@ -86,19 +143,18 @@ module.exports = recl
# s.addRange r # s.addRange r
# console.log r # console.log r
# ,0 # ,0
_writingKeyDown: (e) -> onKeyDown: (e) ->
if e.keyCode is 13 if e.keyCode is 13
txt = @$writing.text() txt = @$writing.text()
e.preventDefault() e.preventDefault()
if ( (txt.length > 0 and txt.length < 63) or if txt.length > 0
window.urb.util.isURL @$writing.text() )
@sendMessage() @sendMessage()
return false return false
@_input() @onInput()
@set() @set()
_input: (e) -> onInput: (e) ->
text = @$writing.text() text = @$writing.text()
length = text.length length = text.length
# geturl = new RegExp [ # geturl = new RegExp [
@ -113,11 +169,10 @@ module.exports = recl
# for url in urls # for url in urls
# length -= url.length # length -= url.length
# length += 10 # length += 10
@$length.text "#{length}/62" @setState {length}
_setFocus: -> @$writing.focus()
_validateAudiPart: (a) -> _validateAudiPart: (a) ->
a = a.trim()
# if a[0] isnt "~" # if a[0] isnt "~"
# return false # return false
if a.indexOf("/") isnt -1 if a.indexOf("/") isnt -1
@ -127,9 +182,9 @@ module.exports = recl
ship = _a[0] ship = _a[0]
else else
ship = a ship = a
if ship.length < 3
return false return (SHIPSHAPE.test ship) and
return true _.all (ship.match /[a-z]{3}/g), (a)-> -1 isnt PO.indexOf a
_validateAudi: -> _validateAudi: ->
v = $('#audi').text() v = $('#audi').text()
@ -138,23 +193,17 @@ module.exports = recl
return true return true
if v.length < 5 # zod/a is shortest if v.length < 5 # zod/a is shortest
return false return false
v = v.split " " _.all (v.split /\ +/), @_validateAudiPart
for a in v
a = a.trim()
valid = @_validateAudiPart(a)
valid
_setAudi: -> _setAudi: ->
valid = @_validateAudi() valid = @_validateAudi()
StationActions.setValidAudience valid StationActions.setValidAudience valid
if valid is true if valid is true
v = $('#audi').text() stan = $('#audi').text() || window.util.mainStationPath window.urb.user
if v.length is 0 then v = window.util.mainStationPath window.urb.user stan = (stan.split /\ +/).map (v)->
v = v.split " " if v[0] is "~" then v else "~"+v
for k,_v of v StationActions.setAudience stan
if _v[0] isnt "~" then v[k] = "~#{_v}" stan
StationActions.setAudience v
v
else else
false false
@ -178,12 +227,11 @@ module.exports = recl
StationStore.addChangeListener @_onChangeStore StationStore.addChangeListener @_onChangeStore
MessageStore.addChangeListener @_onChangeStore MessageStore.addChangeListener @_onChangeStore
@$el = $ @getDOMNode() @$el = $ @getDOMNode()
@$length = $('#length')
@$writing = $('#writing') @$writing = $('#writing')
@$writing.focus() @$writing.focus()
if @get() if @get()
@$writing.text @get() @$writing.text @get()
@_input() @onInput()
@interval = setInterval => @interval = setInterval =>
@$el.find('.time').text @getTime() @$el.find('.time').text @getTime()
, 1000 , 1000
@ -210,25 +258,14 @@ module.exports = recl
div {className:k}, [ div {className:k}, [
(div {className:"attr"}, [ (div {className:"attr"}, [
(React.createElement Member, iden) (React.createElement Member, iden)
(div { (React.createElement Audience, {audi,valid:@state.valid, onBlur:@_setAudi})
id:"audi"
className:"audi valid-#{@state.valid}"
contentEditable:true
onKeyDown: @_audiKeyDown
onBlur:@_setAudi
}, audi.join(" "))
(div {className:"time"}, @getTime()) (div {className:"time"}, @getTime())
]) ])
(div { (div {
id:"writing" id:"writing"
contentEditable:true contentEditable:true
onFocus: @_focus onPaste: @onInput
onBlur: @_blur @onInput, @onFocus, @onBlur, @onKeyDown, @onKeyUp
onInput: @_input
onPaste: @_input
onKeyDown: @_writingKeyDown
onKeyUp: @_writingKeyUp
onFocus: @cursorAtEnd
}, "") }, "")
div {id:"length"}, "0/62" (div {id:"length"}, "#{@state.length}/64 (#{Math.ceil @state.length / 64})")
] ]

View File

@ -37,7 +37,7 @@ module.exports = {
return window.talk.MessagePersistence.get(station, start, end); return window.talk.MessagePersistence.get(station, start, end);
}, },
sendMessage: function(message, audience) { sendMessage: function(message, audience) {
var _audi, _message, k, serial, speech, v; var _audi, _message, i, k, len, ref, ref1, results, say, serial, speech, speeches, txt, v;
serial = window.util.uuid32(); serial = window.util.uuid32();
audience = _.uniq(audience); audience = _.uniq(audience);
_audi = {}; _audi = {};
@ -69,23 +69,36 @@ module.exports = {
url: message url: message
}; };
} }
_message = { speeches = ((ref = speech.lin) != null ? ref.txt.length : void 0) < 64 ? [speech] : ((ref1 = speech.lin, say = ref1.say, txt = ref1.txt, ref1), txt.match(/(.{0,64} |.{64}|.+$)/g).map(function(s) {
ship: window.urb.ship, return {
thought: { lin: {
serial: serial, say: say,
audience: _audi, txt: s.slice(-1 !== " ") ? s : s.slice(0, -1)
statement: {
bouquet: [],
speech: speech,
date: Date.now()
} }
} };
}; }));
MessageDispatcher.handleViewAction({ results = [];
type: "message-send", for (i = 0, len = speeches.length; i < len; i++) {
message: _message speech = speeches[i];
}); _message = {
return window.talk.MessagePersistence.sendMessage(_message.thought); ship: window.urb.ship,
thought: {
serial: window.util.uuid32(),
audience: _audi,
statement: {
bouquet: [],
speech: speech,
date: Date.now()
}
}
};
MessageDispatcher.handleViewAction({
type: "message-send",
message: _message
});
results.push(window.talk.MessagePersistence.sendMessage(_message.thought));
}
return results;
} }
}; };
@ -261,8 +274,31 @@ Message = recl({
} }
return this.props._handlePm(user); return this.props._handlePm(user);
}, },
renderSpeech: function(speech) {
var con, x;
switch (false) {
case !((con = speech.lin) || (con = speech.app) || (con = speech.exp) || (con = speech.tax)):
return con.txt;
case !(con = speech.url):
return a({
href: con.txt,
target: "_blank"
}, con.txt);
case !(con = speech.mor):
return con.map(this.renderSpeech);
default:
return "Unknown speech type:" + ((function() {
var results;
results = [];
for (x in speech) {
results.push(" %" + x);
}
return results;
})()).join('');
}
},
render: function() { render: function() {
var attachments, aude, audi, con, delivery, klass, mess, name, ref1, speech, type, x; var attachments, aude, audi, delivery, klass, mess, name, ref1, speech, type;
delivery = _.uniq(_.pluck(this.props.thought.audience, "delivery")); delivery = _.uniq(_.pluck(this.props.thought.audience, "delivery"));
klass = delivery.indexOf("received") !== -1 ? " received" : " pending"; klass = delivery.indexOf("received") !== -1 ? " received" : " pending";
speech = this.props.thought.statement.speech; speech = this.props.thought.statement.speech;
@ -295,26 +331,7 @@ Message = recl({
}); });
type = ['private', 'public']; type = ['private', 'public'];
type = type[Number(aude.indexOf(window.util.mainStationPath(window.urb.user)) === -1)]; type = type[Number(aude.indexOf(window.util.mainStationPath(window.urb.user)) === -1)];
mess = (function() { mess = this.renderSpeech(speech);
switch (false) {
case !((con = speech.lin) || (con = speech.app) || (con = speech.exp) || (con = speech.tax)):
return con.txt;
case !(con = speech.url):
return a({
href: con.txt,
target: "_blank"
}, con.txt);
default:
return "Unknown speech type:" + ((function() {
var results;
results = [];
for (x in speech) {
results.push(" %" + x);
}
return results;
})()).join('');
}
})();
klass += (function() { klass += (function() {
switch (false) { switch (false) {
case speech.app == null: case speech.app == null:
@ -353,6 +370,7 @@ Message = recl({
}); });
module.exports = recl({ module.exports = recl({
displayName: "Messages",
pageSize: 50, pageSize: 50,
paddingTop: 100, paddingTop: 100,
stateFromStore: function() { stateFromStore: function() {
@ -402,7 +420,7 @@ module.exports = recl({
sortedMessages: function(messages) { sortedMessages: function(messages) {
return _.sortBy(messages, function(_message) { return _.sortBy(messages, function(_message) {
_message.pending = _message.thought.audience[station]; _message.pending = _message.thought.audience[station];
return _message.thought.statement.date; return _message.key;
}); });
}, },
componentDidMount: function() { componentDidMount: function() {
@ -696,7 +714,7 @@ module.exports = recl({
},{"../actions/StationActions.coffee":2,"../stores/StationStore.coffee":20,"./MemberComponent.coffee":3}],6:[function(require,module,exports){ },{"../actions/StationActions.coffee":2,"../stores/StationStore.coffee":20,"./MemberComponent.coffee":3}],6:[function(require,module,exports){
var Member, MessageActions, MessageStore, StationActions, StationStore, br, div, input, recl, ref, textarea; var Audience, Member, MessageActions, MessageStore, PO, SHIPSHAPE, StationActions, StationStore, br, div, input, recl, ref, textarea;
recl = React.createClass; recl = React.createClass;
@ -712,7 +730,34 @@ StationStore = require('../stores/StationStore.coffee');
Member = require('./MemberComponent.coffee'); Member = require('./MemberComponent.coffee');
SHIPSHAPE = /^~?([a-z]{3}|[a-z]{6}(-[a-z]{6}){0,3}|[a-z]{6}(-[a-z]{6}){3}(--[a-z]{6}(-[a-z]{6}){3})+)$/;
PO = 'dozmarbinwansamlitsighidfidlissogdirwacsabwissib\nrigsoldopmodfoglidhopdardorlorhodfolrintogsilmir\nholpaslacrovlivdalsatlibtabhanticpidtorbolfosdot\nlosdilforpilramtirwintadbicdifrocwidbisdasmidlop\nrilnardapmolsanlocnovsitnidtipsicropwitnatpanmin\nritpodmottamtolsavposnapnopsomfinfonbanporworsip\nronnorbotwicsocwatdolmagpicdavbidbaltimtasmallig\nsivtagpadsaldivdactansidfabtarmonranniswolmispal\nlasdismaprabtobrollatlonnodnavfignomnibpagsopral\nbilhaddocridmocpacravripfaltodtiltinhapmicfanpat\ntaclabmogsimsonpinlomrictapfirhasbosbatpochactid\nhavsaplindibhosdabbitbarracparloddosbortochilmac\ntomdigfilfasmithobharmighinradmashalraglagfadtop\nmophabnilnosmilfopfamdatnoldinhatnacrisfotribhoc\nnimlarfitwalrapsarnalmoslandondanladdovrivbacpol\nlaptalpitnambonrostonfodponsovnocsorlavmatmipfap\n\nzodnecbudwessevpersutletfulpensytdurwepserwylsun\nrypsyxdyrnuphebpeglupdepdysputlughecryttyvsydnex\nlunmeplutseppesdelsulpedtemledtulmetwenbynhexfeb\npyldulhetmevruttylwydtepbesdexsefwycburderneppur\nrysrebdennutsubpetrulsynregtydsupsemwynrecmegnet\nsecmulnymtevwebsummutnyxrextebfushepbenmuswyxsym\nselrucdecwexsyrwetdylmynmesdetbetbeltuxtugmyrpel\nsyptermebsetdutdegtexsurfeltudnuxruxrenwytnubmed\nlytdusnebrumtynseglyxpunresredfunrevrefmectedrus\nbexlebduxrynnumpyxrygryxfeptyrtustyclegnemfermer\ntenlusnussyltecmexpubrymtucfyllepdebbermughuttun\nbylsudpemdevlurdefbusbeprunmelpexdytbyttyplevmyl\nwedducfurfexnulluclennerlexrupnedlecrydlydfenwel\nnydhusrelrudneshesfetdesretdunlernyrsebhulryllud\nremlysfynwerrycsugnysnyllyndyndemluxfedsedbecmun\nlyrtesmudnytbyrsenwegfyrmurtelreptegpecnelnevfes';
Audience = recl({
displayName: "Audience",
onKeyDown: function(e) {
if (e.keyCode === 13) {
e.preventDefault();
setTimeout(function() {
return $('#writing').focus();
}, 0);
return false;
}
},
render: function() {
return div({
id: "audi",
className: "audi valid-" + this.props.valid,
contentEditable: true,
onKeyDown: this.onKeyDown,
onBlur: this.props.onBlur
}, this.props.audi.join(" "));
}
});
module.exports = recl({ module.exports = recl({
displayName: "Writing",
set: function() { set: function() {
if (window.localStorage && this.$writing) { if (window.localStorage && this.$writing) {
return window.localStorage.setItem('writing', this.$writing.text()); return window.localStorage.setItem('writing', this.$writing.text());
@ -738,21 +783,25 @@ module.exports = recl({
return s; return s;
}, },
getInitialState: function() { getInitialState: function() {
return this.stateFromStore(); return _.extend(this.stateFromStore(), {
length: 0,
lengthy: false
});
}, },
typing: function(state) { typing: function(state) {
if (this.state.typing[this.state.station] !== state) { if (this.state.typing[this.state.station] !== state) {
return StationActions.setTyping(this.state.station, state); return StationActions.setTyping(this.state.station, state);
} }
}, },
_blur: function() { onBlur: function() {
this.$writing.text(this.$writing.text()); this.$writing.text(this.$writing.text());
MessageActions.setTyping(false); MessageActions.setTyping(false);
return this.typing(false); return this.typing(false);
}, },
_focus: function() { onFocus: function() {
MessageActions.setTyping(true); MessageActions.setTyping(true);
return this.typing(true); this.typing(true);
return this.cursorAtEnd;
}, },
addCC: function(audi) { addCC: function(audi) {
var cc, i, len, listening, s; var cc, i, len, listening, s;
@ -773,7 +822,7 @@ module.exports = recl({
return audi; return audi;
}, },
sendMessage: function() { sendMessage: function() {
var audi; var audi, txt;
if (this._validateAudi() === false) { if (this._validateAudi() === false) {
$('#audi').focus(); $('#audi').focus();
return; return;
@ -784,50 +833,46 @@ module.exports = recl({
audi = this.state.audi; audi = this.state.audi;
} }
audi = this.addCC(audi); audi = this.addCC(audi);
MessageActions.sendMessage(this.$writing.text().trim(), audi); txt = this.$writing.text().trim().replace(/\xa0/g, ' ');
this.$length.text("0/62"); MessageActions.sendMessage(txt, audi);
this.$writing.text(''); this.$writing.text('');
this.setState({
length: 0
});
this.set(); this.set();
return this.typing(false); return this.typing(false);
}, },
_audiKeyDown: function(e) { onKeyUp: function(e) {
if (e.keyCode === 13) {
e.preventDefault();
setTimeout(function() {
return $('#writing').focus();
}, 0);
return false;
}
},
_writingKeyUp: function(e) {
if (!window.urb.util.isURL(this.$writing.text())) { if (!window.urb.util.isURL(this.$writing.text())) {
return this.$length.toggleClass('valid-false', this.$writing.text().length > 62); return this.setState({
lengthy: this.$writing.text().length > 62
});
} }
}, },
_writingKeyDown: function(e) { onKeyDown: function(e) {
var txt; var txt;
if (e.keyCode === 13) { if (e.keyCode === 13) {
txt = this.$writing.text(); txt = this.$writing.text();
e.preventDefault(); e.preventDefault();
if ((txt.length > 0 && txt.length < 63) || window.urb.util.isURL(this.$writing.text())) { if (txt.length > 0) {
this.sendMessage(); this.sendMessage();
} }
return false; return false;
} }
this._input(); this.onInput();
return this.set(); return this.set();
}, },
_input: function(e) { onInput: function(e) {
var length, text; var length, text;
text = this.$writing.text(); text = this.$writing.text();
length = text.length; length = text.length;
return this.$length.text(length + "/62"); return this.setState({
}, length: length
_setFocus: function() { });
return this.$writing.focus();
}, },
_validateAudiPart: function(a) { _validateAudiPart: function(a) {
var _a, ship; var _a, ship;
a = a.trim();
if (a.indexOf("/") !== -1) { if (a.indexOf("/") !== -1) {
_a = a.split("/"); _a = a.split("/");
if (_a[1].length === 0) { if (_a[1].length === 0) {
@ -837,13 +882,12 @@ module.exports = recl({
} else { } else {
ship = a; ship = a;
} }
if (ship.length < 3) { return (SHIPSHAPE.test(ship)) && _.all(ship.match(/[a-z]{3}/g), function(a) {
return false; return -1 !== PO.indexOf(a);
} });
return true;
}, },
_validateAudi: function() { _validateAudi: function() {
var a, i, len, v, valid; var v;
v = $('#audi').text(); v = $('#audi').text();
v = v.trim(); v = v.trim();
if (v.length === 0) { if (v.length === 0) {
@ -852,32 +896,23 @@ module.exports = recl({
if (v.length < 5) { if (v.length < 5) {
return false; return false;
} }
v = v.split(" "); return _.all(v.split(/\ +/), this._validateAudiPart);
for (i = 0, len = v.length; i < len; i++) {
a = v[i];
a = a.trim();
valid = this._validateAudiPart(a);
}
return valid;
}, },
_setAudi: function() { _setAudi: function() {
var _v, k, v, valid; var stan, valid;
valid = this._validateAudi(); valid = this._validateAudi();
StationActions.setValidAudience(valid); StationActions.setValidAudience(valid);
if (valid === true) { if (valid === true) {
v = $('#audi').text(); stan = $('#audi').text() || window.util.mainStationPath(window.urb.user);
if (v.length === 0) { stan = (stan.split(/\ +/)).map(function(v) {
v = window.util.mainStationPath(window.urb.user); if (v[0] === "~") {
} return v;
v = v.split(" "); } else {
for (k in v) { return "~" + v;
_v = v[k];
if (_v[0] !== "~") {
v[k] = "~" + _v;
} }
} });
StationActions.setAudience(v); StationActions.setAudience(stan);
return v; return stan;
} else { } else {
return false; return false;
} }
@ -905,12 +940,11 @@ module.exports = recl({
StationStore.addChangeListener(this._onChangeStore); StationStore.addChangeListener(this._onChangeStore);
MessageStore.addChangeListener(this._onChangeStore); MessageStore.addChangeListener(this._onChangeStore);
this.$el = $(this.getDOMNode()); this.$el = $(this.getDOMNode());
this.$length = $('#length');
this.$writing = $('#writing'); this.$writing = $('#writing');
this.$writing.focus(); this.$writing.focus();
if (this.get()) { if (this.get()) {
this.$writing.text(this.get()); this.$writing.text(this.get());
this._input(); this.onInput();
} }
return this.interval = setInterval((function(_this) { return this.interval = setInterval((function(_this) {
return function() { return function() {
@ -944,28 +978,25 @@ module.exports = recl({
div({ div({
className: "attr" className: "attr"
}, [ }, [
React.createElement(Member, iden), div({ React.createElement(Member, iden), React.createElement(Audience, {
id: "audi", audi: audi,
className: "audi valid-" + this.state.valid, valid: this.state.valid,
contentEditable: true,
onKeyDown: this._audiKeyDown,
onBlur: this._setAudi onBlur: this._setAudi
}, audi.join(" ")), div({ }), div({
className: "time" className: "time"
}, this.getTime()) }, this.getTime())
]), div({ ]), div({
id: "writing", id: "writing",
contentEditable: true, contentEditable: true,
onFocus: this._focus, onPaste: this.onInput,
onBlur: this._blur, onInput: this.onInput,
onInput: this._input, onFocus: this.onFocus,
onPaste: this._input, onBlur: this.onBlur,
onKeyDown: this._writingKeyDown, onKeyDown: this.onKeyDown,
onKeyUp: this._writingKeyUp, onKeyUp: this.onKeyUp
onFocus: this.cursorAtEnd
}, ""), div({ }, ""), div({
id: "length" id: "length"
}, "0/62") }, this.state.length + "/64 (" + (Math.ceil(this.state.length / 64)) + ")")
]); ]);
} }
}); });
@ -5898,11 +5929,12 @@ MessageStore = _.merge(new EventEmitter, {
return _messages[message.thought.serial] = message; return _messages[message.thought.serial] = message;
}, },
loadMessages: function(messages, last, get) { loadMessages: function(messages, last, get) {
var k, serial, v; var i, key, len, serial, v;
for (k in messages) { key = last;
v = messages[k]; for (i = 0, len = messages.length; i < len; i++) {
v = messages[i];
serial = v.thought.serial; serial = v.thought.serial;
v.key = serial; v.key = key++;
_messages[serial] = v; _messages[serial] = v;
} }
if (last < _last || _last === null || get === true) { if (last < _last || _last === null || get === true) {

View File

@ -52,9 +52,10 @@ MessageStore = _.merge new EventEmitter,{
_messages[message.thought.serial] = message _messages[message.thought.serial] = message
loadMessages: (messages,last,get) -> loadMessages: (messages,last,get) ->
for k,v of messages key = last
for v in messages
serial = v.thought.serial serial = v.thought.serial
v.key = serial v.key = key++
# always overwrite with new # always overwrite with new
_messages[serial] = v _messages[serial] = v
_last = last if last < _last or _last is null or get is true _last = last if last < _last or _last is null or get is true
@ -103,4 +104,4 @@ MessageStore.dispatchToken = MessageDispatcher.register (payload) ->
MessageStore.emitChange() MessageStore.emitChange()
break break
module.exports = MessageStore module.exports = MessageStore