diff --git a/pub/bootstrap/hymn.hook b/pub/bootstrap/hymn.hook
index d61143a2e..78d5be8a1 100644
--- a/pub/bootstrap/hymn.hook
+++ b/pub/bootstrap/hymn.hook
@@ -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
diff --git a/pub/module/main.js b/pub/module/main.js
new file mode 100644
index 000000000..f6433dca1
--- /dev/null
+++ b/pub/module/main.js
@@ -0,0 +1,6 @@
+main = {
+ mount: function() { console.log('mount.') },
+ unmount: function() { console.log('unmount.') }
+}
+
+window.tree.modules.talk = main
\ No newline at end of file
diff --git a/pub/module/mod.md b/pub/module/mod.md
new file mode 100644
index 000000000..38ec42b4d
--- /dev/null
+++ b/pub/module/mod.md
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/pub/talk/hymn.hook b/pub/talk/hymn.hook
index 16184e286..4d074f95f 100644
--- a/pub/talk/hymn.hook
+++ b/pub/talk/hymn.hook
@@ -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");
==
==
diff --git a/pub/talk/src/css/main.css b/pub/talk/main.css
similarity index 100%
rename from pub/talk/src/css/main.css
rename to pub/talk/main.css
diff --git a/pub/talk/src/js/main.js b/pub/talk/main.js
similarity index 100%
rename from pub/talk/src/js/main.js
rename to pub/talk/main.js
diff --git a/pub/talk/src/css/fonts.styl b/pub/talk/src/css/fonts.styl
deleted file mode 100644
index abfedf60e..000000000
--- a/pub/talk/src/css/fonts.styl
+++ /dev/null
@@ -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;
-}
\ No newline at end of file
diff --git a/pub/talk/src/css/main.styl b/pub/talk/src/css/main.styl
deleted file mode 100644
index 0aa6ac43e..000000000
--- a/pub/talk/src/css/main.styl
+++ /dev/null
@@ -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'
diff --git a/pub/talk/src/css/mobile.styl b/pub/talk/src/css/mobile.styl
deleted file mode 100644
index bb63d3239..000000000
--- a/pub/talk/src/css/mobile.styl
+++ /dev/null
@@ -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
diff --git a/pub/talk/src/js/.main.js b/pub/talk/src/js/.main.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/pub/talk/src/js/actions/MessageActions.coffee b/pub/talk/src/js/actions/MessageActions.coffee
deleted file mode 100644
index 6843bfcd5..000000000
--- a/pub/talk/src/js/actions/MessageActions.coffee
+++ /dev/null
@@ -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
-
diff --git a/pub/talk/src/js/actions/StationActions.coffee b/pub/talk/src/js/actions/StationActions.coffee
deleted file mode 100644
index 2ea566488..000000000
--- a/pub/talk/src/js/actions/StationActions.coffee
+++ /dev/null
@@ -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
diff --git a/pub/talk/src/js/components/MemberComponent.coffee b/pub/talk/src/js/components/MemberComponent.coffee
deleted file mode 100644
index 46be2a3a1..000000000
--- a/pub/talk/src/js/components/MemberComponent.coffee
+++ /dev/null
@@ -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
- ]
diff --git a/pub/talk/src/js/components/MessagesComponent.coffee b/pub/talk/src/js/components/MessagesComponent.coffee
deleted file mode 100644
index c337106b2..000000000
--- a/pub/talk/src/js/components/MessagesComponent.coffee
+++ /dev/null
@@ -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)
diff --git a/pub/talk/src/js/components/StationComponent.coffee b/pub/talk/src/js/components/StationComponent.coffee
deleted file mode 100644
index 7cd76078b..000000000
--- a/pub/talk/src/js/components/StationComponent.coffee
+++ /dev/null
@@ -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)
- )
diff --git a/pub/talk/src/js/components/StationsComponent.coffee b/pub/talk/src/js/components/StationsComponent.coffee
deleted file mode 100644
index 0309ffc32..000000000
--- a/pub/talk/src/js/components/StationsComponent.coffee
+++ /dev/null
@@ -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:"+"}, ""
- ]
- ]
\ No newline at end of file
diff --git a/pub/talk/src/js/components/TalkComponent.coffee b/pub/talk/src/js/components/TalkComponent.coffee
deleted file mode 100644
index ae816c81e..000000000
--- a/pub/talk/src/js/components/TalkComponent.coffee
+++ /dev/null
@@ -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 {}))
- ])
\ No newline at end of file
diff --git a/pub/talk/src/js/components/WritingComponent.coffee b/pub/talk/src/js/components/WritingComponent.coffee
deleted file mode 100644
index 795df136f..000000000
--- a/pub/talk/src/js/components/WritingComponent.coffee
+++ /dev/null
@@ -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})")
- ]
diff --git a/pub/talk/src/js/dep/director.js b/pub/talk/src/js/dep/director.js
deleted file mode 100644
index c956af400..000000000
--- a/pub/talk/src/js/dep/director.js
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-//
-// Generated on Tue Dec 16 2014 12:13:47 GMT+0100 (CET) by Charlie Robbins, Paolo Fragomeni & the Contributors (Using Codesurgeon).
-// Version 1.2.6
-//
-(function(a){function k(a,b,c,d){var e=0,f=0,g=0,c=(c||"(").toString(),d=(d||")").toString(),h;for(h=0;hi.indexOf(d,e)||~i.indexOf(c,e)&&!~i.indexOf(d,e)||!~i.indexOf(c,e)&&~i.indexOf(d,e)){f=i.indexOf(c,e),g=i.indexOf(d,e);if(~f&&!~g||!~f&&~g){var j=a.slice(0,(h||1)+1).join(b);a=[j].concat(a.slice((h||1)+1))}e=(g>f?g:f)+1,h=0}else e=0}return a}function j(a,b){var c,d=0,e="";while(c=a.substr(d).match(/[^\w\d\- %@&]*\*[^\w\d\- %@&]*/))d=c.index+c[0].length,c[0]=c[0].replace(/^\*/,"([_.()!\\ %@&a-zA-Z0-9-]+)"),e+=a.substr(0,c.index)+c[0];a=e+=a.substr(d);var f=a.match(/:([^\/]+)/ig),g,h;if(f){h=f.length;for(var j=0;j7))this.history===!0?setTimeout(function(){window.onpopstate=d},500):window.onhashchange=d,this.mode="modern";else{var f=document.createElement("iframe");f.id="state-frame",f.style.display="none",document.body.appendChild(f),this.writeFrame(""),"onpropertychange"in document&&"attachEvent"in document&&document.attachEvent("onpropertychange",function(){event.propertyName==="location"&&c.check()}),window.setInterval(function(){c.check()},50),this.onHashChanged=d,this.mode="legacy"}e.listeners.push(a);return this.mode},destroy:function(a){if(!!e&&!!e.listeners){var b=e.listeners;for(var c=b.length-1;c>=0;c--)b[c]===a&&b.splice(c,1)}},setHash:function(a){this.mode==="legacy"&&this.writeFrame(a),this.history===!0?(window.history.pushState({},document.title,a),this.fire()):b.hash=a[0]==="/"?a:"/"+a;return this},writeFrame:function(a){var b=document.getElementById("state-frame"),c=b.contentDocument||b.contentWindow.document;c.open(),c.write("