| 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 |