Change deeply the look of the application. Still to do: timelines/collections, activities.

This commit is contained in:
Feufochmar 2020-03-27 17:08:59 +01:00
parent 7c0d471328
commit 7e04869453
4 changed files with 483 additions and 283 deletions

View File

@ -7,31 +7,19 @@ body {
color: hsl(240, 10%, 15%);
border-color: hsl(240, 10%, 15%);
}
/* Header */
header {
padding: 0;
margin: 0;
background-color: hsl(240, 10%, 75%);
border-style: solid;
border-width: thin;
border-radius: 0.5em;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
padding-right: 1em;
text-align: center;
margin-bottom: 0.5em;
display: flex;
flex-direction: row;
justify-content: flex-start;
}
nav {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
flex-direction: column;
justify-content: flex-start;
align-items: center;
align-items: stretch;
}
.page {
@ -47,7 +35,6 @@ nav {
margin: 0;
border-style: solid;
border-width: thin;
border-radius: 0.5em 0.5em 0 0;
background-color: hsl(240, 10%, 65%);
padding-top: 0.5em;
padding-bottom: 0.5em;
@ -55,6 +42,18 @@ nav {
padding-right: 1em;
}
.error {
padding: 0;
margin: 0;
background-color: hsl(0, 40%, 85%);
border-style: solid;
border-width: thin;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
padding-right: 1em;
}
/* Main */
h1 {
padding: 0;
@ -92,27 +91,26 @@ main {
background-color: hsl(240, 10%, 85%);
border-style: solid;
border-width: thin;
border-radius: 0 0.5em 0.5em 0.5em;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
padding-right: 1em;
}
/* Footer */
footer {
.timeline {
padding: 0;
margin: 0;
background-color: hsl(240, 10%, 75%);
background-color: hsl(240, 10%, 85%);
border-style: solid;
border-width: thin;
border-radius: 0.5em;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
padding-right: 1em;
text-align: center;
margin-top: 0.5em;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
/* Other */
@ -146,7 +144,6 @@ li.actor-display {
display: inline-block;
border-style: solid;
border-width: thin;
border-radius: 0.5em;
padding: 0.1em;
margin: 0;
margin-left: 0.5em;
@ -158,7 +155,6 @@ article.activity {
display: block;
border-style: solid;
border-width: thin;
border-radius: 0.5em;
margin: 0;
padding: 0.5em;
margin-top: 0.1em;
@ -192,3 +188,7 @@ section.activity-object-field:after {
section.activity-object-content {
background-color: hsl(240, 10%, 95%);
}
#profile-display-name {
font-size: xx-large;
}

102
img/unknown-user.svg Normal file
View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="96"
height="96"
viewBox="0 0 25.399999 25.400001"
version="1.1"
id="svg8"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="unknown-user.svg">
<defs
id="defs2">
<inkscape:path-effect
effect="simplify"
id="path-effect821"
is_visible="true"
steps="1"
threshold="0.000408163"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
simplifyindividualpaths="false"
simplifyJustCoalesce="false" />
<inkscape:path-effect
effect="simplify"
id="path-effect817"
is_visible="true"
steps="1"
threshold="0.000408163"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
simplifyindividualpaths="false"
simplifyJustCoalesce="false" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4.8024336"
inkscape:cx="44.525706"
inkscape:cy="35.984974"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1049"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-271.59998)">
<rect
style="opacity:1;fill:#ececec;fill-opacity:1;stroke:#000000;stroke-width:0.5291667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect875"
width="17.118422"
height="17.118422"
x="201.45149"
y="183.49098"
transform="rotate(45)" />
<path
style="opacity:1;fill:#7b7b7b;fill-opacity:1;stroke:#000000;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 48 42.277344 A 12.285437 36.856316 0 0 0 35.714844 79.132812 A 12.285437 36.856316 0 0 0 35.742188 81.492188 L 48 93.75 L 60.246094 81.503906 A 12.285437 36.856316 0 0 0 60.285156 79.132812 A 12.285437 36.856316 0 0 0 48 42.277344 z "
transform="matrix(0.26458333,0,0,0.26458333,0,271.59998)"
id="path879" />
<circle
style="opacity:1;fill:#7b7b7b;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path877"
cx="12.7"
cy="280.03113"
r="3.6361773" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -8,95 +8,112 @@
<script src="render.js"></script>
</head>
<body onload="UI.checkConnection()">
<nav id="tab-bar" style="visibility:hidden;">
<!-- Profile page tab -->
<input type="radio" id="profile-selector" class="page" name="page" value="profile" checked onchange="UI.showPage('profile')" />
<label for="profile-selector" class="page-label" id="profile-selector-label">Profile</label>
<nav id="tab-bar">
<!-- Send page tab -->
<input type="radio" id="send-selector" class="page" name="page" value="send" checked onchange="UI.showPage('send')" />
<input type="radio" id="send-selector" class="page" name="page" value="send" checked onchange="UI.setContext('send-message')" />
<label for="send-selector" class="page-label" id="send-selector-label">Send Message</label>
<!-- Inbox tab -->
<input type="radio" id="inbox-selector" class="page" name="page" value="inbox" onchange="UI.showPage('inbox')" />
<label for="inbox-selector" class="page-label" id="inbox-selector-label">Inbox</label>
<input type="radio" id="inbox-selector" class="page" name="page" value="inbox" onchange="UI.setContext('my-inbox')" />
<label for="inbox-selector" class="page-label" id="inbox-selector-label">My Inbox</label>
<!-- Outbox tab -->
<input type="radio" id="outbox-selector" class="page" name="page" value="outbox" onchange="UI.showPage('outbox')" />
<label for="outbox-selector" class="page-label" id="outbox-selector-label">Outbox</label>
<!-- Lookup user tab -->
<input type="radio" id="lookup-selector" class="page" name="page" value="lookup" onchange="UI.showPage('lookup')" />
<label for="lookup-selector" class="page-label" id="lookup-selector-label">Lookup User</label>
<!-- Disconnection -->
<input type="radio" id="disconnect-selector" class="page" name="page" value="disconnect" onchange="UI.showPage('select-user')" />
<label for="disconnect-selector" class="page-label" id="disconnect-selector-label">Disconnection</label>
<input type="radio" id="outbox-selector" class="page" name="page" value="outbox" onchange="UI.setContext('my-outbox')" />
<label for="outbox-selector" class="page-label" id="outbox-selector-label">My Outbox</label>
<!-- Profile -->
<input type="radio" id="profile-selector" class="page" name="page" value="profile" onchange="UI.setContext('my-profile')" />
<label for="profile-selector" class="page-label" id="profile-selector-label">My Profile</label>
<!-- Lookup user box -->
<nav class="page-label">
<label for="lookup-actor" id="lookup-actor-label">Lookup Actor</label>
<input id="lookup-actor" type="text" placeholder="name@server"/>
<button onclick="UI.lookupActor()">Search</button>
</nav>
</nav>
<!-- Connection pages -->
<main id="select-user">
<h2>Connection</h2>
Indicate the account to connect to. <br/>
<input id="connect-username" type="text" placeholder="user@server" pattern=".*@.*" required /><br/>
<button onclick="UI.selectUser()">Next</button>
<section id="select-user-error"></section>
</main>
<main id="ask-password" style="display:none;">
<h2>Password</h2>
<section id="ask-password-user-info"></section>
Enter the password for this account. <br/>
<input id="connect-password" type="password" placeholder="password" /><br/>
<button onclick="UI.showPage('select-user')">Back</button>
<button onclick="UI.connectUser()">Connect</button>
<section id="ask-password-error"></section>
</main>
<!-- Profile page -->
<main id="profile" style="display:none;">
<section id="profile-info"></section>
</main>
<!-- Send message page -->
<main id="send" style="display:none;">
<h4>Audience</h4>
<label for="send-message-public-visibility">General visibility</label>
<select id="send-message-public-visibility" onchange="UI.updateSendVisibility()">
<option value="to">Public (to), displayed in local/global timelines</option>
<option value="cc">Public (cc), hidden from local/global timelines</option>
<option value="non">Not public</option>
</select><br/>
<label for="send-message-follower-visibility">Follower's visibility</label>
<select id="send-message-follower-visibility" onchange="UI.updateSendVisibility()">
<option value="to">Public (to)</option>
<option value="cc">Public (cc)</option>
<option value="non">Not sent to followers</option>
</select><br/>
<label for="send-message-to-recipient">To</label>
<ul id="send-message-to" class="recipient-list"></ul>
<input id="send-message-to-recipient" type="text" placeholder="user@instance" size="40" />
<button onclick="UI.addToRecipient()">Add</button><br/>
<label for="send-message-cc-recipient">Cc</label>
<ul id="send-message-cc" class="recipient-list"></ul>
<input id="send-message-cc-recipient" type="text" placeholder="user@instance" size="40" />
<button onclick="UI.addCcRecipient()">Add</button><br/>
<section id="send-message-recipient-error"></section>
<hr/>
<h4>Message</h4>
<input id="send-message-subject" type="text" onchange="UI.updateSendContent()" size="80" placeholder="Subject (optional)"/> <br/>
<textarea id="send-message-content" rows="20" cols="80" placeholder="What do you want to say ?" onchange="UI.updateSendContent()"></textarea> <br/>
<button onclick="UI.sendMessage()">Send</button>
<section id="send-error"></section>
</main>
<!-- Inbox page -->
<main id="inbox" style="display:none;">
<section id="inbox-messages"></section>
<section id="inbox-messages-error"></section>
</main>
<!-- Outbox page -->
<main id="outbox" style="display:none;">
<section id="outbox-messages"></section>
<section id="outbox-messages-error"></section>
</main>
<!-- Lookup page -->
<main id="lookup" style="display:none;">
<input id="lookup-user" type="text" placeholder="user@instance"/> <button onclick="UI.lookupUser()">Lookup user</button> <br/><hr/>
<section id="lookup-user-error"></section>
<section id="lookup-user-info"></section><hr/>
<section id="lookup-user-timeline"></section>
<section id="lookup-user-timeline-error"></section>
</main>
<!-- Timelines -->
<section id="timeline" style="display:none;">
<section id="timeline-error" class="error"></section>
<section id="timeline-data" class="timeline"></section>
</section>
<!-- Content pages -->
<section id="main-content">
<section id="content-error" class="error"></section>
<!-- Account selection page -->
<main id="select-user" style="display:none;">
<h2>Connection</h2>
Indicate the account to connect to. <br/>
<input id="connect-username" type="text" placeholder="name@server" pattern=".*@.*" required /><br/>
<button onclick="UI.selectUser()">Next</button>
</main>
<!-- Password page -->
<main id="ask-password" style="display:none;">
<h2>Password</h2>
<section id="ask-password-user-info">
<section class="actor-display">
<span id="ask-password-user-icon"/></span>
<p style="display:inline-block;">
<strong><span id="ask-password-user-display-name"></span></strong><br/>
<a id="ask-password-user-address"></a>
</p>
</section>
</section>
Enter the password for this account. <br/>
<input id="connect-password" type="password" placeholder="password" /><br/>
<button onclick="UI.showPage('select-user', undefined)">Back</button>
<button onclick="UI.connectUser()">Connect</button>
</main>
<!-- Profile page -->
<main id="show-profile" style="display:none;">
<section>
<span id="profile-icon"></span>
<p style="display:inline-block;">
<span id="profile-display-name"></span><br/>
<a id="profile-address"></a>
</p>
</section>
<section>
<p id="profile-summary">
</p>
</section>
<section>
<details>
<summary>Show source</summary>
<textarea rows="30" cols="120" readonly id="profile-code-source">
</textarea>
</details>
</section>
</main>
<!-- Show Message page -->
<main id="show-message" style="display:none;">
<section id="message-info"></section>
</main>
<!-- Send message page -->
<main id="send-message" style="display:none;">
<h4>Audience</h4>
<label for="send-message-public-visibility">General visibility</label>
<select id="send-message-public-visibility" onchange="UI.updateSendVisibility()">
<option value="to">Public (to), displayed in local/global timelines</option>
<option value="cc">Public (cc), hidden from local/global timelines</option>
<option value="non">Not public</option>
</select><br/>
<label for="send-message-follower-visibility">Follower's visibility</label>
<select id="send-message-follower-visibility" onchange="UI.updateSendVisibility()">
<option value="to">Public (to)</option>
<option value="cc">Public (cc)</option>
<option value="non">Not sent to followers</option>
</select><br/>
<label for="send-message-to-recipient">To</label>
<ul id="send-message-to" class="recipient-list"></ul>
<input id="send-message-to-recipient" type="text" placeholder="user@instance" size="40" />
<button onclick="UI.addToRecipient()">Add</button><br/>
<label for="send-message-cc-recipient">Cc</label>
<ul id="send-message-cc" class="recipient-list"></ul>
<input id="send-message-cc-recipient" type="text" placeholder="user@instance" size="40" />
<button onclick="UI.addCcRecipient()">Add</button><br/>
<section id="send-message-recipient-error"></section>
<h4>Message</h4>
<input id="send-message-subject" type="text" onchange="UI.updateSendContent()" size="80" placeholder="Subject (optional)"/> <br/>
<textarea id="send-message-content" rows="20" cols="80" placeholder="What do you want to say ?" onchange="UI.updateSendContent()"></textarea> <br/>
<button onclick="UI.sendMessage()">Send</button>
</main>
</section>
</body>
</html>

423
render.js
View File

@ -4,211 +4,337 @@ const {Message} = require('./src/message.js')
const {ConnectedUser} = require('./src/connected-user.js')
// For access of elements
var Elem = function(id) {
const Elem = function(id) {
return window.document.getElementById(id)
}
// UI actions
var UI = {
// Attributes
composed_message: new Message(),
// Methods
// Actor display
renderActorTag: function(actor) {
// Icon list
const Icons = {
'unknown-user': "/img/unknown-user.svg"
}
// To render elements that cannot be present in index.html from a model element
const Render = {
// Render an actor in audience fields context
audienceActor: function(actor) {
var display = '<section class="actor-display">'
if (actor.valid) {
if (actor.info.icon) {
display = display + '<img src="' + actor.info.icon + '" width="32" height="32" /> '
var icon = actor.info.icon
if (!icon) {
icon = Icons['unknown-user']
}
display = display
+ '<p style="display:inline-block;"><strong>' + actor.displayName() + '</strong> <br/>'
+ '<a href="' + actor.urls.profile + '">'
+ actor.address()
+ '</a></p>'
display = display + '<img src="' + actor.info.icon + '" width="32" height="32" /> '
+ '<p style="display:inline-block;"><strong>' + actor.displayName() + '</strong> <br/>'
+ '<a href="' + actor.urls.profile + '">'
+ actor.address()
+ '</a></p>'
} else {
display = display
+ '<p style="display:inline-block;">'
+ '<a href="' + actor.urls.profile + '">'
+ 'Other actor'
+ '</a></p>'
display = display + '<img src="' + Icons['unknown-user'] + '" width="32" height="32" /> '
+ '<p style="display:inline-block;">'
+ '<a href="' + actor.urls.profile + '">'
+ 'Other actor'
+ '</a></p>'
}
display = display + '</section>'
return display
},
// Show the page tab
showPageTab: function(is_shown) {
Elem('tab-bar').style.visibility = is_shown ? 'visible' : 'hidden'
},
// Action done when refreshing a page
refreshPage: {
'select-user': function() {
UI.showPageTab(false)
ConnectedUser.disconnect()
Elem('connect-username').value = ''
// Raw data conversion
rawData: function(rawData) {
var str_data = JSON.stringify(rawData, null, 1)
var replace_map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&#039;'
}
str_data = str_data.replace(/[&<>"']/g, x => replace_map[x])
return str_data
}
}
// UI actions
const UI = {
// Attributes
composed_message: new Message(), // Message used in composition page
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
// Contextual methods
refresh_context: {
'send-message': function() {
UI.updateNav('send-selector')
UI.showTimeline(undefined, undefined)
if (UI.is_connected) {
UI.showPage('send-message', undefined)
} else {
UI.showPage('select-user', undefined)
}
},
'ask-password': function() {
UI.showPageTab(false)
Elem('connect-password').value = ''
Elem('ask-password-user-info').innerHTML = UI.renderActorTag(ConnectedUser.actor)
'my-inbox': function() {
UI.updateNav('inbox-selector')
if (UI.is_connected) {
UI.showTimeline(ConnectedUser.actor.urls.inbox, ConnectedUser.tokens.user.access_token)
UI.showPage('show-profile', ConnectedUser.actor)
} else {
UI.showTimeline(undefined, undefined)
UI.showPage('select-user', undefined)
}
},
'profile': function() {
UI.showPageTab(true)
UI.updateProfilePage()
'my-outbox': function() {
UI.updateNav('outbox-selector')
if (UI.is_connected) {
UI.showTimeline(ConnectedUser.actor.urls.inbox, ConnectedUser.tokens.user.access_token)
UI.showPage('show-profile', ConnectedUser.actor)
} else {
UI.showTimeline(undefined, undefined)
UI.showPage('select-user', undefined)
}
},
'send': function() {
UI.showPageTab(true)
UI.composed_message = new Message()
UI.updateSendMessagePage()
'my-profile': function() {
UI.updateNav('profile-selector')
UI.showTimeline(undefined, undefined)
if (UI.is_connected) {
UI.showPage('show-profile', ConnectedUser.actor)
} else {
UI.showPage('select-user', undefined)
}
},
'inbox': function() {
UI.showPageTab(true)
Elem('inbox-messages-error').innerHTML = ''
Elem('inbox-messages').innerHTML = 'Loading inbox...'
UI.showTimeline('inbox-messages', ConnectedUser.tokens.user.access_token, ConnectedUser.actor.urls.inbox)
},
'outbox': function() {
UI.showPageTab(true)
Elem('outbox-messages-error').innerHTML = ''
Elem('outbox-messages').innerHTML = 'Loading outbox...'
UI.showTimeline('outbox-messages', ConnectedUser.tokens.user.access_token, ConnectedUser.actor.urls.outbox)
},
'lookup': function() {
UI.showPageTab(true)
Elem('lookup-user-error').innerHTML = ''
Elem('lookup-user-info').innerHTML = ''
Elem('lookup-user-timeline').innerHTML = ''
Elem('lookup-user-timeline-error').innerHTML = ''
'other-profile': function() {
UI.updateNav(undefined)
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.showPage('show-profile', UI.other_actor)
}
},
// Show a given page
showPage: function(page) {
['select-user', 'ask-password', 'profile', 'send', 'inbox', 'outbox', 'lookup'].map(x => Elem(x).style.display = 'none')
Elem(page).style.display = 'block'
UI.refreshPage[page]()
// Page refresh methods
refresh_page: {
'select-user': function(_) {
Elem('connect-username').value = ''
},
'ask-password': function(_) {
Elem('connect-password').value = ''
var icon = ConnectedUser.actor.info.icon
if (!icon) {
icon = Icons['unknown-user']
}
Elem('ask-password-user-icon').innerHTML = '<img src="' + icon + '" width="32" height="32" />'
Elem('ask-password-user-display-name').innerText = ConnectedUser.actor.displayName()
Elem('ask-password-user-address').href = ConnectedUser.actor.urls.profile
Elem('ask-password-user-address').innerText = ConnectedUser.actor.address()
},
'show-profile': function(actor) {
// data contains the actor to display
var icon = actor.info.icon
if (!icon) {
icon = Icons['unknown-user']
}
Elem('profile-icon').innerHTML = '<img src="' + icon + '" width="96" height="96" />'
Elem('profile-display-name').innerText = actor.displayName()
Elem('profile-address').href = actor.urls.profile
Elem('profile-address').innerText = actor.address()
Elem('profile-summary').innerHTML = actor.info.summary
Elem('profile-code-source').value = JSON.stringify(actor.raw, null, 1)
},
'show-message': function(data) {
},
'send-message': function(_) {
Elem('send-message-to-recipient').value = ''
Elem('send-message-cc-recipient').value = ''
Elem('send-message-public-visibility').value = UI.composed_message.public_visibility
Elem('send-message-follower-visibility').value = UI.composed_message.follower_visibility
Elem('send-message-subject').value = UI.composed_message.subject
Elem('send-message-content').value = UI.composed_message.content
// TO/CC
Elem('send-message-to').innerHTML = UI.composed_message.to.map(
function(element) {
return '<li class="actor-display">' + Render.audienceActor(element) + ' <button onclick="UI.removeToRecipient(\'' + element.urls.profile + '\')">×</button></li>'
}).join('')
Elem('send-message-cc').innerHTML = UI.composed_message.cc.map(
function(element) {
return '<li class="actor-display">' + Render.audienceActor(element) + ' <button onclick="UI.removeCcRecipient(\'' + element.urls.profile + '\')">×</button></li>'
}).join('')
}
},
// When the page loads, load the connected user if already connected
// Methods
// On load, auto-connect
checkConnection: function() {
// Connect
ConnectedUser.loadFromLocalStorage(
function(load_ok, failure_message) {
if (load_ok) {
// TODO: Refresh the access token ?
// No need to show the login pages, go directly to send message page
UI.showPage('send')
} else {
// Show the select user page
UI.showPage('select-user')
UI.onConnectionChange(load_ok)
if (failure_message) {
UI.displayContentError(failure_message)
}
})
},
// When the user enter its address, load the actor representing the user
// On connected, show the right page
onConnectionChange: function(connected) {
UI.is_connected = connected
UI.refresh_context[UI.current_context]()
},
// Display content errors
displayContentError: function(message) {
Elem('content-error').style.display = 'block'
Elem('content-error').innerText = 'Error: ' + message
},
// Display timeline errors
displayTimelineError: function(message) {
Elem('timeline-error').style.display = 'block'
Elem('timeline-error').innerText = 'Error: ' + message
},
// Clear error messages
clearError: function() {
Elem('content-error').style.display = 'none'
Elem('content-error').innerText = ''
Elem('timeline-error').style.display = 'none'
Elem('timeline-error').innerText = ''
},
// Show a page
showPage: function(page, data) {
// Clear errors
UI.clearError()
// Hide all other pages
for (const p in UI.refresh_page) {
Elem(p).style.display = 'none'
}
// Show the page
Elem(page).style.display = 'block'
// Refresh
UI.refresh_page[page](data)
},
// Show the timeline
showTimeline: function(url, token) {
if (url) {
Elem('timeline').style.display = 'block'
Elem('timeline-data').innerHTML = 'Loading collection...'
// TODO
} else {
Elem('timeline').style.display = 'none'
}
},
// Update the nav
updateNav: function(selected) {
// Unselect all options
['send-selector', 'inbox-selector', 'outbox-selector', 'profile-selector'].map(x => Elem(x).checked = false)
if (selected) {
Elem(selected).checked = true
}
},
// Change context
setContext: function(ctx) {
UI.current_context = ctx
UI.refresh_context[UI.current_context]()
},
// Lookup actor
lookupActor: function() {
// Find the actor and change to the 'other-profile' context
UI.other_actor = new Actor()
UI.other_actor.loadFromNameServerAddress(
Elem('lookup-actor').value,
function(load_ok, failure_message) {
if (load_ok) {
UI.setContext('other-profile')
} else {
UI.displayContentError('Unable to find user (' + failure_message + ')')
}
})
},
// Action on the select-user page
selectUser: function() {
// Load the actor and go to the ask-password page
ConnectedUser.actor.loadFromNameServerAddress(
Elem('connect-username').value,
function(load_ok, failure_message) {
if (load_ok) {
UI.showPage('ask-password')
UI.showPage('ask-password', undefined)
} else {
Elem('select-user-error').innerText = 'Error: ' + failure_message
UI.displayContentError(failure_message)
}
})
},
// When the user enter its password, get the access tokens and then go to the send page
// Action on the ask-password page
connectUser: function() {
// Connect the user and go to the send page
// Connect the user
ConnectedUser.connect(
Elem('connect-password').value,
function(load_ok, failure_message) {
if (load_ok) {
UI.showPage('send')
} else {
Elem('ask-password-error').innerText = 'Error: ' + failure_message
UI.onConnectionChange(load_ok)
if (failure_message) {
UI.displayContentError(failure_message)
}
})
},
updateProfilePage: function() {
Elem('profile-info').innerHTML = UI.renderActor(ConnectedUser.actor)
},
updateSendMessagePage: function() {
Elem('send-message-to-recipient').value = ''
Elem('send-message-cc-recipient').value = ''
Elem('send-message-public-visibility').value = UI.composed_message.public_visibility
Elem('send-message-follower-visibility').value = UI.composed_message.follower_visibility
Elem('send-message-subject').value = UI.composed_message.subject
Elem('send-message-content').value = UI.composed_message.content
// TO/CC
Elem('send-message-to').innerHTML = UI.composed_message.to.map(
function(element) {
return '<li class="actor-display">' + UI.renderActorTag(element) + ' <button onclick="UI.removeToRecipient(\'' + element.urls.profile + '\')">×</button></li>'
}).join('')
Elem('send-message-cc').innerHTML = UI.composed_message.cc.map(
function(element) {
return '<li class="actor-display">' + UI.renderActorTag(element) + ' <button onclick="UI.removeCcRecipient(\'' + element.urls.profile + '\')">×</button></li>'
}).join('')
// Errors
Elem('send-message-recipient-error').innerHTML = ''
Elem('send-error').innerHTML = ''
},
// Action on the send page
// Update visibility
updateSendVisibility: function() {
UI.composed_message.setVisibility(Elem('send-message-public-visibility').value, Elem('send-message-follower-visibility').value)
},
updateSendContent: function() {
UI.composed_message.setContent(Elem('send-message-subject').value, Elem('send-message-content').value)
},
// Add to recipient lists
// Add in To
addToRecipient: function() {
var actor = new Actor()
const actor = new Actor()
actor.loadFromNameServerAddress(
Elem('send-message-to-recipient').value,
function(load_ok, failure_message) {
if (load_ok) {
UI.composed_message.addToRecipient(actor)
UI.updateSendMessagePage()
UI.showPage('send-message', undefined)
} else {
Elem('send-message-recipient-error').innerHTML = 'Unable to find user (' + failure_message + ')'
UI.displayContentError('Unable to find user (' + failure_message + ')')
}
})
},
// Add in Cc
addCcRecipient: function() {
var actor = new Actor()
const actor = new Actor()
actor.loadFromNameServerAddress(
Elem('send-message-cc-recipient').value,
Elem('send-message-to-recipient').value,
function(load_ok, failure_message) {
if (load_ok) {
UI.composed_message.addCcRecipient(actor)
UI.updateSendMessagePage()
UI.showPage('send-message', undefined)
} else {
Elem('send-message-recipient-error').innerHTML = 'Unable to find user (' + failure_message + ')'
UI.displayContentError('Unable to find user (' + failure_message + ')')
}
})
},
// Remove from recipient lists
// Remove from To
removeToRecipient: function(url_profile) {
// Don't fetch the actor, only set the profile url used in removal
var actor = new Actor()
const actor = new Actor()
actor.urls.profile = url_profile
//
UI.composed_message.removeToRecipient(actor)
UI.updateSendMessagePage()
UI.showPage('send-message', undefined)
},
// Remove from Cc
removeCcRecipient: function(url_profile) {
var actor = new Actor()
// Don't fetch the actor, only set the profile url used in removal
const actor = new Actor()
actor.urls.profile = url_profile
//
UI.composed_message.removeCcRecipient(actor)
UI.updateSendMessagePage()
UI.showPage('send-message', undefined)
},
// Update message content
updateSendContent: function() {
UI.composed_message.setContent(Elem('send-message-subject').value, Elem('send-message-content').value)
},
// Send message
sendMessage: function() {
UI.composed_message.send(
function(is_ok, failure_message) {
if (is_ok) {
UI.showPage('send')
UI.showPage('send-message', undefined)
} else {
Elem('send-error').innerText = failure_message
UI.displayContentError('Error when sending message: ' + failure_message)
}
})
},
}
/*
renderRawData: function(rawData) {
var str_data = JSON.stringify(rawData, null, 1)
var replace_map = {
@ -300,51 +426,6 @@ var UI = {
Elem(id + '-error').innerText = failure_message
}
})
},
renderActor: function(actor) {
var display = '<section>'
if (actor.valid) {
if (actor.info.icon) {
display = display + '<img src="' + actor.info.icon + '" width="96" height="96" /> '
}
display = display
+ '<p style="display:inline-block;"><strong>' + actor.displayName() + '</strong> <br/>'
+ '<a href="' + actor.urls.profile + '">'
+ actor.address()
+ '</a></p>'
+ '<p>' + actor.info.summary + '</p>'
} else {
display = display
+ '<p style="display:inline-block;">'
+ '<a href="' + actor.urls.profile + '">'
+ 'Other actor'
+ '</a></p>'
}
display = display + '</section>'
if (actor.raw) {
display = display + UI.renderRawData(actor.raw)
}
return display
},
lookupUser: function() {
Elem('lookup-user-info').innerHTML = ''
Elem('lookup-user-timeline').innerHTML = ''
Elem('lookup-user-error').innerHTML = ''
Elem('lookup-user-timeline-error').innerHTML = ''
var actor = new Actor()
actor.loadFromNameServerAddress(
Elem('lookup-user').value,
function(load_ok, failure_message) {
if (load_ok) {
Elem('lookup-user-info').innerHTML = UI.renderActor(actor)
if (actor.urls.outbox) {
UI.showTimeline('lookup-user-timeline', undefined, actor.urls.outbox)
} else {
Elem('lookup-user-timeline-error').innerText = 'User does not have a public outbox.'
}
} else {
Elem('lookup-user-error').innerText = 'Unable to find user (' + failure_message + ')'
}
})
}
*/
}