340 lines
9.2 KiB
JavaScript
340 lines
9.2 KiB
JavaScript
var h = require('hyperscript')
|
|
var router = require('phoenix-router')
|
|
var remote = require('remote')
|
|
var Menu = remote.require('menu')
|
|
var MenuItem = remote.require('menu-item')
|
|
var dialog = remote.require('dialog')
|
|
var ssbref = require('ssb-ref')
|
|
var app = require('../app')
|
|
var com = require('../com')
|
|
var u = require('../util')
|
|
var pages = require('../pages')
|
|
|
|
var _onPageTeardown
|
|
var _teardownTasks = []
|
|
var _hideNav = false
|
|
|
|
// re-renders the page
|
|
var refreshPage =
|
|
module.exports.refreshPage = function (e, cb) {
|
|
e && e.preventDefault()
|
|
var starttime = Date.now()
|
|
|
|
// run the router
|
|
var route = router('#'+(location.href.split('#')[1]||''), 'home')
|
|
app.page.id = route[0]
|
|
app.page.param = route[1]
|
|
app.page.qs = route[2] || {}
|
|
|
|
// update state
|
|
app.fetchLatestState(function() {
|
|
|
|
// re-route to setup if needed
|
|
if (!app.users.names[app.user.id]) {
|
|
_hideNav = true
|
|
if (window.location.hash != '#/setup') {
|
|
window.location.hash = '#/setup'
|
|
cb && (typeof cb == 'function') && cb()
|
|
return
|
|
}
|
|
} else
|
|
_hideNav = false
|
|
|
|
// cleanup the old page
|
|
h.cleanup()
|
|
window.onscroll = null // commonly used for infinite scroll
|
|
_onPageTeardown && _onPageTeardown()
|
|
_onPageTeardown = null
|
|
_teardownTasks.forEach(function (task) { task() })
|
|
_teardownTasks.length = 0
|
|
|
|
// render the new page
|
|
var page = pages[app.page.id]
|
|
if (!page)
|
|
page = pages.notfound
|
|
page()
|
|
|
|
// clear pending messages, if home
|
|
if (app.page.id == 'home')
|
|
app.observ.newPosts(0)
|
|
|
|
// metrics
|
|
console.debug('page loaded in', (Date.now() - starttime), 'ms')
|
|
cb && (typeof cb == 'function') && cb()
|
|
})
|
|
}
|
|
|
|
var renderNav =
|
|
module.exports.renderNav = function () {
|
|
var navEl = document.getElementById('page-nav')
|
|
if (_hideNav) {
|
|
navEl.style.display = 'none'
|
|
} else {
|
|
navEl.style.display = 'block'
|
|
navEl.innerHTML = ''
|
|
navEl.appendChild(com.pagenav())
|
|
setNavAddress()
|
|
}
|
|
}
|
|
|
|
// render a new page
|
|
module.exports.setPage = function (name, page, opts) {
|
|
if (opts && opts.onPageTeardown)
|
|
_onPageTeardown = opts.onPageTeardown
|
|
|
|
// render nav
|
|
renderNav()
|
|
|
|
// render page
|
|
var pageEl = document.getElementById('page-container')
|
|
pageEl.innerHTML = ''
|
|
if (!opts || !opts.noHeader)
|
|
pageEl.appendChild(com.page(name, page))
|
|
else
|
|
pageEl.appendChild(h('#page.'+name+'-page', page))
|
|
|
|
// scroll to top
|
|
window.scrollTo(0, 0)
|
|
}
|
|
var setNavAddress =
|
|
module.exports.setNavAddress = function (location) {
|
|
if (!location) {
|
|
// pull from current page
|
|
var location = app.page.id
|
|
if (location == 'profile' || location == 'webview' || location == 'search' || location == 'msg')
|
|
location = app.page.param
|
|
}
|
|
document.body.querySelector('#page-nav input').value = location
|
|
}
|
|
module.exports.onTeardown = function (cb) {
|
|
_teardownTasks.push(cb)
|
|
}
|
|
|
|
module.exports.navBack = function (e) {
|
|
e && e.preventDefault()
|
|
e && e.stopPropagation()
|
|
window.history.back()
|
|
}
|
|
module.exports.navForward = function (e) {
|
|
e && e.preventDefault()
|
|
e && e.stopPropagation()
|
|
window.history.forward()
|
|
}
|
|
module.exports.navRefresh = function (e) {
|
|
e && e.preventDefault()
|
|
e && e.stopPropagation()
|
|
refreshPage()
|
|
}
|
|
|
|
module.exports.contextMenu = function (e) {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
|
|
var menu = new Menu()
|
|
menu.append(new MenuItem({ label: 'Copy', click: oncopy }))
|
|
menu.append(new MenuItem({ label: 'Select All', click: onselectall }))
|
|
menu.append(new MenuItem({ type: 'separator' }))
|
|
if (app.page.id == 'webview' && ssbref.isBlobId(app.page.param)) {
|
|
menu.append(new MenuItem({ label: 'Save As...', click: onsaveas }))
|
|
menu.append(new MenuItem({ type: 'separator' }))
|
|
}
|
|
menu.append(new MenuItem({ label: 'Open Devtools', click: function() { openDevTools() } }))
|
|
menu.popup(remote.getCurrentWindow())
|
|
|
|
function oncopy () {
|
|
var webview = document.querySelector('webview')
|
|
if (webview)
|
|
webview.copy()
|
|
else
|
|
require('clipboard').writeText(window.getSelection().toString())
|
|
}
|
|
function onselectall () {
|
|
var webview = document.querySelector('webview')
|
|
if (webview)
|
|
webview.selectAll()
|
|
else {
|
|
var selection = window.getSelection()
|
|
var range = document.createRange()
|
|
range.selectNodeContents(document.getElementById('page'))
|
|
selection.removeAllRanges()
|
|
selection.addRange(range)
|
|
}
|
|
}
|
|
function onsaveas () {
|
|
var path = dialog.showSaveDialog(remote.getCurrentWindow())
|
|
if (path) {
|
|
app.ssb.patchwork.saveBlobToFile(app.page.param, path, function (err) {
|
|
if (err) {
|
|
alert('Error: '+err.message)
|
|
console.error(err)
|
|
} else
|
|
notice('success', 'Saved to '+path, 5e3)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
var openDevTools =
|
|
module.exports.openDevTools = function () {
|
|
var webview = document.querySelector('webview')
|
|
if (webview)
|
|
webview.openDevTools()
|
|
else
|
|
remote.getCurrentWindow().openDevTools()
|
|
}
|
|
var toggleDevTools =
|
|
module.exports.toggleDevTools = function () {
|
|
var webview = document.querySelector('webview')
|
|
if (webview) {
|
|
if (webview.isDevToolsOpened())
|
|
webview.closeDevTools()
|
|
else
|
|
webview.openDevTools()
|
|
} else
|
|
remote.getCurrentWindow().toggleDevTools()
|
|
}
|
|
|
|
var oldScrollTop
|
|
module.exports.disableScrolling = function () {
|
|
oldScrollTop = document.body.scrollTop
|
|
document.querySelector('html').style.overflow = 'hidden'
|
|
window.scrollTo(0, oldScrollTop)
|
|
}
|
|
module.exports.enableScrolling = function () {
|
|
document.querySelector('html').style.overflow = 'auto'
|
|
window.scrollTo(0, oldScrollTop)
|
|
}
|
|
|
|
|
|
var setStatus =
|
|
module.exports.setStatus = function (message) {
|
|
var status = document.getElementById('app-status')
|
|
status.innerHTML = ''
|
|
if (message) {
|
|
if (message.indexOf('/profile/') === 0) {
|
|
var id = message.slice('/profile/'.length)
|
|
message = [h('strong', com.userName(id)), ' ', com.userRelationship(id)]
|
|
} else if (message.indexOf('/msg/') === 0) {
|
|
message = message.slice('/msg/'.length)
|
|
}
|
|
|
|
status.appendChild(h('div', message))
|
|
}
|
|
}
|
|
var numNotices = 0
|
|
var notice =
|
|
module.exports.notice = function (type, message, duration) {
|
|
var notices = document.getElementById('app-notices')
|
|
var el = h('.alert.alert-'+type, message)
|
|
notices.appendChild(el)
|
|
function remove () {
|
|
notices.removeChild(el)
|
|
}
|
|
setTimeout(remove, duration || 15e3)
|
|
return remove
|
|
}
|
|
|
|
|
|
var pleaseWaitTimer, uhohTimer, tooLongTimer, noticeRemove
|
|
var pleaseWait =
|
|
module.exports.pleaseWait = function (enabled, after) {
|
|
function doit() {
|
|
// clear main timer
|
|
clearTimeout(pleaseWaitTimer); pleaseWaitTimer = null
|
|
noticeRemove && noticeRemove()
|
|
noticeRemove = null
|
|
|
|
if (enabled === false) {
|
|
// hide spinner
|
|
document.querySelector('#please-wait').style.display = 'none'
|
|
setStatus(false)
|
|
|
|
// clear secondary timers
|
|
clearTimeout(uhohTimer); uhohTimer = null
|
|
clearTimeout(tooLongTimer); tooLongTimer = null
|
|
}
|
|
else {
|
|
// show spinner
|
|
document.querySelector('#please-wait').style.display = 'block'
|
|
|
|
// setup secondary timers
|
|
uhohTimer = setTimeout(function () {
|
|
noticeRemove = notice('warning', 'Hmm, this seems to be taking a while...')
|
|
}, 5e3)
|
|
tooLongTimer = setTimeout(function () {
|
|
noticeRemove = notice('danger', 'I think something broke :(. Please restart Patchwork and let us know if this keeps happening!')
|
|
}, 20e3)
|
|
}
|
|
}
|
|
|
|
// disable immediately
|
|
if (!enabled)
|
|
return doit()
|
|
|
|
// enable immediately, or after a timer (if not already waiting)
|
|
if (!after)
|
|
doit()
|
|
else if (!pleaseWaitTimer)
|
|
pleaseWaitTimer = setTimeout(doit, after)
|
|
}
|
|
|
|
|
|
module.exports.dropdown = function (el, options, opts, cb) {
|
|
if (typeof opts == 'function') {
|
|
cb = opts
|
|
opts = null
|
|
}
|
|
opts = opts || {}
|
|
|
|
// render
|
|
var dropdown = h('.dropdown'+(opts.cls||'')+(opts.right?'.right':''),
|
|
{ onmouseleave: die },
|
|
options.map(function (o) {
|
|
if (o instanceof HTMLElement)
|
|
return o
|
|
if (o.separator)
|
|
return h('hr')
|
|
return h('a.item', { href: '#', onclick: onselect(o.value), title: o.title||'' }, o.label)
|
|
})
|
|
)
|
|
if (opts.width)
|
|
dropdown.style.width = opts.width + 'px'
|
|
|
|
// position off the parent element
|
|
var rect = el.getClientRects()[0]
|
|
dropdown.style.top = (rect.bottom + document.body.scrollTop + 10 + (opts.offsetY||0)) + 'px'
|
|
if (opts.right)
|
|
dropdown.style.left = (rect.right + document.body.scrollLeft - (opts.width||200) + 5 + (opts.offsetX||0)) + 'px'
|
|
else
|
|
dropdown.style.left = (rect.left + document.body.scrollLeft - 20 + (opts.offsetX||0)) + 'px'
|
|
|
|
// add to page
|
|
document.body.appendChild(dropdown)
|
|
document.body.addEventListener('click', die)
|
|
|
|
// handler
|
|
function onselect (value) {
|
|
return function (e) {
|
|
e.preventDefault()
|
|
cb(value)
|
|
die()
|
|
}
|
|
}
|
|
function die () {
|
|
document.body.removeEventListener('click', die)
|
|
if (dropdown)
|
|
document.body.removeChild(dropdown)
|
|
dropdown = null
|
|
}
|
|
}
|
|
|
|
module.exports.triggerFind = function () {
|
|
var finder = document.body.querySelector('#finder')
|
|
if (!finder) {
|
|
document.body.appendChild(finder = com.finder())
|
|
finder.querySelector('input').focus()
|
|
} else {
|
|
finder.find()
|
|
}
|
|
} |