Last active
December 18, 2015 07:30
-
-
Save alchen/3ca9d24bf26ba1b1bad2 to your computer and use it in GitHub Desktop.
Partial mithril.js implementation of timeline display for alchen/DTCP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var m = require('./mithril'); | |
var twitterText = require('twitter-text'); | |
var newTweet = {}; | |
newTweet.Tweet = function Tweet(status) { | |
status = status || ''; | |
this.status = m.prop(status); | |
this.formattedStatus = m.prop(twitterText.autoLink(status)); | |
this.remainingLength = m.prop( | |
status ? 140 - twitterText.getTweetLength(status) : 140 | |
); | |
}; | |
newTweet.Tweet.prototype.setStatus = function setStatus(status) { | |
this.status(status); | |
this.formattedStatus(twitterText.autoLink(status)); | |
this.remainingLength( | |
status ? 140 - twitterText.getTweetLength(status) : 140 | |
); | |
}; | |
newTweet.Tweet.prototype.isValidTweetText = function setStatus() { | |
return twitterText.isValidTweetText(this.status()); | |
}; | |
newTweet.vm = (function () { | |
var vm = {}; | |
vm.init = function () { | |
//a slot to store the name of a new todo before it is created | |
vm.tweet = new newTweet.Tweet(); | |
//adds a todo to the list, and clears the description field for user convenience | |
vm.format = function (status) { | |
newTweet.vm.tweet.setStatus(status); | |
}; | |
vm.updateStatus = function () { | |
console.log('papa'); | |
}; | |
}; | |
return vm; | |
}()); | |
//the controller defines what part of the model is relevant for the current page | |
//in our case, there's only one view-model that handles everything | |
newTweet.controller = function() { | |
newTweet.vm.init(); | |
}; | |
//here's the view | |
newTweet.view = function() { | |
return m('html', [ | |
m('head', [ | |
m('title', 'testbed'), | |
m('link', {rel: 'stylesheet', href: 'css/normalize.css'}), | |
m('link', {rel: 'stylesheet', href: 'css/custom.css'}), | |
]), | |
m('body', [ | |
m('div', {class: 'newtweet'}, [ | |
m('section', {class: 'newtweettext'}, [ | |
m('section', { | |
class: 'newrawtweet', | |
contenteditable: 'true', | |
autofocus: 'true', | |
oninput: m.withAttr('innerHTML', newTweet.vm.format) | |
}), | |
m('section', { | |
class: 'newformattedtweet', | |
innerHTML: newTweet.vm.tweet.formattedStatus() | |
}) | |
]), | |
m('section', {class: 'newtweetmeta'}, [ | |
m('span', {class: 'remaining'}, newTweet.vm.tweet.remainingLength()), | |
m('button', newTweet.vm.tweet.isValidTweetText() ? { | |
class: 'newtweetbutton activenewtweetbutton', | |
onclick: newTweet.vm.updateStatus | |
} : { | |
class: 'newtweetbutton' | |
}, 'Tweet') | |
]) | |
]) | |
]) | |
]); | |
}; | |
//initialize the application | |
m.mount(document, {controller: newTweet.controller, view: newTweet.view}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var _ = require('lodash'); | |
var moment = require('moment'); | |
var m = require('./lib/mithril'); | |
var Tweet = require('./models/tweet'); | |
var TweetComponent = require('./components/tweet'); | |
var vm = (function () { | |
var vm = {}; | |
vm.init = function () { | |
var tweets = require('./tweets.json'); | |
vm.timeline = _.map(tweets, function (tweet) { | |
return new Tweet(tweet); | |
}); | |
vm.now = m.prop(moment()); | |
setInterval(function () { | |
vm.now(moment()); | |
m.redraw(); | |
}, 60 * 1000); | |
}; | |
return vm; | |
}()); | |
var controller = function() { | |
vm.init(); | |
}; | |
var view = function() { | |
return m('html', [ | |
m('head', [ | |
m('title', 'testbed'), | |
m('link', {rel: 'stylesheet', href: 'css/normalize.css'}), | |
m('link', {rel: 'stylesheet', href: 'css/iconic-glyphs.css'}), | |
m('link', {rel: 'stylesheet', href: 'css/custom.css'}), | |
]), | |
// m('body', vm.timeline) | |
m('body', [ | |
m('ul', {class: 'tweets timeline home activetimeline'}, _.map(vm.timeline, function (tweet) { | |
return m.component(TweetComponent, { | |
tweet: tweet, | |
now: vm.now | |
}); | |
}) | |
) | |
]) | |
]); | |
}; | |
m.mount(document, {controller: controller, view: view}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
// var ipc = require('ipc'); | |
var _ = require('lodash'); | |
var m = require('../lib/mithril'); | |
var moment = require('moment'); | |
var twitterText = require('twitter-text'); | |
var Tweet = function (tweet) { | |
var options = { | |
usernameIncludeSymbol: true | |
}; | |
// Accommodate different type of events | |
this.type = m.prop('tweet'); | |
// Tweet status | |
this.id = m.prop(tweet.id_str); | |
this.rawStatus = m.prop(tweet.text); | |
this.formattedStatus = m.prop( | |
tweet.entities ? twitterText.autoLinkWithJSON(tweet.text, tweet.entities, options) | |
: twitterText.autoLink(tweet.text, options) | |
); | |
this.inReplyTo = m.prop(tweet.in_reply_to_status_id_str); | |
this.isRetweeted = m.prop(tweet.retweeted); | |
this.isFavorited = m.prop(tweet.favorited); | |
this.createdAt = m.prop(moment(new Date(tweet.created_at))); | |
// User info | |
this.screenName = m.prop(tweet.user.screen_name); | |
this.name = m.prop(tweet.user.name); | |
this.userId = m.prop(tweet.user.id_str); | |
this.icon = m.prop(tweet.user.profile_image_url_https); | |
this.protected = m.prop(tweet.user.protected); | |
this.mentions = m.prop(tweet.entities ? | |
_.map(tweet.entities.user_mentions, function (k) { | |
return k.screen_name; | |
}) : [] | |
); | |
this.media = m.prop(tweet.extended_entities ? | |
_.map(tweet.extended_entities.media, function (k) { | |
return k.media_url_https; | |
}) : [] | |
); | |
if (tweet.retweeted_status) { | |
this.retweet = m.prop(new Tweet(tweet.retweeted_status)); | |
} else { | |
this.retweet = m.prop(); | |
} | |
// Quote info | |
if (tweet.quoted_status) { | |
this.quote = m.prop(new Tweet(tweet.quoted_status)); | |
} else { | |
this.quote = m.prop(); | |
} | |
}; | |
Tweet.prototype.showName = function () { | |
var self = this.retweet() || this; | |
return self.name(); | |
}; | |
Tweet.prototype.showScreenName = function () { | |
var self = this.retweet() || this; | |
return self.screenName(); | |
}; | |
Tweet.prototype.showStatus = function () { | |
var self = this.retweet() || this; | |
return self.formattedStatus(); | |
}; | |
Tweet.prototype.isUserProtected = function () { | |
var self = this.retweet() || this.quote() || this; | |
return self.protected(); | |
}; | |
Tweet.prototype.reply = function (exclude) { | |
var self = this.retweet() || this; | |
var mentions = _.filter(self.mentions(), function (k) { | |
return k !== exclude; | |
}); | |
mentions.unshift(self.screenName); | |
// ipc.send('reply', self.inReplyTo(), mentions); | |
}; | |
module.exports = Tweet; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var _ = require('lodash'); | |
var moment = require('moment'); | |
var m = require('../lib/mithril'); | |
function displayNone() { | |
this.style.visibility = 'hidden'; | |
} | |
function timeFrom(time, now) { | |
var duration = moment.duration(now.diff(moment(new Date(time)))); | |
var sign = null; | |
if ((sign = duration.as('second')) <= 5) { | |
return 'now'; | |
} else if (sign < 60) { | |
return Math.round(sign) + 's'; | |
} else if ((sign = duration.as('minute')) < 60) { | |
return Math.round(sign) + 'm'; | |
} else if ((sign = duration.as('hour')) < 24) { | |
return Math.round(sign) + 'h'; | |
} else if ((sign = duration.as('day')) <= 365) { | |
return Math.round(sign) + 'd'; | |
} else { | |
sign = duration.as('year'); | |
return Math.round(sign) + 'y'; | |
} | |
} | |
function extendedEntities(media) { | |
var length = media.length; | |
var width = 'width: calc(100% / ' + length + ');'; | |
return m('section', {class: 'tweetmedia'}, [ | |
m('ul', {class: 'tweetimagelist'}, _.map(media, function (mediaUrl) { | |
return m('li', {class: 'tweetimagebox', style: width}, [ | |
m('a', { | |
class: 'tweetimagelink', | |
target: '_blank', | |
style: 'background-image:url(\'' + mediaUrl + ':small\');', | |
href: mediaUrl | |
}, mediaUrl) | |
]); | |
})) | |
]); | |
} | |
var TweetComponent = { | |
controller: function (data) { | |
return data; | |
}, | |
view: function (ctrl) { | |
var tweet = ctrl.tweet; | |
return m('li', {class: 'tweet'}, [ | |
m('section', {class: 'tweetleft'}, [ | |
m('img', { | |
class: 'tweeticon', | |
src: tweet.icon(), | |
onerror: displayNone | |
}) | |
]), | |
m('section', {class: 'tweetright'}, [ | |
m('section', {class: 'tweetmeta'}, [ | |
m('section', {class: 'tweetmetaleft'}, [ | |
m('span', {class: 'name'}, tweet.showName()), | |
m.trust(' '), | |
m('span', {class: 'screenname'}, tweet.showScreenName()) | |
]), | |
m('section', {class: 'tweetmetaright'}, [ | |
m('span', {class: 'tweettime'}, timeFrom(tweet.createdAt(), ctrl.now())), | |
m('ul', {class: 'tweetactions'}, tweet.isUserProtected() ? [ | |
m('li', {class: 'tweetaction'}, [ | |
m('button', {class: 'tweetbutton'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'share' | |
}) | |
]) | |
]), | |
m('li', {class: 'tweetaction'}, [ | |
m('button', {class: 'tweetbutton disabledbutton'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'loop-circular' | |
}) | |
]) | |
]), | |
m('li', {class: 'tweetaction'}, [ | |
m('button', {class: 'tweetbutton disabledbutton'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'double-quote-serif-left' | |
}) | |
]) | |
]), | |
m('li', {class: 'tweetaction'}, [ | |
m('button', {class: 'tweetbutton'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'star' | |
}) | |
]) | |
]) | |
] : [ | |
m('li', {class: 'tweetaction'}, [ | |
m('button', {class: 'tweetbutton'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'share' | |
}) | |
]) | |
]), | |
m('li', {class: 'tweetaction'}, [ | |
m('button', {class: 'tweetbutton'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'loop-circular' | |
}) | |
]) | |
]), | |
m('li', {class: 'tweetaction'}, [ | |
m('button', {class: 'tweetbutton'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'double-quote-serif-left' | |
}) | |
]) | |
]), | |
m('li', {class: 'tweetaction'}, [ | |
m('button', {class: 'tweetbutton'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'star' | |
}) | |
]) | |
]) | |
]) | |
]) | |
]), | |
m('section', {class: 'tweettext'}, m.trust(tweet.showStatus())), | |
tweet.retweet() ? m('section', {class: 'tweetretweet'}, [ | |
m('span', { | |
class: 'iconic tweetbuttonicon', | |
'data-glyph': 'loop-square' | |
}), | |
m('span', {class: 'retweetname'}, tweet.name()) | |
]) : '', | |
tweet.media().length ? extendedEntities(tweet.media()) : '', | |
tweet.quote() ? m('section', {class: 'quotedtweet'}, [ | |
m('section', {class: 'quotedmeta'}, [ | |
m('span', {class: 'name'}, tweet.quote().showName()), | |
m.trust(' '), | |
m('span', {class: 'screenname'}, tweet.quote().showScreenName()) | |
]), | |
m('section', {class: 'quotedtext'}, m.trust(tweet.quote().showStatus())), | |
tweet.quote().media().length ? extendedEntities(tweet.quote().media()) : '' | |
]) : '' | |
]), | |
]); | |
} | |
}; | |
module.exports = TweetComponent; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment