Show the timeline
This commit is contained in:
parent
7e04869453
commit
cb5977f910
16
apmail.css
16
apmail.css
|
@ -40,6 +40,10 @@ nav {
|
|||
padding-bottom: 0.5em;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.page-label:hover {
|
||||
background-color: hsl(240, 10%, 75%);
|
||||
}
|
||||
|
||||
.error {
|
||||
|
@ -113,6 +117,12 @@ main {
|
|||
align-items: stretch;
|
||||
}
|
||||
|
||||
.timeline-prev-next {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
/* Other */
|
||||
a:link {
|
||||
color: hsl(220, 100%, 40%);
|
||||
|
@ -151,7 +161,7 @@ li.actor-display {
|
|||
background-color: hsl(240, 10%, 75%);
|
||||
}
|
||||
|
||||
article.activity {
|
||||
section.timeline-activity {
|
||||
display: block;
|
||||
border-style: solid;
|
||||
border-width: thin;
|
||||
|
@ -159,6 +169,10 @@ article.activity {
|
|||
padding: 0.5em;
|
||||
margin-top: 0.1em;
|
||||
margin-bottom: 0.1em;
|
||||
cursor: pointer;
|
||||
}
|
||||
section.timeline-activity:hover {
|
||||
background-color: hsl(240, 10%, 75%);
|
||||
}
|
||||
|
||||
section.actor-display {
|
||||
|
|
12
index.html
12
index.html
|
@ -31,7 +31,17 @@
|
|||
<!-- Timelines -->
|
||||
<section id="timeline" style="display:none;">
|
||||
<section id="timeline-error" class="error"></section>
|
||||
<section id="timeline-data" class="timeline"></section>
|
||||
<section class="timeline">
|
||||
<section class="timeline-prev-next">
|
||||
<button id="timeline-prev-top" onclick="UI.prevTimeline();">Previous</button>
|
||||
<button id="timeline-next-top" onclick="UI.nextTimeline();">Next</button>
|
||||
</section>
|
||||
<section id="timeline-data"></section>
|
||||
<section class="timeline-prev-next">
|
||||
<button id="timeline-prev-bottom" onclick="UI.prevTimeline();">Previous</button>
|
||||
<button id="timeline-next-bottom" onclick="UI.nextTimeline();">Next</button>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<!-- Content pages -->
|
||||
<section id="main-content">
|
||||
|
|
4
main.js
4
main.js
|
@ -3,8 +3,8 @@ const { app, BrowserWindow } = require('electron')
|
|||
function createWindow () {
|
||||
// Create the browser window.
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
width: 1024,
|
||||
height: 768,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
|
|
122
render.js
122
render.js
|
@ -10,7 +10,7 @@ const Elem = function(id) {
|
|||
|
||||
// Icon list
|
||||
const Icons = {
|
||||
'unknown-user': "/img/unknown-user.svg"
|
||||
'unknown-user': "img/unknown-user.svg"
|
||||
}
|
||||
|
||||
// To render elements that cannot be present in index.html from a model element
|
||||
|
@ -50,6 +50,40 @@ const Render = {
|
|||
}
|
||||
str_data = str_data.replace(/[&<>"']/g, x => replace_map[x])
|
||||
return str_data
|
||||
},
|
||||
// Activity in timeline
|
||||
// By type of activity
|
||||
timelineActivity: {
|
||||
'Create': function(activity) {
|
||||
var display = '<section class="timeline-activity" onclick="UI.showActivity(\'' + activity.id + '\');">'
|
||||
+ 'New ' + activity.object.type + '<br/>'
|
||||
+ '<strong>' + activity.actor.displayName() + '</strong><br/>'
|
||||
if (activity.object.summary) {
|
||||
display = display + '<em>' + activity.object.summary + '</em>'
|
||||
} else {
|
||||
display = display + '<em>No summary</em>'
|
||||
}
|
||||
display = display + '</section>'
|
||||
return display
|
||||
},
|
||||
'Like': function(activity) {
|
||||
return '<section class="timeline-activity" onclick="UI.showActivity(\'' + activity.id + '\');">'
|
||||
+ 'Like <br/>'
|
||||
+ '<strong>' + activity.actor.displayName() + '</strong>'
|
||||
+ '</section>'
|
||||
},
|
||||
'Announce': function(activity) {
|
||||
return '<section class="timeline-activity" onclick="UI.showActivity(\'' + activity.id + '\');">'
|
||||
+ 'Announce <br/>'
|
||||
+ '<strong>' + activity.actor.displayName() + '</strong>'
|
||||
+ '</section>'
|
||||
},
|
||||
'Delete': function(activity) {
|
||||
return '<section class="timeline-activity" onclick="UI.showActivity(\'' + activity.id + '\');">'
|
||||
+ 'Delete <br/>'
|
||||
+ '<strong>' + activity.actor.displayName() + '</strong>'
|
||||
+ '</section>'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,6 +94,7 @@ const UI = {
|
|||
current_context: 'my-inbox', // By default, show the inbox
|
||||
is_connected: false, // Indicate if the user is connected
|
||||
other_actor: new Actor(), // Other actor to display
|
||||
timeline: new Timeline(), // Collection of activities to display in the central column
|
||||
// Contextual methods
|
||||
refresh_context: {
|
||||
'send-message': function() {
|
||||
|
@ -84,7 +119,7 @@ const UI = {
|
|||
'my-outbox': function() {
|
||||
UI.updateNav('outbox-selector')
|
||||
if (UI.is_connected) {
|
||||
UI.showTimeline(ConnectedUser.actor.urls.inbox, ConnectedUser.tokens.user.access_token)
|
||||
UI.showTimeline(ConnectedUser.actor.urls.outbox, ConnectedUser.tokens.user.access_token)
|
||||
UI.showPage('show-profile', ConnectedUser.actor)
|
||||
} else {
|
||||
UI.showTimeline(undefined, undefined)
|
||||
|
@ -102,12 +137,13 @@ const UI = {
|
|||
},
|
||||
'other-profile': function() {
|
||||
UI.updateNav(undefined)
|
||||
UI.showPage('show-profile', UI.other_actor)
|
||||
if (UI.other_actor.urls.outbox) {
|
||||
UI.showTimeline(UI.other_actor.urls.outbox, undefined)
|
||||
} else {
|
||||
UI.displayTimelineError('Actor does not have a public outbox.')
|
||||
UI.displayContentError('Actor does not have a public outbox.')
|
||||
UI.showTimeline(undefined, undefined)
|
||||
}
|
||||
UI.showPage('show-profile', UI.other_actor)
|
||||
}
|
||||
},
|
||||
// Page refresh methods
|
||||
|
@ -211,7 +247,39 @@ const UI = {
|
|||
if (url) {
|
||||
Elem('timeline').style.display = 'block'
|
||||
Elem('timeline-data').innerHTML = 'Loading collection...'
|
||||
// TODO
|
||||
Elem('timeline-prev-top').style.display = 'none'
|
||||
Elem('timeline-prev-bottom').style.display = 'none'
|
||||
Elem('timeline-next-top').style.display = 'none'
|
||||
Elem('timeline-next-bottom').style.display = 'none'
|
||||
UI.timeline = new Timeline()
|
||||
UI.timeline.load(
|
||||
url,
|
||||
token,
|
||||
function(load_ok, failure_message) {
|
||||
if (load_ok) {
|
||||
Elem('timeline-data').innerHTML = UI.timeline.activities.map(function(activity) {
|
||||
if (Render.timelineActivity[activity.type]) {
|
||||
return Render.timelineActivity[activity.type](activity)
|
||||
} else {
|
||||
return '<section class="timeline-activity">'
|
||||
+ 'Other activity (' + activity.type + ')<br/>'
|
||||
+ '<strong>' + activity.actor.displayName() + '</strong></section>'
|
||||
}
|
||||
}).join('')
|
||||
if (UI.timeline.prev) {
|
||||
Elem('timeline-prev-top').style.display = 'block'
|
||||
Elem('timeline-prev-bottom').style.display = 'block'
|
||||
}
|
||||
if (UI.timeline.next) {
|
||||
Elem('timeline-next-top').style.display = 'block'
|
||||
Elem('timeline-next-bottom').style.display = 'block'
|
||||
}
|
||||
} else {
|
||||
UI.displayTimelineError(failure_message)
|
||||
Elem('timeline-data').innerHTML = ''
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Elem('timeline').style.display = 'none'
|
||||
}
|
||||
|
@ -331,6 +399,21 @@ const UI = {
|
|||
UI.displayContentError('Error when sending message: ' + failure_message)
|
||||
}
|
||||
})
|
||||
},
|
||||
// Timeline navigation
|
||||
nextTimeline: function() {
|
||||
if (UI.timeline.next) {
|
||||
UI.showTimeline(UI.timeline.next, UI.timeline.token)
|
||||
}
|
||||
},
|
||||
prevTimeline: function() {
|
||||
if (UI.timeline.prev) {
|
||||
UI.showTimeline(UI.timeline.prev, UI.timeline.token)
|
||||
}
|
||||
},
|
||||
// Show contents of activities
|
||||
showActivity: function(activityId) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
|
@ -397,35 +480,6 @@ const UI = {
|
|||
+ UI.renderRawData(activity.raw)
|
||||
+ '</article>'
|
||||
}
|
||||
},
|
||||
showTimeline: function(id, token, url) {
|
||||
var timeline = new Timeline()
|
||||
timeline.load(url, token, function(load_ok, failure_message) {
|
||||
if (load_ok) {
|
||||
var content = timeline.activities.map(
|
||||
function(activity) {
|
||||
if (UI.renderActivity[activity.type]) {
|
||||
return UI.renderActivity[activity.type](activity)
|
||||
} else {
|
||||
return '<article class="activity">'
|
||||
+ 'Other activity (' + activity.type + ').'
|
||||
+ UI.renderRawActivity(activity)
|
||||
+ '</article>'
|
||||
}
|
||||
}).join('')
|
||||
content = content + '<section class="prev-next">'
|
||||
if (timeline.prev) {
|
||||
content = content + '<button onclick="UI.showTimeline(\'' + id + '\',' + (token ? '\'' + token + '\'' : 'undefined') + ',\'' + timeline.prev + '\')">Prev</button>'
|
||||
}
|
||||
if (timeline.next) {
|
||||
content = content + '<button onclick="UI.showTimeline(\'' + id + '\',' + (token ? '\'' + token + '\'' : 'undefined') + ',\'' + timeline.next + '\')">Next</button>'
|
||||
}
|
||||
content = content + '</section>'
|
||||
Elem(id).innerHTML = content
|
||||
} else {
|
||||
Elem(id + '-error').innerText = failure_message
|
||||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ const {KnownActors} = require('./known-actors.js')
|
|||
// Activity class
|
||||
const Activity = function(raw_activity) {
|
||||
this.raw = raw_activity
|
||||
this.id = raw_activity.id
|
||||
this.type = raw_activity.type
|
||||
this.published = raw_activity.published ? new Date(raw_activity.published) : undefined
|
||||
this.object = raw_activity.object
|
||||
|
|
|
@ -4,8 +4,19 @@ const {Activity} = require('./activity.js')
|
|||
// Represent a collection of activities
|
||||
var Timeline = function() {}
|
||||
Timeline.prototype = {
|
||||
// attributes
|
||||
// List of activities
|
||||
activities: [],
|
||||
// Link to previous page
|
||||
prev: undefined,
|
||||
// Link to next page
|
||||
next: undefined,
|
||||
// Token used when loading -- for loading prev/next within the same context
|
||||
token: undefined,
|
||||
//
|
||||
load: function(url, token, callback) {
|
||||
var request = new XMLHttpRequest()
|
||||
this.token = token
|
||||
const request = new XMLHttpRequest()
|
||||
request.onreadystatechange = function() {
|
||||
if (request.readyState == 4 && request.status == 200) {
|
||||
var answer = JSON.parse(request.responseText)
|
||||
|
@ -40,9 +51,9 @@ Timeline.prototype = {
|
|||
},
|
||||
parseActivities: function(raw_activities, callback) {
|
||||
// Get the next activity
|
||||
var raw_act = raw_activities.shift()
|
||||
const raw_act = raw_activities.shift()
|
||||
if (raw_act) {
|
||||
var act = new Activity(raw_act)
|
||||
const act = new Activity(raw_act)
|
||||
act.loadActors(
|
||||
function(load_ok, failure_message) {
|
||||
if (load_ok) {
|
||||
|
|
Loading…
Reference in New Issue