UNPKG

solid-panes

Version:

Solid-compatible Panes: applets and views for the mashlib and databrowser

1,400 lines (1,366 loc) • 48.5 kB
/* 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 = '&#215;' 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 = '&#9733;' 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 } }