src/microblogPane/microblogPane.js
/*
Microblog pane
Charles McKenzie <charles2@mit.edu>
*/
/* global alert */
var UI = require('solid-ui')
module.exports = {
icon: UI.icons.originalIconBase + 'microblog/microblog.png',
name: 'microblogPane',
label: function (subject) {
if (UI.store.whether(subject, UI.ns.rdf('type'), UI.ns.foaf('Person'))) {
return 'Microblog'
} else {
return null
}
},
render: function (s, doc) {
//* **********************************************
// NAMESPACES SECTION
//* **********************************************
var SIOC = UI.rdf.Namespace('http://rdfs.org/sioc/ns#')
var SIOCt = UI.rdf.Namespace('http://rdfs.org/sioc/types#')
var FOAF = UI.rdf.Namespace('http://xmlns.com/foaf/0.1/')
var terms = UI.rdf.Namespace('http://purl.org/dc/terms/')
var RDF = UI.ns.rdf
var kb = UI.store
var charCount = 140
var sf = UI.store.fetcher
//* **********************************************
// BACK END
//* **********************************************
var sparqlUpdater = kb.updater
// ----------------------------------------------
// FOLLOW LIST
// store the URIs of followed users for
// dereferencing the @replies
// ----------------------------------------------
var FollowList = function (user) {
this.userlist = {}
this.uris = {}
var myFollows = kb.each(kb.sym(user), SIOC('follows'))
for (var mf in myFollows) {
this.add(kb.any(myFollows[mf], SIOC('id')), myFollows[mf].uri)
}
}
FollowList.prototype.add = function (user, uri) {
// add a user to the follows store
if (this.userlist[user]) {
if (!(uri in this.uris)) {
this.userlist[user].push(uri)
this.uris[uri] = ''
}
} else {
this.userlist[user] = [uri]
}
}
FollowList.prototype.selectUser = function (user) {
// check if a user is in the follows list.
if (this.userlist[user]) {
return [this.userlist[user].length === 1, this.userlist[user]]
} else {
// user does not follow any users with this nick
return [false, []]
}
}
// ----------------------------------------------
// FAVORITES
// controls the list of favorites.
// constructor expects a user as uri.
// ----------------------------------------------
var Favorites = function (user) {
this.favorites = {}
this.favoritesURI = ''
if (!user) {
// TODO is this even useful?
return
}
this.user = user.split('#')[0]
const created = kb.each(kb.sym(user), SIOC('creator_of'))
for (const c in created) {
if (kb.whether(created[c], RDF('type'), SIOCt('FavouriteThings'))) {
this.favoritesURI = created[c]
var favs = kb.each(created[c], SIOC('container_of'))
for (var f in favs) {
this.favorites[favs[f]] = ''
}
break
}
}
}
Favorites.prototype.favorited = function (post) {
/* Favorited- returns true if the post is a favorite
false otherwise */
return kb.sym(post) in this.favorites
}
Favorites.prototype.add = function (post, callback) {
var batch = new UI.rdf.Statement(
this.favoritesURI,
SIOC('container_of'),
kb.sym(post),
kb.sym(this.user)
)
sparqlUpdater.insert_statement(batch, function (a, success, c) {
if (success) {
kb.add(batch.subject, batch.predicate, batch.object, batch.why)
}
callback(a, success, c)
})
}
Favorites.prototype.remove = function (post, callback) {
var batch = new UI.rdf.Statement(
this.favoritesURI,
SIOC('container_of'),
kb.sym(post),
kb.sym(this.user)
)
sparqlUpdater.delete_statement(batch, function (a, success, c) {
if (success) {
kb.add(batch.subject, batch.predicate, batch.object, batch.why)
}
callback(a, success, c)
})
}
// ----------------------------------------------
// MICROBLOG
// store the uri's of followed users for
// dereferencing the @replies.
// ----------------------------------------------
var Microblog = function (kb) {
this.kb = kb
// attempt to fetch user account from local preferences if just
// in case the user's foaf was not writable. add it to the store
// this will probably need to change.
var theUser = UI.authn.currentUser()
if (theUser) {
var theAccount = UI.preferences.get('acct')
if (theAccount) {
theAccount = kb.sym(theAccount)
}
if (theUser && theAccount) {
kb.add(
theUser,
FOAF('holdsAccount'),
theAccount,
theUser.uri.split('#')[0]
)
}
}
}
Microblog.prototype.getUser = function (uri) {
const User = {}
User.name = kb.any(uri, SIOC('name')) ? kb.any(uri, SIOC('name')) : ''
User.avatar = kb.any(uri, SIOC('avatar'))
? kb.any(uri, SIOC('avatar'))
: ''
User.id = kb.any(uri, SIOC('id'))
User.sym = uri
return User
}
Microblog.prototype.getPost = function (uri) {
var Post = {}
// date ----------
var postLink = new Date(kb.anyValue(uri, terms('created')))
var h = postLink.getHours()
var a = h > 12 ? ' PM' : ' AM'
h = h > 12 ? h - 12 : h
var m = postLink.getMinutes()
m = m < 10 ? '0' + m : m
var mo = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
]
var da = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
var ds =
da[postLink.getDay()] +
' ' +
postLink.getDate() +
' ' +
mo[postLink.getMonth()] +
' ' +
postLink.getFullYear()
postLink = h + ':' + m + a + ' on ' + ds
Post.date = postLink
// ---------
Post.mentions = ''
Post.message = String(kb.any(uri, SIOC('content')))
Post.creator = kb.any(uri, SIOC('has_creator'))
Post.uri = ''
return Post
}
Microblog.prototype.gen_random_uri = function (base) {
// generate random uri
var uriNonce = base + '#n' + Math.floor(Math.random() * 10e9)
return kb.sym(uriNonce)
}
Microblog.prototype.statusUpdate = function (
statusMsg,
callback,
replyTo,
meta
) {
var myUserURI = this.getMyURI()
const myUser = kb.sym(myUserURI.split('#')[0])
var newPost = this.gen_random_uri(myUser.uri)
var microlist = kb.each(kb.sym(myUserURI), SIOC('creator_of'))
var micro
for (var microlistelement in microlist) {
if (
kb.whether(
microlist[microlistelement],
RDF('type'),
SIOCt('Microblog')
) &&
!kb.whether(
microlist[microlistelement],
SIOC('topic'),
kb.sym(this.getMyURI())
)
) {
micro = microlist[microlistelement]
break
}
}
// generate new post
var batch = [
new UI.rdf.Statement(
newPost,
RDF('type'),
SIOCt('MicroblogPost'),
myUser
),
new UI.rdf.Statement(
newPost,
SIOC('has_creator'),
kb.sym(myUserURI),
myUser
),
new UI.rdf.Statement(newPost, SIOC('content'), statusMsg, myUser),
new UI.rdf.Statement(newPost, terms('created'), new Date(), myUser),
new UI.rdf.Statement(micro, SIOC('container_of'), newPost, myUser)
]
// message replies
if (replyTo) {
batch.push(
new UI.rdf.Statement(
newPost,
SIOC('reply_of'),
kb.sym(replyTo),
myUser
)
)
}
// @replies, #hashtags, !groupReplies
for (var r in meta.recipients) {
batch.push(
new UI.rdf.Statement(
newPost,
SIOC('topic'),
kb.sym(meta.recipients[r]),
myUser
)
)
batch.push(
new UI.rdf.Statement(kb.any(), SIOC('container_of'), newPost, myUser)
)
var mblogs = kb.each(kb.sym(meta.recipients[r]), SIOC('creator_of'))
for (var mbl in mblogs) {
if (
kb.whether(mblogs[mbl], SIOC('topic'), kb.sym(meta.recipients[r]))
) {
var replyBatch = new UI.rdf.Statement(
mblogs[mbl],
SIOC('container_of'),
newPost,
kb.sym(meta.recipients[r].split('#')[0])
)
sparqlUpdater.insert_statement(replyBatch)
}
}
}
sparqlUpdater.insert_statement(batch, function (a, b, c) {
callback(a, b, c, batch)
})
}
Microblog.prototype.getMyURI = function () {
var me = UI.authn.currentUser()
console.log(me)
var myMicroblog = kb.any(kb.sym(me), FOAF('holdsAccount'))
console.log('\n\n' + myMicroblog)
return myMicroblog ? myMicroblog.uri : false
}
Microblog.prototype.generateNewMB = function (id, name, avatar, loc) {
var host = loc + '/' + id
var rememberMicroblog = function () {
UI.preferences.set('acct', host + '#' + id)
}
var cbgenUserMB = function (a, success, c, d) {
if (success) {
alert(
'Microblog generated at ' +
host +
'#' +
id +
'please add <b>' +
host +
'</b> to your foaf.'
)
// mbCancelNewMB() @@TBD
// assume the foaf is not writable and store the microblog to the
// preferences for later retrieval.
// this will probably need to change.
rememberMicroblog()
for (var triple in d) {
kb.add(
d[triple].subject,
d[triple].predicate,
d[triple].object,
d[triple].why
)
}
}
}
var genUserMB = [
// user
new UI.rdf.Statement(
kb.sym(host + '#' + id),
RDF('type'),
SIOC('User'),
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#' + id),
SIOC('creator_of'),
kb.sym(host + '#mb'),
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#' + id),
SIOC('creator_of'),
kb.sym(host + '#mbn'),
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#' + id),
SIOC('creator_of'),
kb.sym(host + '#fav'),
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#' + id),
SIOC('name'),
name,
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#' + id),
SIOC('id'),
id,
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#' + id),
RDF('label'),
id,
kb.sym(host)
),
new UI.rdf.Statement(
s,
FOAF('holdsAccount'),
kb.sym(host + '#' + id),
kb.sym(host)
),
// microblog
new UI.rdf.Statement(
kb.sym(host + '#mb'),
RDF('type'),
SIOCt('Microblog'),
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#mb'),
SIOC('has_creator'),
kb.sym(host + '#' + id),
kb.sym(host)
),
// notification microblog
new UI.rdf.Statement(
kb.sym(host + '#mbn'),
RDF('type'),
SIOCt('Microblog'),
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#mbn'),
SIOC('topic'),
kb.sym(host + '#' + id),
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#mbn'),
SIOC('has_creator'),
kb.sym(host + '#' + id),
kb.sym(host)
),
// favorites container
new UI.rdf.Statement(
kb.sym(host + '#fav'),
RDF('type'),
SIOCt('FavouriteThings'),
kb.sym(host)
),
new UI.rdf.Statement(
kb.sym(host + '#fav'),
SIOC('has_creator'),
kb.sym(host + '#' + id),
kb.sym(host)
)
]
if (avatar) {
// avatar optional
genUserMB.push(
new UI.rdf.Statement(
kb.sym(host + '#' + id),
SIOC('avatar'),
kb.sym(avatar),
kb.sym(host)
)
)
}
sparqlUpdater.insert_statement(genUserMB, cbgenUserMB)
}
var mb = new Microblog(kb)
var myFavorites = new Favorites(mb.getMyURI())
var myFollowList = new FollowList(mb.getMyURI())
//* **********************************************
// FRONT END FUNCTIONALITY
//* **********************************************
// ----------------------------------------------
// PANE
// User Interface for the Microblog Pane
// ----------------------------------------------
var Pane = function (s, doc, microblogPane) {
var TabManager = function (doc) {
this.tablist = {}
this.doc = doc
this.tabView = doc.createElement('ul')
this.tabView.className = 'tabslist'
}
TabManager.prototype.create = function (id, caption, view, isDefault) {
var tab = this.doc.createElement('li')
tab.innerHTML = caption
if (isDefault) {
tab.className = 'active'
}
tab.id = id
const change = this.change
const tablist = this.tablist
tab.addEventListener(
'click',
function (evt) {
change(evt.target.id, tablist, doc)
},
false
)
this.tablist[id] = { view: view.id, tab: tab }
this.tabView.appendChild(tab)
}
TabManager.prototype.getTabView = function () {
return this.tabView
}
TabManager.prototype.change = function (id, tablist, doc) {
for (var tab in tablist) {
if (tab === id) {
tablist[id].tab.className = 'active'
doc.getElementById(tablist[id].view).className += ' active'
} else {
var view = doc.getElementById(tablist[tab].view)
view.className = view.className.replace(/\w*active\w*/, '')
tablist[tab].tab.className = tablist[id].tab.className.replace(
/\w*active\w*/,
''
)
}
}
}
this.microblogPane = microblogPane
var accounts = kb.each(s, FOAF('holdsAccount'))
for (var a in accounts) {
if (
kb.whether(accounts[a], RDF('type'), SIOC('User')) &&
kb.whether(
kb.any(accounts[a], SIOC('creator_of')),
RDF('type'),
SIOCt('Microblog')
)
) {
var account = accounts[a]
break
}
}
this.Ifollow = kb.whether(kb.sym(mb.getMyURI()), SIOC('follows'), account)
var resourceType = kb.any(s, RDF('type'))
if (
resourceType.uri === SIOCt('Microblog').uri ||
resourceType.uri === SIOCt('MicroblogPost').uri
) {
this.thisIsMe = kb.any(s, SIOC('has_creator')).uri === mb.getMyURI()
} else if (resourceType.uri === SIOC('User').uri) {
this.thisIsMe = s.uri === mb.getMyURI()
} else if (resourceType.uri === FOAF('Person').uri) {
const me = UI.authn.currentUser()
const meUri = me && me.uri
this.thisIsMe = s.uri === meUri
} else {
this.thisIsMe = false
}
this.Tab = new TabManager(doc)
}
Pane.prototype.notify = function (messageString) {
var xmsg = doc.createElement('li')
xmsg.className = 'notify'
xmsg.innerHTML = messageString
doc.getElementById('notify-container').appendChild(xmsg)
setTimeout(function () {
doc.getElementById('notify-container').removeChild(xmsg)
// delete xmsg;
}, 4000)
}
Pane.prototype.header = function (s, doc) {
var that = this
function lsFollowUser () {
var myUser = kb.sym(mb.getMyURI())
// var Ifollow = that.Ifollow
var username = that.creator.name
var mbconfirmFollow = function (uri, success, _msg) {
if (success === true) {
if (!that.Ifollow) {
// prevent duplicate entries from being added to kb (because that was happening)
if (
!kb.whether(
followMe.subject,
followMe.predicate,
followMe.object,
followMe.why
)
) {
kb.add(
followMe.subject,
followMe.predicate,
followMe.object,
followMe.why
)
}
} else {
kb.removeMany(
followMe.subject,
followMe.predicate,
followMe.object,
followMe.why
)
}
console.log(that.Ifollow)
that.Ifollow = !that.Ifollow
xfollowButton.disabled = false
console.log(that.Ifollow)
var followButtonLabel = that.Ifollow ? 'Unfollow ' : 'Follow '
var doFollow = that.Ifollow ? 'now follow ' : 'no longer follow '
xfollowButton.value = followButtonLabel + username
that.notify('You ' + doFollow + username + '.')
}
}
var followMe = new UI.rdf.Statement(
myUser,
SIOC('follows'),
that.creator.sym,
myUser
)
xfollowButton.disabled = true
xfollowButton.value = 'Updating...'
if (!that.Ifollow) {
sparqlUpdater.insert_statement(followMe, mbconfirmFollow)
} else {
sparqlUpdater.delete_statement(followMe, mbconfirmFollow)
}
}
var notify = function (messageString) {
var xmsg = doc.createElement('li')
xmsg.className = 'notify'
xmsg.innerHTML = messageString
doc.getElementById('notify-container').appendChild(xmsg)
setTimeout(function () {
doc.getElementById('notify-container').removeChild(xmsg)
// delete xmsg;
}, 4000)
}
var mbCancelNewMB = function (_evt) {
xupdateContainer.removeChild(
xupdateContainer.childNodes[xupdateContainer.childNodes.length - 1]
)
xcreateNewMB.disabled = false
}
var lsCreateNewMB = function (_evt) {
// disable the create new microblog button.
// then prefills the information.
xcreateNewMB.disabled = true
var xcmb = doc.createElement('div')
var xcmbName = doc.createElement('input')
if (kb.whether(s, FOAF('name'))) {
// handle use of FOAF:NAME
xcmbName.value = kb.any(s, FOAF('name'))
} else {
// handle use of family and given name
xcmbName.value = kb.any(s, FOAF('givenname'))
? kb.any(s, FOAF('givenname')) + ' '
: ''
xcmbName.value += kb.any(s, FOAF('family_name'))
? kb.any(s, FOAF('givenname'))
: ''
xcmbName.value =
kb.any(s, FOAF('givenname')) + ' ' + kb.any(s, FOAF('family_name'))
}
var xcmbId = doc.createElement('input')
xcmbId.value = kb.any(s, FOAF('nick')) ? kb.any(s, FOAF('nick')) : ''
var xcmbAvatar = doc.createElement('input')
if (kb.whether(s, FOAF('img'))) {
// handle use of img
xcmbAvatar.value = kb.any(s, FOAF('img')).uri
} else {
// otherwise try depiction
xcmbAvatar.value = kb.any(s, FOAF('depiction'))
? kb.any(s, FOAF('depiction')).uri
: ''
}
var workspace
// = kb.any(s,WORKSPACE) //TODO - ADD URI FOR WORKSPACE DEFINITION
var xcmbWritable = doc.createElement('input')
xcmbWritable.value =
workspace || 'http://dig.csail.mit.edu/2007/wiki/sandbox' // @@@
xcmb.innerHTML = `
<form class ="createNewMB" id="createNewMB">
<p id="xcmbname"><span class="">Name: </span></p>
<p id="xcmbid">Id: </p>
<p id="xcmbavatar">Avatar: </p>
<p id="xcmbwritable">Host my microblog at: </p>
<input type="button" id="mbCancel" value="Cancel" />
<input type="submit" id="mbCreate" value="Create!" />
</form>
`
xupdateContainer.appendChild(xcmb)
doc.getElementById('xcmbname').appendChild(xcmbName)
doc.getElementById('xcmbid').appendChild(xcmbId)
doc.getElementById('xcmbavatar').appendChild(xcmbAvatar)
doc.getElementById('xcmbwritable').appendChild(xcmbWritable)
doc
.getElementById('mbCancel')
.addEventListener('click', mbCancelNewMB, false)
doc.getElementById('createNewMB').addEventListener(
'submit',
function () {
mb.generateNewMB(
xcmbId.value,
xcmbName.value,
xcmbAvatar.value,
xcmbWritable.value
)
},
false
)
xcmbName.focus()
}
var mbSubmitPost = function () {
var meta = {
recipients: []
}
// user has selected a microblog to post to
if (mb.getMyURI()) {
// let myUser = kb.sym(mb.getMyURI())
// submission callback
var cbconfirmSubmit = function (uri, success, responseText, d) {
if (success === true) {
for (var triple in d) {
kb.add(
d[triple].subject,
d[triple].predicate,
d[triple].object,
d[triple].why
)
}
xupdateSubmit.disabled = false
xupdateStatus.value = ''
mbLetterCount()
notify('Microblog Updated.')
if (that.thisIsMe) {
doc
.getElementById('postNotificationList')
.insertBefore(
that.generatePost(d[0].subject),
doc.getElementById('postNotificationList').childNodes[0]
)
}
} else {
notify('There was a problem submitting your post.')
}
}
var words = xupdateStatus.value.split(' ')
var mbUpdateWithReplies = function () {
xupdateSubmit.disabled = true
xupdateSubmit.value = 'Updating...'
mb.statusUpdate(
xupdateStatus.value,
cbconfirmSubmit,
xinReplyToContainer.value,
meta
)
}
for (var word in words) {
if (words[word].match(/@\w+/)) {
var atUser = words[word].replace(/\W/g, '')
var recipient = myFollowList.selectUser(atUser)
if (recipient[0] === true) {
meta.recipients.push(recipient[1][0])
} else if (recipient[1].length > 1) {
// if multiple users allow the user to choose
var xrecipients = doc.createElement('select')
var xrecipientsSubmit = doc.createElement('input')
xrecipientsSubmit.type = 'button'
xrecipientsSubmit.value = 'Continue'
xrecipientsSubmit.addEventListener(
'click',
function () {
meta.recipients.push(recipient[1][xrecipients.value])
mbUpdateWithReplies()
xrecipients.parentNode.removeChild(xrecipientsSubmit)
xrecipients.parentNode.removeChild(xrecipients)
},
false
)
var recipChoice = function (recip, c) {
var name = kb.any(kb.sym(recip), SIOC('name'))
var choice = doc.createElement('option')
choice.value = c
choice.innerHTML = name
return choice
}
for (var r in recipient[1]) {
xrecipients.appendChild(recipChoice(recipient[1][r], r))
}
xupdateContainer.appendChild(xrecipients)
xupdateContainer.appendChild(xrecipientsSubmit)
return
} else {
// no users known or self reference.
if (
String(
kb.any(kb.sym(mb.getMyURI()), SIOC('id'))
).toLowerCase() === atUser.toLowerCase()
) {
meta.recipients.push(mb.getMyURI())
} else {
notify(
'You do not follow ' +
atUser +
'. Try following ' +
atUser +
' before mentioning them.'
)
return
}
}
}
/* else if(words[word].match(/\#\w+/)){
//hashtag
} else if(words[word].match(/\!\w+/)){
//usergroup
} */
}
mbUpdateWithReplies()
} else {
notify('Please set your microblog first.')
}
}
var mbLetterCount = function () {
xupdateStatusCounter.innerHTML = charCount - xupdateStatus.value.length
xupdateStatusCounter.style.color =
charCount - xupdateStatus.value.length < 0 ? '#c33' : ''
if (xupdateStatus.value.length === 0) {
xinReplyToContainer.value = ''
xupdateSubmit.value = 'Send'
}
}
// reply viewer
var xviewReply = doc.createElement('ul')
xviewReply.className = 'replyView'
xviewReply.addEventListener(
'click',
function () {
xviewReply.className = 'replyView'
},
false
)
this.xviewReply = xviewReply
var headerContainer = doc.createElement('div')
headerContainer.className = 'header-container'
// ---create status update box---
var xnotify = doc.createElement('ul')
xnotify.id = 'notify-container'
xnotify.className = 'notify-container'
this.xnotify = xnotify
var xupdateContainer = doc.createElement('form')
xupdateContainer.className = 'update-container'
xupdateContainer.innerHTML = '<h3>What are you up to?</h3>'
if (mb.getMyURI()) {
var xinReplyToContainer = doc.createElement('input')
xinReplyToContainer.id = 'xinReplyToContainer'
xinReplyToContainer.type = 'hidden'
var xupdateStatus = doc.createElement('textarea')
xupdateStatus.id = 'xupdateStatus'
var xupdateStatusCounter = doc.createElement('span')
xupdateStatusCounter.appendChild(doc.createTextNode(charCount))
xupdateStatus.cols = 30
xupdateStatus.addEventListener('keyup', mbLetterCount, false)
xupdateStatus.addEventListener('focus', mbLetterCount, false)
var xupdateSubmit = doc.createElement('input')
xupdateSubmit.id = 'xupdateSubmit'
xupdateSubmit.type = 'submit'
xupdateSubmit.value = 'Send'
xupdateContainer.appendChild(xinReplyToContainer)
xupdateContainer.appendChild(xupdateStatusCounter)
xupdateContainer.appendChild(xupdateStatus)
xupdateContainer.appendChild(xupdateSubmit)
xupdateContainer.addEventListener('submit', mbSubmitPost, false)
} else {
var xnewUser = doc.createTextNode(
"Hi, it looks like you don't have a microblog, " +
' would you like to create one? '
)
var xcreateNewMB = doc.createElement('input')
xcreateNewMB.type = 'button'
xcreateNewMB.value = 'Create a new Microblog'
xcreateNewMB.addEventListener('click', lsCreateNewMB, false)
xupdateContainer.appendChild(xnewUser)
xupdateContainer.appendChild(xcreateNewMB)
}
headerContainer.appendChild(xupdateContainer)
var subheaderContainer = doc.createElement('div')
subheaderContainer.className = 'subheader-container'
// user header
// this.creator
var creators = kb.each(s, FOAF('holdsAccount'))
for (var c in creators) {
if (
kb.whether(creators[c], RDF('type'), SIOC('User')) &&
kb.whether(
kb.any(creators[c], SIOC('creator_of')),
RDF('type'),
SIOCt('Microblog')
)
) {
var creator = creators[c]
// var mb = kb.sym(creator.uri.split("#")[0]);
// UI.store.fetcher.refresh(mb);
break
// TODO add support for more than one microblog in same foaf
}
}
if (creator) {
this.creator = mb.getUser(creator)
// ---display avatar, if available ---
if (this.creator.avatar !== '') {
var avatar = doc.createElement('img')
avatar.src = this.creator.avatar.uri
subheaderContainer.appendChild(avatar)
}
// ---generate name ---
var userName = doc.createElement('h1')
userName.className = 'fn'
userName.appendChild(
doc.createTextNode(this.creator.name + ' (' + this.creator.id + ')')
)
subheaderContainer.appendChild(userName)
// ---display follow button---
if (!this.thisIsMe && mb.getMyURI()) {
var xfollowButton = doc.createElement('input')
xfollowButton.setAttribute('type', 'button')
const followButtonLabel = this.Ifollow ? 'Unfollow ' : 'Follow '
xfollowButton.value = followButtonLabel + this.creator.name
xfollowButton.addEventListener('click', lsFollowUser, false)
subheaderContainer.appendChild(xfollowButton)
}
// user header end
// header tabs
var xtabsList = this.Tab.getTabView()
headerContainer.appendChild(subheaderContainer)
headerContainer.appendChild(xtabsList)
}
return headerContainer
}
Pane.prototype.generatePost = function (post, _me) {
/*
generatePost - Creates and formats microblog posts
post - symbol of the uri the post in question
*/
var that = this
var viewPost = function (uris) {
const xviewReply = that.xviewReply
for (let i = 0; i < xviewReply.childNodes.length; i++) {
xviewReply.removeChild(xviewReply.childNodes[0])
}
var xcloseContainer = doc.createElement('li')
xcloseContainer.className = 'closeContainer'
var xcloseButton = doc.createElement('span')
xcloseButton.innerHTML = '×'
xcloseButton.className = 'closeButton'
xcloseContainer.appendChild(xcloseButton)
xviewReply.appendChild(xcloseContainer)
for (var uri in uris) {
xviewReply.appendChild(
that.generatePost(kb.sym(uris[uri]), this.thisIsMe, 'view')
)
}
xviewReply.className = 'replyView-active'
that.microblogPane.appendChild(xviewReply)
}
// container for post
var xpost = doc.createElement('li')
xpost.className = 'post'
xpost.setAttribute('id', String(post.uri).split('#')[1])
var Post = mb.getPost(post)
// username text
// var uname = kb.any(kb.any(post, SIOC('has_creator')), SIOC('id'))
var uholdsaccount = kb.any(
undefined,
FOAF('holdsAccount'),
kb.any(post, SIOC('has_creator'))
)
var xuname = doc.createElement('a')
xuname.href = uholdsaccount.uri
xuname.className = 'userLink'
var xunameText = doc.createTextNode(mb.getUser(Post.creator).id)
xuname.appendChild(xunameText)
// user image
var xuavatar = doc.createElement('img')
xuavatar.src = mb.getUser(Post.creator).avatar.uri
xuavatar.className = 'postAvatar'
// post content
var xpostContent = doc.createElement('blockquote')
var postText = Post.message
// post date
var xpostLink = doc.createElement('a')
xpostLink.className = 'postLink'
xpostLink.addEventListener(
'click',
function () {
viewPost([post.uri])
},
false
)
xpostLink.id = 'post_' + String(post.uri).split('#')[1]
xpostLink.setAttribute('content', post.uri)
xpostLink.setAttribute('property', 'permalink')
const postLink = doc.createTextNode(
Post.date ? Post.date : 'post date unknown'
)
xpostLink.appendChild(postLink)
// LINK META DATA (MENTIONS, HASHTAGS, GROUPS)
var mentions = kb.each(post, SIOC('topic'))
const tags = {}
for (var mention in mentions) {
sf.lookUpThing(mentions[mention])
const id = kb.any(mentions[mention], SIOC('id'))
tags['@' + id] = mentions[mention]
}
var postTags = postText.match(/(@|#|!)\w+/g)
var postFunction = function () {
const p = postTags.pop()
return tags[p]
? kb.any(undefined, FOAF('holdsAccount'), tags[p]).uri
: p
}
for (var t in tags) {
var person = t.replace(/@/, '')
var replacePerson = RegExp('(@|!|#)(' + person + ')')
postText = postText.replace(
replacePerson,
'$1<a href="' + postFunction() + '">$2</a>'
)
}
xpostContent.innerHTML = postText
// in reply to logic
// This has the potential to support a post that replies to many messages.
var inReplyTo = kb.each(post, SIOC('reply_of'))
var xreplyTo = doc.createElement('span')
for (var reply in inReplyTo) {
var theReply
theReply = String(inReplyTo[reply]).replace(/<|>/g, '')
var genReplyTo = function () {
var reply = doc.createElement('a')
reply.innerHTML = ', <b>in reply to</b>'
reply.addEventListener(
'click',
function () {
viewPost([post.uri, theReply])
return false
},
false
)
return reply
}
xreplyTo.appendChild(genReplyTo())
}
// END LINK META DATA
// add the reply to and delete buttons to the interface
var mbReplyTo = function () {
var id = mb.getUser(Post.creator).id
var xupdateStatus = doc.getElementById('xupdateStatus')
var xinReplyToContainer = doc.getElementById('xinReplyToContainer')
var xupdateSubmit = doc.getElementById('xupdateSubmit')
xupdateStatus.value = '@' + id + ' '
xupdateStatus.focus()
xinReplyToContainer.value = post.uri
xupdateSubmit.value = 'Reply'
}
var mbDeletePost = function (evt) {
var lsconfirmNo = function () {
doc
.getElementById('notify-container')
.removeChild(xconfirmDeletionDialog)
evt.target.disabled = false
}
var lsconfirmYes = function () {
reallyDelete()
doc
.getElementById('notify-container')
.removeChild(xconfirmDeletionDialog)
}
evt.target.disabled = true
var xconfirmDeletionDialog = doc.createElement('li')
xconfirmDeletionDialog.className = 'notify conf'
xconfirmDeletionDialog.innerHTML +=
'<p>Are you sure you want to delete this post?</p>'
xconfirmDeletionDialog.addEventListener(
'keyup',
function (evt) {
if (evt.keyCode === 27) {
lsconfirmNo()
}
},
false
)
var confirmyes = doc.createElement('input')
confirmyes.type = 'button'
confirmyes.className = 'confirm'
confirmyes.value = 'Delete'
confirmyes.addEventListener('click', lsconfirmYes, false)
var confirmno = doc.createElement('input')
confirmno.type = 'button'
confirmno.className = 'confirm'
confirmno.value = 'Cancel'
confirmno.addEventListener('click', lsconfirmNo, false)
xconfirmDeletionDialog.appendChild(confirmno)
xconfirmDeletionDialog.appendChild(confirmyes)
doc
.getElementById('notify-container')
.appendChild(xconfirmDeletionDialog)
confirmno.focus()
var reallyDelete = function () {
// callback after deletion
var mbconfirmDeletePost = function (a, success) {
if (success) {
that.notify('Post deleted.')
// update the ui to reflect model changes.
var deleteThisNode = evt.target.parentNode
deleteThisNode.parentNode.removeChild(deleteThisNode)
kb.removeMany(deleteMe)
} else {
that.notify('Oops, there was a problem, please try again')
evt.target.disabled = true
}
}
// delete references to post
var deleteContainerOf = function (a, success) {
if (success) {
var deleteContainer = kb.statementsMatching(
undefined,
SIOC('container_of'),
kb.sym(
doc
.getElementById('post_' + evt.target.parentNode.id)
.getAttribute('content')
)
)
sparqlUpdater.batch_delete_statement(
deleteContainer,
mbconfirmDeletePost
)
} else {
that.notify('Oops, there was a problem, please try again')
evt.target.disabled = false
}
}
// delete attributes of post
evt.target.disabled = true
const deleteMe = kb.statementsMatching(
kb.sym(
doc
.getElementById('post_' + evt.target.parentNode.id)
.getAttribute('content')
)
)
sparqlUpdater.batch_delete_statement(deleteMe, deleteContainerOf)
}
}
if (mb.getMyURI()) {
// If the microblog in question does not belong to the user,
// display the delete post and reply to post buttons.
var themaker = kb.any(post, SIOC('has_creator'))
if (mb.getMyURI() !== themaker.uri) {
var xreplyButton = doc.createElement('input')
xreplyButton.type = 'button'
xreplyButton.value = 'reply'
xreplyButton.className = 'reply'
xreplyButton.addEventListener('click', mbReplyTo, false)
} else {
var xdeleteButton = doc.createElement('input')
xdeleteButton.type = 'button'
xdeleteButton.value = 'Delete'
xdeleteButton.className = 'reply'
xdeleteButton.addEventListener('click', mbDeletePost, false)
}
}
var mbFavorite = function (evt) {
var nid = evt.target.parentNode.id
var favpost = doc.getElementById('post_' + nid).getAttribute('content')
xfavorite.className += ' ing'
var cbFavorite = function (a, success, _c, _d) {
if (success) {
xfavorite.className =
xfavorite.className.split(' ')[1] === 'ed'
? 'favorit'
: 'favorit ed'
}
}
if (!myFavorites.favorited(favpost)) {
myFavorites.add(favpost, cbFavorite)
} else {
myFavorites.remove(favpost, cbFavorite)
}
}
var xfavorite = doc.createElement('a')
xfavorite.innerHTML = '★'
xfavorite.addEventListener('click', mbFavorite, false)
if (myFavorites.favorited(post.uri)) {
xfavorite.className = 'favorit ed'
} else {
xfavorite.className = 'favorit'
}
// build
xpost.appendChild(xuavatar)
xpost.appendChild(xpostContent)
if (mb.getMyURI()) {
xpost.appendChild(xfavorite)
if (mb.getMyURI() !== themaker.uri) {
xpost.appendChild(xreplyButton)
} else {
xpost.appendChild(xdeleteButton)
}
}
xpost.appendChild(xuname)
xpost.appendChild(xpostLink)
if (inReplyTo !== '') {
xpost.appendChild(xreplyTo)
}
return xpost
}
Pane.prototype.generatePostList = function (gmbPosts) {
/*
generatePostList - Generate the posts and
display their results on the interface.
*/
var postList = doc.createElement('ul')
var postlist = {}
var datelist = []
for (var post in gmbPosts) {
var postDate = kb.any(gmbPosts[post], terms('created'))
if (postDate) {
datelist.push(postDate)
postlist[postDate] = this.generatePost(gmbPosts[post], this.thisIsMe)
}
}
datelist.sort().reverse()
for (var d in datelist) {
postList.appendChild(postlist[datelist[d]])
}
return postList
}
Pane.prototype.followsView = function () {
var getFollowed = function (user) {
var userid = kb.any(user, SIOC('id'))
var follow = doc.createElement('li')
follow.className = 'follow'
userid = userid || user.uri
var fol = kb.any(undefined, FOAF('holdsAccount'), user)
fol = fol ? fol.uri : user.uri
follow.innerHTML = '<a href="' + fol + '">' + userid + '</a>'
return follow
}
var xfollows = doc.createElement('div')
xfollows.id = 'xfollows'
xfollows.className = 'followlist-container view-container'
if (this.creator && kb.whether(this.creator.sym, SIOC('follows'))) {
var creatorFollows = kb.each(this.creator.sym, SIOC('follows'))
var xfollowsList = doc.createElement('ul')
for (var thisPerson in creatorFollows) {
xfollowsList.appendChild(getFollowed(creatorFollows[thisPerson]))
}
xfollows.appendChild(xfollowsList)
}
this.Tab.create('tab-follows', 'Follows', xfollows, false)
return xfollows
}
Pane.prototype.streamView = function (s, doc) {
var postContainer = doc.createElement('div')
postContainer.id = 'postContainer'
postContainer.className = 'post-container view-container active'
var mbPosts = []
if (kb.whether(s, FOAF('name')) && kb.whether(s, FOAF('holdsAccount'))) {
sf.lookUpThing(kb.any(s, FOAF('holdsAccount')))
var follows = kb.each(kb.any(s, FOAF('holdsAccount')), SIOC('follows'))
for (var f in follows) {
sf.lookUpThing(follows[f])
// look up people user follows
var smicroblogs = kb.each(follows[f], SIOC('creator_of'))
// get the follows microblogs
for (var smb in smicroblogs) {
sf.lookUpThing(smicroblogs[smb])
if (kb.whether(smicroblogs[smb], SIOC('topic'), follows[f])) {
continue
} else {
mbPosts = mbPosts.concat(
kb.each(smicroblogs[smb], SIOC('container_of'))
)
}
}
}
}
if (mbPosts.length > 0) {
var postList = this.generatePostList(mbPosts)
// generate stream
postList.id = 'postList'
postList.className = 'postList'
postContainer.appendChild(postList)
}
this.Tab.create('tab-stream', 'By Follows', postContainer, true)
return postContainer
}
Pane.prototype.notificationsView = function (s, doc) {
var postNotificationContainer = doc.createElement('div')
postNotificationContainer.id = 'postNotificationContainer'
postNotificationContainer.className =
'notification-container view-container'
var postMentionContainer = doc.createElement('div')
postMentionContainer.id = 'postMentionContainer'
postMentionContainer.className = 'mention-container view-container'
var mbnPosts = []
var mbmPosts = []
// get mbs that I am the creator of.
var theUser = kb.any(s, FOAF('holdsAccount'))
var user = kb.any(theUser, SIOC('id'))
var microblogs = kb.each(theUser, SIOC('creator_of'))
for (var mbm in microblogs) {
sf.lookUpThing(microblogs[mbm])
if (kb.whether(microblogs[mbm], SIOC('topic'), theUser)) {
mbmPosts = mbmPosts.concat(
kb.each(microblogs[mbm], SIOC('container_of'))
)
} else {
if (kb.whether(microblogs[mbm], RDF('type'), SIOCt('Microblog'))) {
mbnPosts = mbnPosts.concat(
kb.each(microblogs[mbm], SIOC('container_of'))
)
}
}
}
var postNotificationList = this.generatePostList(mbnPosts)
postNotificationList.id = 'postNotificationList'
postNotificationList.className = 'postList'
postNotificationContainer.appendChild(postNotificationList)
var postMentionList = this.generatePostList(mbmPosts)
postMentionList.id = 'postMentionList'
postMentionList.className = 'postList'
postMentionContainer.appendChild(postMentionList)
this.postMentionContainer = postMentionContainer
this.postNotificationContainer = postNotificationContainer
this.Tab.create(
'tab-by-user',
'By ' + user,
postNotificationContainer,
false
)
this.Tab.create('tab-at-user', '@' + user, postMentionContainer, false)
}
Pane.prototype.build = function () {
var microblogPane = this.microblogPane
this.headerContainer = this.header(s, doc)
this.postContainer = this.streamView(s, doc)
this.notificationsView(s, doc)
this.xfollows = this.followsView()
microblogPane.className = 'ppane'
microblogPane.appendChild(this.xviewReply)
microblogPane.appendChild(this.xnotify)
microblogPane.appendChild(this.headerContainer)
if (this.xfollows !== undefined) {
microblogPane.appendChild(this.xfollows)
}
microblogPane.appendChild(this.postContainer)
microblogPane.appendChild(this.postNotificationContainer)
microblogPane.appendChild(this.postMentionContainer)
}
var microblogpane = doc.createElement('div')
// var getusersfollows = function(uri){
// var follows = new Object();
// var followsa = {follows:0, matches:0};
// var accounts = kb.each(s, FOAF("holdsAccount"));
// //get all of the accounts that a person holds
// for (var acct in accounts){
// var account = accounts[acct].uri;
// var act = kb.each(kb.sym(account),SIOC("follows"));
// for (var a in act){
// var thisuri = act[a].uri.split("#")[0];
// if (!follows[thisuri]){followsa.follows+=1;}
// follows[thisuri] =true;
// }
// }
//
// var buildPaneUI = function(uri){
// followsa.matches = (follows[uri]) ? followsa.matches+1: followsa.matches;
// console.log(follows.toSource());
// if(followsa.follows == followsa.matches ){
var ppane = new Pane(s, doc, microblogpane)
ppane.build()
// return false;
// }
// else{
// return true;
// }
// }
// sf.addCallback('done',buildPaneUI);
// sf.addCallback('fail',buildPaneUI);
// //fetch each of the followers
// for (var f in follows){
// sf.refresh(kb.sym(f));
// }
// }(s);
return microblogpane
}
}