blob: de604de36992091f65f6e2f9b8d2872e8323be64 [file] [log] [blame]
class Chat
Vue.util.defineReactive @@log, []
Vue.util.defineReactive @@topic, {}
@@start = Date.new().getTime()
@@fetch_requested = false
@@backlog_fetched = false
# as it says: fetch backlog of chat messages from the server
def self.fetch_backlog()
return if @@fetch_requested
retrieve "chat/#{Agenda.file[/\d[\d_]+/]}", :json do |messages|
messages.each {|message| Chat.add message}
@@backlog_fetched = true
end
# start countdown to meeting
self.countdown()
setInterval self.countdown, 30_000
# synchonize chat logs
if defined? BroadcastChannel
channel = BroadcastChannel.new('chatsync')
# ask if there are any earlier data
channel.postMessage type: 'query', start: @@start
def channel.onmessage(event)
if event.data.type == :query and event.data.start > @@start
# respond with log if requestor started after this window
channel.postMessage type: 'log', start: @@start, log: @@log
elsif event.data.type == :log and event.data.start < @@start
# merge data from before this window started
event.data.log.each do |message|
unless message.type == :topic or message.timestamp >= @@start
Chat.add message
end
end
@@start = event.data.start
end
end
end
@@fetch_requested = true
end
# set topic to meeting status
def self.countdown()
status = Chat.status
Chat.setTopic subtype: 'status', user: 'whimsy', text: status if status
end
# replace topic locally
def self.setTopic(entry)
return if @@topic.text == entry.text
@@log = @@log.filter {|item| return item.type != :topic}
entry.type = :topic
@@topic = entry
Chat.add entry
Main.refresh() if entry.subtype == :status
end
# change topic globally
def self.changeTopic(entry)
return if @@topic.text == entry.text
entry.type = :topic
entry.agenda = Agenda.file
post 'message', entry do |message|
Chat.setTopic entry
end
end
# return the chat log
def self.log
@@log
end
# identify what changed in the agenda
def self.agenda_change(before, after)
# bootstrap has a single Roll Call entry
return unless before and before.length > 1
# build an index of the 'before' agenda
index = {}
before.each do |item|
index[item.title] = item
end
# categorize each item in the 'after' agenda
add = []
change = []
after.each do |item|
before = index[item.title]
if not before
add << item
elsif before.missing or not item.missing
if before.digest != item.digest
if before.missing
add << item
else
change << item
end
end
index.delete item.title
end
end
# build a set of messages
messages = []
unless add.empty?
messages << "Added: #{add.map {|item| item.title}.join(', ')}"
end
unless change.empty?
messages << "Updated: #{change.map {|item| item.title}.join(', ')}"
end
missing = Object.values(index)
unless missing.empty?
messages << "Deleted: #{missing.map {|item| item.title}.join(', ')}"
end
# output the messages
unless messages.empty?
messages.each do |message|
Chat.add type: 'agenda', user: 'agenda', text: message
end
Main.refresh()
end
end
# identify what changed in the reporter drafts
def self.reporter_change(before, after)
return unless before and before.drafts and after and after.drafts
# build an index of the 'before' drafts
index = {}
before.drafts.each_pair do |attach, item|
index[item.project] = item
end
# categorize each item in the 'after' drafts
add = []
change = []
after.drafts.each_pair do |attach, item|
before = index[item.project]
console.log [before, item]
if not before
add << item
else
change << item if before.text != item.text
index.delete item.project
end
end
# build a set of messages
messages = []
unless add.empty?
messages << "Added: #{add.map {|item| item.title}.join(', ')}"
end
unless change.empty?
messages << "Updated: #{change.map {|item| item.title}.join(', ')}"
end
missing = Object.values(index)
unless missing.empty?
messages << "Deleted: #{missing.map {|item| item.title}.join(', ')}"
end
# output the messages
unless messages.empty?
messages.each do |message|
Chat.add type: 'agenda', user: 'reporter', text: message
end
Main.refresh()
end
end
# add an entry to the chat log
def self.add(entry)
entry.timestamp ||= Date.new().getTime()
if @@log.empty? or @@log.last.timestamp < entry.timestamp
@@log << entry
else
for i in 0...@@log.length
if entry.timestamp <= @@log[i].timestamp
if entry.timestamp!=@@log[i].timestamp or entry.text!=@@log[i].text
@@log.splice(i, 0, entry)
end
break
end
end
end
end
# meeting status for countdown
def self.status
diff = Agenda.find('Call-to-order').timestamp - Date.new().getTime()
if Minutes.complete
"meeting has completed"
elsif Minutes.started
if @@topic.subtype == :status
@@topic.text
else
"meeting has started"
end
elsif diff > 86_400_000 * 3/2
"meeting will start in about #{Math.floor(diff/86_400_000+0.5)} days"
elsif diff > 3_600_000 * 3/2
"meeting will start in about #{Math.floor(diff/3_600_000+0.5)} hours"
elsif diff > 300_000
"meeting will start in about #{Math.floor(diff/300_000+0.5)*5} minutes"
elsif diff > 90_000
"meeting will start in about #{Math.floor(diff/60_000+0.5)} minutes"
else
"meeting will start shortly"
end
end
end
# subscriptions
Events.subscribe :chat do |message|
if message.agenda == Agenda.file
message.delete 'agenda'
Chat.add message
end
end
Events.subscribe :info do |message|
if message.agenda == Agenda.file
message.delete 'agenda'
Chat.add message
end
end
Events.subscribe :topic do |message|
if message.agenda == Agenda.file
Chat.setTopic message
end
end
Events.subscribe :arrive do |message|
Server.online = message.present
Chat.add type: :info, user: message.user, timestamp: message.timestamp,
text: 'joined the chat'
end
Events.subscribe :depart do |message|
Server.online = message.present
Chat.add type: :info, user: message.user, timestamp: message.timestamp,
text: 'left the chat'
end