blob: 189b14702d1e4ad73068bc67784726368a0816bb [file] [log] [blame]
#
# Main component, responsible for:
#
# * Initial loading and polling of the agenda
#
# * Rendering a Header, a item view, and a Footer
#
# * Resizing view to leave room for the Header and Footer
#
class Main < Vue
# common layout for all pages: header, main, footer, and forms
def render
if not @item
_p 'Not found'
else
_Header item: @item
_main do
if Agenda.index[0].text # don't display page while bootstrapping
Vue.createElement(@item.view, props: {item: @item}, ref: 'view')
end
end
_Footer item: @item, buttons: @buttons, options: @options
# emit hidden forms associated with the buttons displayed on this page
if @buttons
@buttons.each do |button|
if button.form
Vue.createElement(button.form, props: {item: @item, server: Server,
button: button})
end
end
end
end
end
# initial load of the agenda, and route first request
def created()
# copy server info for later use
@@server.each_pair do |prop, value|
Server[prop] = value
end
Pending.fetch() if PageCache.enabled or not Server.userid
Agenda.load(@@page.parsed, @@page.digest)
Minutes.load(@@page.minutes)
Reporter.fetch() if PageCache.enabled
self.route(@@page.path, @@page.query)
# free memory
@@page.parsed = nil
end
# encapsulate calls to the router
def route(path, query)
route = Router.route(path,query)
@item = route.item
@buttons = route.buttons
@options = route.options
unless Main.item and route.item and Main.item.view == route.item.view
Main.view = nil
end
Main.item = route.item
# update title to match the item title whenever page changes
if defined? document and route.item
document.getElementsByTagName('title')[0].textContent = route.item.title
end
end
# navigation method that updates history (back button) information
def navigate(path, query)
history.state.scrollY = window.scrollY
history.replaceState(history.state, nil, history.path)
Main.scrollTo = 0
self.route(path, query)
history.pushState({path: path, query: query}, nil, path)
window.onresize()
Main.latest = false if path
end
# refresh the current page
def refresh()
self.route(history.state.path, history.state.query)
end
# dummy exported refresh method (replaced on client side)
def self.refresh()
end
# additional client side initialization
def mounted()
# export navigate and refresh methods as well as view
Main.navigate = self.navigate
Main.refresh = self.refresh
Main.view = $refs.view
Main.item = Agenda
# store initial state in history, taking care not to overwrite
# history set by the Search component.
if not history.state or not history.state.query
path = @@page.path
if path == 'bootstrap.html'
path = document.location.href
base = document.getElementsByTagName('base')[0].href
if path.start_with? base
path = path.slice(base.length)
elsif path.end_with? '/latest/'
Main.latest = true
path = '.'
end
end
history.replaceState({path: path}, nil, path)
end
# listen for back button, and re-route/re-render when it occcurs
window.addEventListener :popstate do |event|
if event.state and defined? event.state.path
Main.scrollTo = event.state.scrollY || 0
self.route(event.state.path, event.state.query)
end
end
# start watching keystrokes and fingers
Keyboard.initEventHandlers()
Touch.initEventHandlers()
# whenever the window is resized, adjust margins of the main area to
# avoid overlapping the header and footer areas
def window.onresize()
main = document.querySelector('main')
return unless main
footer = document.querySelector('footer')
header = document.querySelector('header')
if
window.innerHeight <= 400 and
document.body.scrollHeight > window.innerHeight
then
footer.style.position = 'relative' if footer
header.style.position = 'relative' if header
main.style.marginTop = 0
main.style.marginBottom = 0
else
footer.style.position = 'fixed' if footer
header.style.position = 'fixed' if header
main.style.marginTop =
"#{document.querySelector('header.navbar').clientHeight}px"
main.style.marginBottom =
"#{document.querySelector('footer.navbar').clientHeight}px"
end
if Main.scrollTo == 0 or Main.scrollTo
if Main.scrollTo == -1
jQuery('html, body').
animate({scrollTop: document.documentElement.scrollHeight}, :fast)
else
window.scrollTo(0, Main.scrollTo)
Main.scrollTo = nil
end
end
end
# do an initial resize
Main.scrollTo = 0
window.onresize()
# if agenda is stale, fetch immediately; otherwise save etag
Agenda.fetch(@@page.etag, @@page.digest)
# start Service Worker
PageCache.register() if PageCache.enabled
# start backchannel
Events.monitor()
end
# after each subsequent re-rendering, resize main window
def updated()
window.onresize()
end
end