move ssb-patchwork-api and ssb-patchwork-ui into this repo
This commit is contained in:
25
ui/lib/pages/drive.js
Normal file
25
ui/lib/pages/drive.js
Normal file
@@ -0,0 +1,25 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var com = require('../com')
|
||||
|
||||
module.exports = function (opts) {
|
||||
|
||||
// markup
|
||||
|
||||
ui.setPage('drive', h('.layout-onecol',
|
||||
h('.layout-main',
|
||||
(opts && opts.download) ?
|
||||
h('.well.white', { style: 'margin-top: 5px' },
|
||||
h('p', h('strong', opts.download)),
|
||||
h('a.btn.btn-3d', 'Save to your files as...'), ' ', h('a.btn.btn-3d', 'Download...')) :
|
||||
'',
|
||||
h('.pull-right',
|
||||
h('a.btn.btn-3d', 'Upload File')
|
||||
),
|
||||
h('h3', 'Your Drive ', h('small', 'Non-functional Mockup Interface')),
|
||||
com.files(app.user.id)
|
||||
)
|
||||
))
|
||||
}
|
||||
29
ui/lib/pages/feed.js
Normal file
29
ui/lib/pages/feed.js
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var mlib = require('ssb-msgs')
|
||||
var pull = require('pull-stream')
|
||||
var multicb = require('multicb')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var com = require('../com')
|
||||
|
||||
module.exports = function (pid) {
|
||||
|
||||
// markup
|
||||
|
||||
var feed = app.ssb.createFeedStream
|
||||
if (pid) {
|
||||
feed = function (opts) {
|
||||
opts = opts || {}
|
||||
opts.id = pid
|
||||
return app.ssb.createUserStream(opts)
|
||||
}
|
||||
}
|
||||
|
||||
ui.setPage('feed', h('.layout-onecol',
|
||||
h('.layout-main',
|
||||
h('h3.text-center', 'Behind the Scenes ', h('small', 'Raw Data Feed')),
|
||||
com.messageFeed({ feed: feed, render: com.messageSummary.raw, infinite: true })
|
||||
)
|
||||
))
|
||||
}
|
||||
56
ui/lib/pages/friends.js
Normal file
56
ui/lib/pages/friends.js
Normal file
@@ -0,0 +1,56 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var ref = require('ssb-ref')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var com = require('../com')
|
||||
var social = require('../social-graph')
|
||||
|
||||
module.exports = function () {
|
||||
var queryStr = app.page.qs.q || ''
|
||||
var queryRegex
|
||||
|
||||
// filters
|
||||
|
||||
function stdfilter (prof) {
|
||||
if (prof.id == app.user.id) // is self
|
||||
return true
|
||||
if (app.users.names[prof.id] || social.follows(app.user.id, prof.id)) // has a name, or is a friend
|
||||
return true
|
||||
}
|
||||
|
||||
function isRecommended (prof) {
|
||||
var nfollowers = social.followedFollowers(app.user.id, prof.id).length
|
||||
var nflaggers = social.followedFlaggers(app.user.id, prof.id, true).length
|
||||
if (prof.id != app.user.id && !social.follows(app.user.id, prof.id) && nfollowers && !nflaggers)
|
||||
return true
|
||||
}
|
||||
|
||||
function recommendFilterFn (prof) {
|
||||
if (!stdfilter(prof))
|
||||
return false
|
||||
return isRecommended(prof)
|
||||
}
|
||||
|
||||
function othersFilterFn (prof) {
|
||||
if (!stdfilter(prof))
|
||||
return false
|
||||
return (prof.id != app.user.id && !social.follows(app.user.id, prof.id) && !isRecommended(prof))
|
||||
}
|
||||
|
||||
// markup
|
||||
|
||||
var newFollowersToShow = Math.max(app.indexCounts.followsUnread, 30)
|
||||
ui.setPage('followers', h('.layout-onecol',
|
||||
h('.layout-main',
|
||||
h('h3', 'Following'),
|
||||
h('div', { style: 'width: 850px; margin: 0 auto' }, com.friendsHexagrid({ size: 80, nrow: 10 })),
|
||||
h('h3', 'Activity'),
|
||||
com.messageFeed({ render: com.messageSummary, feed: app.ssb.patchwork.createFollowStream, markread: true, limit: newFollowersToShow }),
|
||||
h('h3', { style: 'margin-top: 40px' }, 'Recommendations'),
|
||||
com.contactFeed({ filter: recommendFilterFn }),
|
||||
h('h3', { style: 'margin-top: 40px' }, 'Others'),
|
||||
com.contactFeed({ filter: othersFilterFn })
|
||||
)
|
||||
))
|
||||
}
|
||||
71
ui/lib/pages/home.js
Normal file
71
ui/lib/pages/home.js
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var o = require('observable')
|
||||
var mlib = require('ssb-msgs')
|
||||
var pull = require('pull-stream')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var com = require('../com')
|
||||
var social = require('../social-graph')
|
||||
|
||||
module.exports = function () {
|
||||
|
||||
var hlf // home live feed
|
||||
|
||||
// filters
|
||||
|
||||
var p = app.user.profile
|
||||
|
||||
function homeFilter (m) {
|
||||
var a = m.value.author
|
||||
if (app.users.profiles[a] && app.users.profiles[a].flagged) // flagged by user
|
||||
return false
|
||||
if (app.homeMode.view == 'all')
|
||||
return true
|
||||
if (app.homeMode.view == 'friends')
|
||||
return a == app.user.id || social.follows(app.user.id, a)
|
||||
return social.follows(app.homeMode.view, a) // `view` is the id of a pub
|
||||
}
|
||||
|
||||
// live-mode
|
||||
if (app.homeMode.live)
|
||||
hlf = app.ssb.patchwork.createHomeStream({ gt: [Date.now(), null], live: true })
|
||||
|
||||
// markup
|
||||
|
||||
function render (msg) {
|
||||
return com.message(msg, { markread: true })
|
||||
}
|
||||
function notification (vo, href, title, icon) {
|
||||
return o.transform(vo, function (v) {
|
||||
var cls = (v>0) ? '.highlight' : ''
|
||||
return h('a'+cls, { href: href, title: title }, com.icon(icon), ' ', v)
|
||||
})
|
||||
}
|
||||
ui.setPage('home', h('.layout-twocol',
|
||||
h('.layout-main',
|
||||
com.notifications(),
|
||||
com.composer(null, null, { placeholder: 'Share a message with the world...' }),
|
||||
com.messageFeed({ feed: app.ssb.patchwork.createHomeStream, render: render, onempty: onempty, filter: homeFilter, limit: 100, infinite: true, live: hlf })
|
||||
),
|
||||
h('.layout-rightnav',
|
||||
h('.shortcuts',
|
||||
notification(app.observ.indexCounts.inboxUnread, '#/inbox', 'Your inbox', 'inbox'),
|
||||
notification(app.observ.indexCounts.votesUnread, '#/stars', 'Stars on your posts, and stars by you', 'star'),
|
||||
notification(app.observ.indexCounts.followsUnread, '#/friends', 'Friends, followers, and other users', 'user')
|
||||
),
|
||||
com.notifications.side(),
|
||||
com.friendsHexagrid({ size: 80 }),
|
||||
com.help.side()
|
||||
)
|
||||
), { onPageTeardown: function () {
|
||||
// abort streams
|
||||
hlf && hlf(true, function(){})
|
||||
}})
|
||||
|
||||
function onempty (el) {
|
||||
if (app.homeMode.view == 'all')
|
||||
el.appendChild(com.help.welcome())
|
||||
}
|
||||
|
||||
}
|
||||
32
ui/lib/pages/inbox.js
Normal file
32
ui/lib/pages/inbox.js
Normal file
@@ -0,0 +1,32 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var mlib = require('ssb-msgs')
|
||||
var pull = require('pull-stream')
|
||||
var multicb = require('multicb')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var com = require('../com')
|
||||
var social = require('../social-graph')
|
||||
var subwindows = require('../ui/subwindows')
|
||||
|
||||
module.exports = function () {
|
||||
|
||||
// markup
|
||||
|
||||
ui.setPage('inbox', h('.layout-onecol',
|
||||
h('.layout-main',
|
||||
h('a.btn.btn-3d.pull-right', { onclick: function (e) { e.preventDefault(); subwindows.pm() } }, com.icon('envelope'), ' Secret Message'),
|
||||
h('h3', 'Inbox'),
|
||||
com.messageFeed({ render: com.messageOneline, feed: app.ssb.patchwork.createInboxStream, filter: filter, onempty: onempty, infinite: true })
|
||||
)
|
||||
))
|
||||
|
||||
function onempty (feedEl) {
|
||||
feedEl.appendChild(h('p.text-center', { style: 'margin: 25px 0; padding: 10px; color: gray' }, 'Your inbox is empty!'))
|
||||
}
|
||||
|
||||
function filter (msg) {
|
||||
var a = msg.value.author
|
||||
return a == app.user.id || social.follows(app.user.id, a)
|
||||
}
|
||||
}
|
||||
31
ui/lib/pages/index.js
Normal file
31
ui/lib/pages/index.js
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var ui = require('../ui')
|
||||
var com = require('../com')
|
||||
|
||||
function notfound () {
|
||||
ui.setPage('notfound', [
|
||||
h('img', { src: 'img/lick-the-door.gif', style: 'display: block; margin: 10px auto; border-radius: 3px;' }),
|
||||
h('h2.text-center', 'Page Not Found'),
|
||||
h('div.text-center', { style: 'margin-top: 20px' },
|
||||
'Sorry, that page wasn\'t found. Maybe you typed the name wrong? Or maybe somebody gave you a bad link.'
|
||||
)
|
||||
])
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
drive: require('./drive'),
|
||||
feed: require('./feed'),
|
||||
friends: require('./friends'),
|
||||
home: require('./home'),
|
||||
inbox: require('./inbox'),
|
||||
msg: require('./message'),
|
||||
notfound: notfound,
|
||||
profile: require('./profile'),
|
||||
publisher: require('./publisher'),
|
||||
search: require('./search'),
|
||||
setup: require('./setup'),
|
||||
stars: require('./stars'),
|
||||
sync: require('./sync'),
|
||||
webview: require('./webview')
|
||||
}
|
||||
54
ui/lib/pages/message.js
Normal file
54
ui/lib/pages/message.js
Normal file
@@ -0,0 +1,54 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var mlib = require('ssb-msgs')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var anim = require('../ui/anim')
|
||||
var com = require('../com')
|
||||
var util = require('../util')
|
||||
|
||||
module.exports = function () {
|
||||
|
||||
app.ssb.get(app.page.param, function (err, msg) {
|
||||
var content
|
||||
var isEncrypted = false
|
||||
var secretMessageLabel
|
||||
if (msg) {
|
||||
msg = { key: app.page.param, value: msg }
|
||||
content = com.message(msg, { markread: true, fullview: true, live: true })
|
||||
|
||||
// if encrypted, add the animated 'secret message' label
|
||||
if (typeof msg.value.content == 'string') {
|
||||
isEncrypted = true
|
||||
secretMessageLabel = h('span')
|
||||
anim.textDecoding(secretMessageLabel, 'Secret Thread')
|
||||
}
|
||||
} else {
|
||||
content = 'Message not found.'
|
||||
}
|
||||
|
||||
ui.setPage('message', h('.layout-twocol',
|
||||
h('.layout-main', content),
|
||||
h('.layout-rightnav',
|
||||
(isEncrypted) ?
|
||||
h('.text-center',
|
||||
h('p', h('code', { style: 'font-size: 18px' }, secretMessageLabel, ' ', com.icon('lock'))),
|
||||
h('p', 'All messages in this thread are encrypted.')
|
||||
) :
|
||||
''
|
||||
)
|
||||
))
|
||||
|
||||
if (app.page.qs.jumpto) {
|
||||
setTimeout(function (){
|
||||
var el = document.querySelector('.message[data-key="'+app.page.qs.jumpto+'"]')
|
||||
if (el) {
|
||||
el.scrollIntoView()
|
||||
if ((window.innerHeight + window.scrollY) < document.body.offsetHeight)
|
||||
window.scrollBy(0, -100) // show a little above, if not at the bottom of the page
|
||||
}
|
||||
}, 50)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
200
ui/lib/pages/profile.js
Normal file
200
ui/lib/pages/profile.js
Normal file
@@ -0,0 +1,200 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var refs = require('ssb-ref')
|
||||
var mlib = require('ssb-msgs')
|
||||
var multicb = require('multicb')
|
||||
var schemas = require('ssb-msg-schemas')
|
||||
var pull = require('pull-stream')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var modals = require('../ui/modals')
|
||||
var subwindows = require('../ui/subwindows')
|
||||
var com = require('../com')
|
||||
var u = require('../util')
|
||||
var markdown = require('../markdown')
|
||||
var mentions = require('../mentions')
|
||||
var social = require('../social-graph')
|
||||
|
||||
module.exports = function () {
|
||||
var pid = app.page.param
|
||||
var profile = app.users.profiles[pid]
|
||||
var name = com.userName(pid)
|
||||
|
||||
// user not found
|
||||
if (!profile) {
|
||||
if (refs.isFeedId(pid)) {
|
||||
profile = {
|
||||
assignedBy: {},
|
||||
id: pid,
|
||||
isEmpty: true
|
||||
}
|
||||
} else {
|
||||
ui.setPage('profile', h('.layout-twocol',
|
||||
h('.layout-main',
|
||||
h('.well', { style: 'margin-top: 5px; background: #fff' },
|
||||
h('h3', { style: 'margin-top: 0' }, 'Invalid user ID'),
|
||||
h('p',
|
||||
h('em', pid),
|
||||
' is not a valid user ID. ',
|
||||
h('img.emoji', { src: './img/emoji/disappointed.png', title: 'disappointed', width: 20, height: 20, style: 'vertical-align: top' })
|
||||
)
|
||||
)
|
||||
)
|
||||
))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var isSelf = (pid == app.user.id)
|
||||
var isFollowing = social.follows(app.user.id, pid)
|
||||
var followsYou = social.follows(pid, app.user.id)
|
||||
var hasFlagged = social.flags(app.user.id, pid)
|
||||
var hasBlocked = social.blocks(app.user.id, pid)
|
||||
var followers1 = social.followedFollowers(app.user.id, pid, true)
|
||||
var followers2 = social.unfollowedFollowers(app.user.id, pid)
|
||||
var followeds = social.followeds(pid)
|
||||
var flaggers = social.followedFlaggers(app.user.id, pid, true)
|
||||
|
||||
// name conflict controls
|
||||
var nameConflictDlg
|
||||
var nameConflicts = []
|
||||
for (var id in app.users.names) {
|
||||
if (id != pid && app.users.names[id] == app.users.names[pid])
|
||||
nameConflicts.push(id)
|
||||
}
|
||||
if (nameConflicts.length) {
|
||||
nameConflictDlg = h('.well.white', { style: 'margin: -10px 15px 15px' },
|
||||
h('p', { style: 'margin-bottom: 10px' }, h('strong', 'Other users named "'+app.users.names[pid]+'":')),
|
||||
h('ul.list-inline', nameConflicts.map(function (id) { return h('li', com.user(id)) })),
|
||||
h('p', h('small', 'ProTip: You can rename users to avoid getting confused!'))
|
||||
)
|
||||
}
|
||||
|
||||
// flag controls
|
||||
var flagMsgs
|
||||
if (flaggers.length) {
|
||||
flagMsgs = h('.profile-flags.message-feed')
|
||||
flaggers.forEach(function (id) {
|
||||
var flag = social.flags(id, pid)
|
||||
if (flag.reason && flag.key) {
|
||||
app.ssb.get(flag.key, function (err, flagMsg) {
|
||||
if (err) console.error(err)
|
||||
if (flagMsg) flagMsgs.appendChild(com.message({ key: flag.key, value: flagMsg }))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var hasMsgs = false
|
||||
var content = com.messageFeed({ feed: feedFn, cursor: feedCursor, filter: feedFilter, infinite: true, onempty: onNoMsgs })
|
||||
function feedFn (opts) {
|
||||
opts = opts || {}
|
||||
opts.id = pid
|
||||
return app.ssb.createUserStream(opts)
|
||||
}
|
||||
function feedCursor (msg) {
|
||||
if (msg)
|
||||
return msg.value.sequence
|
||||
}
|
||||
function feedFilter (msg) {
|
||||
hasMsgs = true
|
||||
// post by this user
|
||||
var c = msg.value.content
|
||||
if (msg.value.author == pid && c.type == 'post')
|
||||
return true
|
||||
}
|
||||
function onNoMsgs (feedEl) {
|
||||
if (hasMsgs) {
|
||||
feedEl.appendChild(h('p.text-center.text-muted', h('br'), 'No posts...yet!'))
|
||||
} else {
|
||||
feedEl.appendChild(h('div', { style: 'margin: 12px 1px; background: #fff; padding: 15px 15px 10px' },
|
||||
h('h3', { style: 'margin-top: 0' }, 'Umm... who is this?'),
|
||||
h('p', 'This user\'s data hasn\'t been fetched yet, so we don\'t know anything about them!'),
|
||||
h('p', com.userDownloader(pid))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// render page
|
||||
ui.setPage('profile', h('.layout-twocol',
|
||||
h('.layout-main',
|
||||
h('.profile-header',
|
||||
h('h1', h('strong', name)),
|
||||
h('a.btn.btn-3d', { href: '#', onclick: privateMessage, title: 'Send an encrypted message to '+name }, com.icon('envelope'), ' Secret Message')
|
||||
),
|
||||
flagMsgs ? h('.message-feed-container', flagMsgs) : '',
|
||||
content),
|
||||
h('.layout-rightnav',
|
||||
h('.profile-controls',
|
||||
com.contactPlaque(profile, followers1.length + followers2.length, flaggers.length),
|
||||
(hasBlocked) ? h('.block', 'BLOCKED') : '',
|
||||
(!isSelf) ?
|
||||
[
|
||||
(followsYou) ? h('.follows-you', 'Follows You') : '',
|
||||
h('.btns',
|
||||
h('.btns-group',
|
||||
(hasBlocked) ? '' : h('a.btn.btn-3d', { href: '#', onclick: toggleFollow }, com.icon('user'), ((isFollowing) ? ' Unfollow' : ' Follow')),
|
||||
' ',
|
||||
h('a.btn.btn-3d', { href: '#', onclick: renameModal }, com.icon('pencil'), ' Rename'),
|
||||
' ',
|
||||
h('a.btn.btn-3d', { href: '#', onclick: flagModal }, com.icon('flag'), ((!!hasFlagged) ? ' Unflag' : ' Flag'))))
|
||||
] :
|
||||
h('.btns.text-center', { style: 'padding-right: 10px' },
|
||||
h('a.btn.btn-3d', { href: '#/setup', title: 'Update your name or image' }, com.icon('pencil'), ' Edit Your Profile')),
|
||||
nameConflictDlg,
|
||||
(!isSelf) ?
|
||||
com.connectionGraph(app.user.id, pid, { w: 5.5, drawLabels: false, touchEnabled: false, mouseEnabled: false, mouseWheelEnabled: false }) :
|
||||
'',
|
||||
(flaggers.length) ? h('.relations', h('h4', 'flagged by'), com.userHexagrid(flaggers, { nrow: 4 })) : '',
|
||||
(followers1.length) ? h('.relations', h('h4', 'followers you follow'), com.userHexagrid(followers1, { nrow: 4 })) : '',
|
||||
(followers2.length) ? h('.relations', h('h4', 'followers you don\'t follow'), com.userHexagrid(followers2, { nrow: 4 })) : '',
|
||||
(followeds.length) ? h('.relations', h('h4', name, ' is following'), com.userHexagrid(followeds, { nrow: 4 })) : ''
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
// handlers
|
||||
|
||||
function privateMessage (e) {
|
||||
e.preventDefault()
|
||||
subwindows.pm({ recipients: [pid] })
|
||||
}
|
||||
|
||||
function renameModal (e) {
|
||||
e.preventDefault()
|
||||
modals.setName(pid)
|
||||
}
|
||||
|
||||
function toggleFollow (e) {
|
||||
e.preventDefault()
|
||||
if (isSelf)
|
||||
return
|
||||
ui.pleaseWait(true, 500)
|
||||
if (isFollowing)
|
||||
app.ssb.publish(schemas.unfollow(pid), done)
|
||||
else
|
||||
app.ssb.publish(schemas.follow(pid), done)
|
||||
function done (err) {
|
||||
ui.pleaseWait(false)
|
||||
if (err) modals.error('Error While Publishing', err, 'This error occured while trying to un/follow somebody on their profile page.')
|
||||
else ui.refreshPage()
|
||||
}
|
||||
}
|
||||
|
||||
function flagModal (e) {
|
||||
e.preventDefault()
|
||||
if (isSelf)
|
||||
return
|
||||
if (!hasFlagged)
|
||||
modals.flag(pid)
|
||||
else {
|
||||
var done = multicb()
|
||||
app.ssb.publish(schemas.unblock(pid), done())
|
||||
app.ssb.publish(schemas.unflag(pid), done())
|
||||
done(function (err) {
|
||||
if (err) modals.error('Error While Publishing', err, 'This error occured while trying to un/flag somebody on their profile page.')
|
||||
else ui.refreshPage()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
289
ui/lib/pages/publisher.js
Normal file
289
ui/lib/pages/publisher.js
Normal file
@@ -0,0 +1,289 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var o = require('observable')
|
||||
var ref = require('ssb-ref')
|
||||
var mime = require('mime-types')
|
||||
var pwt = require('published-working-tree')
|
||||
var multicb = require('multicb')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var u = require('../util')
|
||||
var modals = require('../ui/modals')
|
||||
var com = require('../com')
|
||||
var social = require('../social-graph')
|
||||
|
||||
// symbols, used to avoid collisions with filenames
|
||||
var ISROOT = Symbol('isroot')
|
||||
var ISOPEN = Symbol('isopen')
|
||||
|
||||
module.exports = function () {
|
||||
|
||||
var done = multicb({ pluck: 1 })
|
||||
app.ssb.patchwork.getPaths(done())
|
||||
app.ssb.patchwork.getSite(app.user.id, done())
|
||||
done(function (err, res) {
|
||||
if (err)
|
||||
return modals.error('Error Loading User Info', err, 'This error occurred while loading the publisher page')
|
||||
|
||||
// markup
|
||||
|
||||
var folderPath = o(res[0].site)
|
||||
var publishedTree = res[1] ? toTree(res[1]) : null
|
||||
var folderData = o()
|
||||
|
||||
var publishBtn
|
||||
var folderInput = h('input.hidden', { type: 'file', webkitdirectory: true, directory: true, onchange: onfolderchange })
|
||||
ui.setPage('publisher', h('.layout-onecol',
|
||||
h('.layout-main',
|
||||
h('h3', h('strong', 'Your Site')),
|
||||
h('form',
|
||||
h('p',
|
||||
folderInput,
|
||||
h('a.btn.btn-3d', { onclick: folderInput.click.bind(folderInput) }, 'Select Folder'),
|
||||
' ',
|
||||
h('span.files-view-pathctrl', folderPath),
|
||||
publishBtn = o.transform(folderData, function (d) {
|
||||
var c = pwt.changes(d)
|
||||
if (!c.adds.length && !c.dels.length && !c.mods.length)
|
||||
return h('a.pull-right.btn.btn-primary.disabled', 'No Changes')
|
||||
|
||||
var changes = []
|
||||
if (c.adds.length) changes.push('+'+c.adds.length)
|
||||
if (c.dels.length) changes.push('-'+c.dels.length)
|
||||
if (c.mods.length) changes.push('^'+c.mods.length)
|
||||
changes = changes.join(' / ')
|
||||
return h('a.pull-right.btn.btn-primary', { onclick: onpublish }, 'Publish ('+changes+')')
|
||||
})
|
||||
),
|
||||
o.transform(folderData, function (fd) {
|
||||
if (!fd)
|
||||
return
|
||||
return h('table.files-view',
|
||||
h('tbody', render(-1, fd))
|
||||
)
|
||||
})
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
function render (depth, item) {
|
||||
if (item[pwt.TYPE] == 'file') {
|
||||
return h('tr',
|
||||
h('td', getchange(item)),
|
||||
h('td', h('input', { type: 'checkbox', checked: item[pwt.ACTIVE], onchange: oncheck(item) })),
|
||||
h('td',
|
||||
h('a', { style: 'padding-left: '+(+depth*20)+'px' }, com.icon('file'), item[pwt.NAME]), ' ',
|
||||
getstate(item)
|
||||
),
|
||||
h('td', mime.lookup(item[pwt.NAME])||''),
|
||||
h('td', item[pwt.STAT] && u.bytesHuman(item[pwt.STAT].size))
|
||||
)
|
||||
}
|
||||
|
||||
var rows = []
|
||||
|
||||
if (!item[ISROOT]) {
|
||||
var col = h('td.folder',
|
||||
{ onclick: ontoggle(item) },
|
||||
h('span',
|
||||
{ style: 'padding-left: '+(+depth*20)+'px' },
|
||||
com.icon('folder-'+(item[ISOPEN]?'open':'close')), item[pwt.NAME], ' ',
|
||||
getstate(item)
|
||||
)
|
||||
)
|
||||
col.setAttribute('colspan', 3)
|
||||
rows.push(h('tr',
|
||||
h('td', getchange(item)),
|
||||
h('td', h('input', { type: 'checkbox', checked: item[pwt.ACTIVE], onchange: oncheck(item) })),
|
||||
col
|
||||
))
|
||||
}
|
||||
|
||||
// render folders, then files
|
||||
if (item[ISOPEN]) {
|
||||
for (var k in item)
|
||||
if (item[k][pwt.TYPE] == 'directory')
|
||||
rows.push(render(depth + 1, item[k]))
|
||||
for (var k in item)
|
||||
if (item[k][pwt.TYPE] == 'file')
|
||||
rows.push(render(depth + 1, item[k]))
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
function setactive (item, v) {
|
||||
item[pwt.ACTIVE] = v
|
||||
for (var k in item)
|
||||
setactive(item[k], v)
|
||||
}
|
||||
|
||||
function getstate (item) {
|
||||
if (item[pwt.DELETED])
|
||||
return h('em.text-muted', 'not on disk')
|
||||
if (item[pwt.MODIFIED])
|
||||
return h('em.text-muted', 'modified')
|
||||
if (item[pwt.PUBLISHED])
|
||||
return h('em.text-muted', 'published')
|
||||
}
|
||||
|
||||
function getchange (item) {
|
||||
return ({ add: 'add', mod: 'update', del: 'remove' })[pwt.change(item)] || ''
|
||||
}
|
||||
|
||||
// handlers
|
||||
|
||||
function onfolderchange () {
|
||||
folderPath(folderInput.files[0].path)
|
||||
}
|
||||
|
||||
folderPath(function (path) {
|
||||
if (!path)
|
||||
return
|
||||
ui.pleaseWait(true, 100)
|
||||
|
||||
// :TEMP HACK: create the directory if it does not exist
|
||||
var fs = require('fs')
|
||||
if (!fs.existsSync(path))
|
||||
fs.mkdirSync(path)
|
||||
|
||||
pwt.loadworking(path, publishedTree, function (err, data) {
|
||||
ui.pleaseWait(false)
|
||||
data[ISROOT] = true
|
||||
data[ISOPEN] = true
|
||||
folderData(data)
|
||||
})
|
||||
})
|
||||
|
||||
function oncheck (item) {
|
||||
return function () {
|
||||
var newcheck = !item[pwt.ACTIVE]
|
||||
if (newcheck && item[pwt.TYPE] == 'directory' && !item[pwt.DELETED]) {
|
||||
// read all of the directory first
|
||||
ui.pleaseWait(true, 100)
|
||||
pwt.readall(item[pwt.PATH], item, next)
|
||||
}
|
||||
else next()
|
||||
|
||||
function next() {
|
||||
ui.pleaseWait(false)
|
||||
setactive(item, newcheck)
|
||||
folderData(folderData())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ontoggle (item) {
|
||||
return function () {
|
||||
item[ISOPEN] = !item[ISOPEN]
|
||||
if (item[pwt.DIRREAD] || item[pwt.DELETED])
|
||||
folderData(folderData())
|
||||
else {
|
||||
pwt.read(item[pwt.PATH], item, true, function () {
|
||||
folderData(folderData())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onpublish () {
|
||||
var m
|
||||
var c = pwt.changes(folderData())
|
||||
|
||||
var basepathLen = folderPath().length + 1
|
||||
function renderChange (type, label) {
|
||||
return function (item) {
|
||||
return h(type,
|
||||
h('.action', label),
|
||||
h('.path', item[pwt.PATH].slice(basepathLen)),
|
||||
h('.size', item[pwt.STAT] && u.bytesHuman(item[pwt.STAT].size)),
|
||||
h('.type', item[pwt.STAT] && mime.lookup(item[pwt.NAME])||'')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function onconfirmpublish () {
|
||||
var done = multicb()
|
||||
var msg = {
|
||||
type: 'site',
|
||||
includes: c.adds.concat(c.mods).map(function (item) {
|
||||
// create link
|
||||
var link = {
|
||||
link: null,
|
||||
path: item[pwt.PATH].slice(basepathLen),
|
||||
mtime: item[pwt.STAT].mtime.getTime(),
|
||||
size: item[pwt.STAT].size,
|
||||
type: mime.lookup(item[pwt.NAME]) || undefined
|
||||
}
|
||||
|
||||
// add blob
|
||||
var cb = done()
|
||||
app.ssb.patchwork.addFileToBlobs(item[pwt.PATH], function (err, res) {
|
||||
if (err) {
|
||||
modals.error('Failed to Publish File', err, 'This error occurred while adding files to the blobstore in the publisher interface.')
|
||||
cb(err)
|
||||
} else {
|
||||
link.link = res.hash
|
||||
if (res.width && res.height) {
|
||||
link.width = res.width
|
||||
link.height = res.height
|
||||
}
|
||||
cb()
|
||||
}
|
||||
})
|
||||
|
||||
return link
|
||||
}),
|
||||
excludes: c.dels.map(function (item) {
|
||||
return {
|
||||
link: item.link,
|
||||
path: item[pwt.PATH].slice(basepathLen)
|
||||
}
|
||||
})
|
||||
}
|
||||
m.close()
|
||||
|
||||
ui.pleaseWait(true, 100)
|
||||
done(function (err) {
|
||||
ui.pleaseWait(false)
|
||||
if (err) return
|
||||
|
||||
app.ssb.publish(msg, function (err) {
|
||||
if (err)
|
||||
return modals.error('Failed to Publish Files', err, 'This error occurred while publishing the `site` message in the publisher interface.')
|
||||
ui.refreshPage()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
m = modals.default(h('.modal-form',
|
||||
h('h3', 'Review Changes'),
|
||||
h('.files-view-changes',
|
||||
c.adds.map(renderChange('.add', '+')),
|
||||
c.mods.map(renderChange('.mod', '^')),
|
||||
c.dels.map(renderChange('.del', '-'))
|
||||
),
|
||||
h('a.btn.btn-primary', { onclick: onconfirmpublish }, 'Publish')
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function set (obj, path, value) {
|
||||
var k
|
||||
while (true) {
|
||||
k = path.shift()
|
||||
if (!path.length)
|
||||
break
|
||||
if (!obj[k])
|
||||
obj[k] = {}
|
||||
obj = obj[k]
|
||||
}
|
||||
obj[k] = value
|
||||
}
|
||||
function toTree (site) {
|
||||
var tree = {}
|
||||
for (var path in site)
|
||||
set(tree, path.split('/'), site[path])
|
||||
return tree
|
||||
}
|
||||
66
ui/lib/pages/search.js
Normal file
66
ui/lib/pages/search.js
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var mlib = require('ssb-msgs')
|
||||
var pull = require('pull-stream')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var com = require('../com')
|
||||
var social = require('../social-graph')
|
||||
|
||||
module.exports = function () {
|
||||
|
||||
// filters
|
||||
|
||||
if (!app.page.param) {
|
||||
window.location.hash = '#/'
|
||||
return
|
||||
}
|
||||
var regex = new RegExp(app.page.param.split(' ').join('|'), 'i')
|
||||
|
||||
function postFeed (opts) {
|
||||
opts = opts || {}
|
||||
opts.type = 'post'
|
||||
return app.ssb.messagesByType(opts)
|
||||
}
|
||||
|
||||
function postFilter (m) {
|
||||
var a = m.value.author, c = m.value.content
|
||||
if (app.users.profiles[a] && app.users.profiles[a].flagged) // flagged by user
|
||||
return false
|
||||
if (c.text && regex.test(c.text))
|
||||
return true
|
||||
// if (app.homeMode.view == 'all')
|
||||
// return true
|
||||
// if (app.homeMode.view == 'friends')
|
||||
// return a == app.user.id || social.follows(app.user.id, a)
|
||||
// return social.follows(app.homeMode.view, a) // `view` is the id of a pub
|
||||
}
|
||||
|
||||
function contactFilter (p) {
|
||||
if (p.self.name && regex.test(p.self.name))
|
||||
return true
|
||||
}
|
||||
|
||||
function cursor (msg) {
|
||||
if (msg)
|
||||
return msg.ts
|
||||
}
|
||||
|
||||
// markup
|
||||
|
||||
ui.setPage('home', h('.layout-twocol',
|
||||
h('.layout-main',
|
||||
h('h3', 'Search, "', app.page.param, '"'),
|
||||
com.messageFeed({ feed: postFeed, cursor: cursor, filter: postFilter, onempty: onempty, infinite: true })
|
||||
),
|
||||
h('.layout-rightnav',
|
||||
h('h3', 'People'),
|
||||
com.contactFeed({ filter: contactFilter, compact: true, onempty: onempty })
|
||||
)
|
||||
))
|
||||
|
||||
function onempty (el) {
|
||||
el.appendChild(h('p', 'No results found'))
|
||||
}
|
||||
|
||||
}
|
||||
108
ui/lib/pages/setup.js
Normal file
108
ui/lib/pages/setup.js
Normal file
@@ -0,0 +1,108 @@
|
||||
'ust strict'
|
||||
var h = require('hyperscript')
|
||||
var schemas = require('ssb-msg-schemas')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var modals = require('../ui/modals')
|
||||
var com = require('../com')
|
||||
|
||||
module.exports = function () {
|
||||
var name = app.users.names[app.user.id] || ''
|
||||
var profilePic = null
|
||||
var is_new = !name
|
||||
|
||||
// markup
|
||||
|
||||
var nameInput = h('input.form-control', { type: 'text', name: 'name', placeholder: 'Nickname', value: name, onkeyup: checkInput })
|
||||
var imageUploader = com.imageUploader({ onupload: onImageUpload, existing: com.profilePicUrl(app.user.id) })
|
||||
var issue = h('.text-danger.hide')
|
||||
var postBtn = h('button.btn.btn-primary', { onclick: post, disabled: is_new }, 'Save')
|
||||
ui.setPage('setup', h('.layout-setup',
|
||||
h('.layout-setup-left',
|
||||
h('h2', (is_new) ? 'New account' : 'Edit Your Profile'),
|
||||
h('.panel.panel-default', { style: 'border: 0' },
|
||||
h('.panel-body',
|
||||
h('.form-group',
|
||||
h('label.control-label', 'Your nickname'),
|
||||
nameInput
|
||||
)
|
||||
)
|
||||
),
|
||||
h('.panel.panel-default', { style: 'border: 0' },
|
||||
h('.panel-body',
|
||||
h('label.control-label', 'Your profile pic'),
|
||||
imageUploader
|
||||
)
|
||||
)
|
||||
),
|
||||
h('.layout-setup-right', h('.layout-setup-right-inner',
|
||||
(is_new) ?
|
||||
[
|
||||
h('p', 'Welcome to ', h('strong', 'Secure Scuttlebutt!')),
|
||||
h('p', 'Fill out your profile and then click ', h('strong', 'Save'), ' to get started.')
|
||||
] :
|
||||
h('p', 'Update your profile and then click ', h('strong', 'Save'), ' to publish the changes.'),
|
||||
h('.panel.panel-default', { style: 'border: 0; display: inline-block' },
|
||||
h('.panel-body', issue, postBtn)),
|
||||
(!is_new) ? h('div', { style: 'padding: 0 22px' }, h('a.text-muted', { href: '#', onclick: oncancel }, 'Cancel')) : ''
|
||||
))
|
||||
))
|
||||
|
||||
// handlers
|
||||
|
||||
var badNameCharsRegex = /[^A-z0-9\._-]/
|
||||
function checkInput (e) {
|
||||
if (!nameInput.value) {
|
||||
postBtn.setAttribute('disabled', true)
|
||||
postBtn.classList.remove('hide')
|
||||
issue.classList.add('hide')
|
||||
} else if (badNameCharsRegex.test(nameInput.value)) {
|
||||
issue.innerHTML = 'We\'re sorry, your name can only include A-z 0-9 . _ - and cannot have spaces.'
|
||||
postBtn.setAttribute('disabled', true)
|
||||
postBtn.classList.add('hide')
|
||||
issue.classList.remove('hide')
|
||||
} else if (nameInput.value.slice(-1) == '.') {
|
||||
issue.innerHTML = 'We\'re sorry, your name cannot end with a period.'
|
||||
postBtn.setAttribute('disabled', true)
|
||||
postBtn.classList.add('hide')
|
||||
issue.classList.remove('hide')
|
||||
} else {
|
||||
postBtn.removeAttribute('disabled')
|
||||
postBtn.classList.remove('hide')
|
||||
issue.classList.add('hide')
|
||||
}
|
||||
}
|
||||
|
||||
function post (e) {
|
||||
e.preventDefault()
|
||||
if (!nameInput.value)
|
||||
return
|
||||
|
||||
// close out image uploader if the user didnt
|
||||
imageUploader.forceDone(function () {
|
||||
|
||||
// publish
|
||||
ui.pleaseWait(true, 500)
|
||||
app.ssb.publish(schemas.about(app.user.id, nameInput.value, profilePic), function (err) {
|
||||
ui.pleaseWait(false)
|
||||
if (err) modals.error('Error While Publishing', err, 'This error occurred while trying to post a new profile in setup.')
|
||||
else window.location = '#/'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function oncancel (e) {
|
||||
e.preventDefault()
|
||||
window.location = '#/profile/'+app.user.id
|
||||
}
|
||||
|
||||
function onImageUpload (hasher) {
|
||||
profilePic = {
|
||||
link: '&'+hasher.digest,
|
||||
size: hasher.size,
|
||||
type: 'image/png',
|
||||
width: 275,
|
||||
height: 275
|
||||
}
|
||||
}
|
||||
}
|
||||
27
ui/lib/pages/stars.js
Normal file
27
ui/lib/pages/stars.js
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var com = require('../com')
|
||||
|
||||
module.exports = function () {
|
||||
var p = app.page.param || 'onyours'
|
||||
var render = (p == 'onyours') ? com.messageSummary : com.message
|
||||
var feed = (p == 'onyours') ? app.ssb.patchwork.createVoteStream : app.ssb.patchwork.createMyvoteStream
|
||||
|
||||
// markup
|
||||
|
||||
ui.setPage('stars', h('.layout-onecol',
|
||||
h('.layout-main',
|
||||
h('h3.text-center',
|
||||
h((p == 'onyours' ? 'strong' : 'a'), { href: '#/stars/onyours'}, 'Stars on Your Posts'),
|
||||
' / ',
|
||||
h((p == 'byyou' ? 'strong' : 'a'), { href: '#/stars/byyou'}, 'Starred by You')
|
||||
),
|
||||
com.messageFeed({ render: render, feed: feed, markread: true, onempty: onempty, infinite: true }))
|
||||
))
|
||||
|
||||
function onempty (feedEl) {
|
||||
feedEl.appendChild(h('p.text-center', { style: 'margin: 25px 0; padding: 10px; color: gray' }, 'No stars... yet!'))
|
||||
}
|
||||
}
|
||||
113
ui/lib/pages/sync.js
Normal file
113
ui/lib/pages/sync.js
Normal file
@@ -0,0 +1,113 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var o = require('observable')
|
||||
var mlib = require('ssb-msgs')
|
||||
var pull = require('pull-stream')
|
||||
var multicb = require('multicb')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var modals = require('../ui/modals')
|
||||
var com = require('../com')
|
||||
var u = require('../util')
|
||||
var social = require('../social-graph')
|
||||
|
||||
module.exports = function () {
|
||||
|
||||
// markup
|
||||
|
||||
var pubStatusEl = h('.pub-status')
|
||||
var peersEl = h('.peers',
|
||||
h('h3', 'Mesh Network', h('a.pull-right.btn.btn-3d.btn-sm', { onclick: addnode }, com.icon('plus'), ' Add Node...')),
|
||||
o.transform(app.observ.peers, function (peers) {
|
||||
return h('div', peers.map(renderPeer))
|
||||
})
|
||||
)
|
||||
ui.setPage('sync', h('.layout-onecol',
|
||||
h('.layout-main',
|
||||
o.transform(app.observ.peers, function () {
|
||||
var stats = u.getPubStats()
|
||||
var danger1 = (stats.membersof === 0) ? '.text-danger' : ''
|
||||
var danger2 = (stats.active === 0) ? '.text-danger' : ''
|
||||
|
||||
var warning
|
||||
if (stats.membersof === 0)
|
||||
warning = h('p', com.icon('warning-sign'), ' You need to join a pub if you want to communicate across the Internet!')
|
||||
else if (stats.active === 0)
|
||||
warning = h('p', com.icon('warning-sign'), ' None of your pubs are responding! Are you connected to the Internet?')
|
||||
|
||||
return h('.pub-status',
|
||||
h('h3'+danger1, 'You\'re followed by ', stats.membersof,' public node', (stats.membersof==1?'':'s'), ' ', h('small'+danger2, stats.active, ' connected')),
|
||||
warning,
|
||||
h('p', h('a.btn.btn-3d', { href: '#', onclick: modals.invite }, com.icon('cloud'), ' Join a Public Node'))
|
||||
)
|
||||
}),
|
||||
peersEl
|
||||
)
|
||||
))
|
||||
|
||||
|
||||
function setprogress (el, p, label) {
|
||||
el.querySelector('.progress-bar').style.width = p + '%'
|
||||
el.querySelector('.progress-bar span').innerText = label
|
||||
if (label)
|
||||
el.querySelector('.progress-bar').style.minWidth = '12%'
|
||||
else
|
||||
el.querySelector('.progress-bar').style.minWidth = '2%'
|
||||
}
|
||||
|
||||
function renderPeer (peer) {
|
||||
function onsync (e) {
|
||||
e.preventDefault()
|
||||
app.ssb.gossip.connect({ host: peer.host, port: peer.port, key: peer.key }, function (){})
|
||||
}
|
||||
|
||||
var lastConnect
|
||||
if (peer.time) {
|
||||
if (peer.time.connect > peer.time.attempt)
|
||||
lastConnect = [h('span.text-success', com.icon('ok')), ' Synced '+(new Date(peer.time.connect).toLocaleString())]
|
||||
else if (peer.time.attempt) {
|
||||
lastConnect = [h('span.text-danger', com.icon('remove')), ' Attempted (but failed) to connect at '+(new Date(peer.time.attempt).toLocaleString())]
|
||||
}
|
||||
}
|
||||
|
||||
var el = h('.peer' + ((peer.connected)?'.connected':''), { 'data-id': peer.key },
|
||||
com.userHexagon(peer.key, 80),
|
||||
h('.details',
|
||||
social.follows(peer.key, app.user.id) ? h('small.pull-right.label.label-success', 'Follows You') : '',
|
||||
h('h3',
|
||||
com.userName(peer.key),
|
||||
' ',
|
||||
((peer.connected) ?
|
||||
h('a.btn.btn-3d.btn-xs.disabled', 'Syncing') :
|
||||
h('a.btn.btn-3d.btn-xs', { href: '#', onclick: onsync }, 'Sync')),
|
||||
' ',
|
||||
h('br'), h('small', peer.host+':'+peer.port+':'+peer.key)
|
||||
),
|
||||
h('.progress', h('.progress-bar.progress-bar-striped.active', h('span'))),
|
||||
h('p.last-connect', lastConnect)
|
||||
)
|
||||
)
|
||||
|
||||
if (peer.connected) {
|
||||
if (!peer.progress)
|
||||
setprogress(el, 0, ' Connecting... ')
|
||||
else if (peer.progress.sync)
|
||||
setprogress(el, 100, 'Live-streaming')
|
||||
else
|
||||
setprogress(el, Math.round(peer.progress.current / peer.progress.total * 100), 'Syncing...')
|
||||
}
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
// handlers
|
||||
|
||||
function addnode () {
|
||||
modals.prompt('Nodes full address:', 'host:port@key', 'Connect', function (err, addr) {
|
||||
app.ssb.gossip.connect(addr, function (err) {
|
||||
if (err)
|
||||
modals.error('Failed to Connect', err, 'Error occurred while trying to manually add a node to the network mesh.')
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
42
ui/lib/pages/webview.js
Normal file
42
ui/lib/pages/webview.js
Normal file
@@ -0,0 +1,42 @@
|
||||
'use strict'
|
||||
var h = require('hyperscript')
|
||||
var o = require('observable')
|
||||
var com = require('../com')
|
||||
var app = require('../app')
|
||||
var ui = require('../ui')
|
||||
var ssbref = require('ssb-ref')
|
||||
|
||||
module.exports = function (opts) {
|
||||
var param = (opts && opts.param) ? opts.param : app.page.param
|
||||
var port = (ssbref.isLink(param)) ? 7777 : 7778
|
||||
var url = 'http://localhost:' + port + '/' + param
|
||||
|
||||
// markup
|
||||
|
||||
var webview = com.webview({ url: url })
|
||||
ui.setPage('webview', h('.layout-grid',
|
||||
h('.layout-grid-col.webview-left', webview),
|
||||
(opts && opts.sideview) ? h('.layout-grid-col.webview-right', { style: showhide(app.observ.sideview) }, opts.sideview) : ''
|
||||
), { onPageTeardown: function () {
|
||||
window.removeEventListener('resize', resize)
|
||||
}})
|
||||
|
||||
function showhide (input) {
|
||||
return { display: o.transform(input, function (v) { return (v) ? 'block' : 'none' }) }
|
||||
}
|
||||
|
||||
// dynamically size various controls
|
||||
resize()
|
||||
window.addEventListener('resize', resize)
|
||||
function resize () {
|
||||
[
|
||||
[webview.querySelector('::shadow object'), 0],
|
||||
[document.querySelector('.webview-page .layout-grid'), 0],
|
||||
[document.querySelector('.webview-page .webview-left'), 0],
|
||||
[document.querySelector('.webview-page .webview-right'), 0]
|
||||
].forEach(function (entry) {
|
||||
if (entry[0])
|
||||
entry[0].style.height = (window.innerHeight - 40 - entry[1]) + 'px'
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user