Refactor single-page-app page assembly

This commit is contained in:
Tony Garnock-Jones 2016-12-06 18:30:02 +13:00
parent 88ff347744
commit 985403894f
9 changed files with 252 additions and 231 deletions

View File

@ -1,79 +0,0 @@
<div id="main-tabs-bodies">
<div id="main-tab-body-contacts">
<h2>Add a new contact</h2>
<form class="form-inline">
<label for="add-contact-email">New contact email: </label>
<input class="form-control" id="add-contact-email" type="email">
<button class="btn btn-default" id="add-contact">Add contact</button>
</form>
<h2>Contact List</h2>
<div class="container">
<div class="contact-list" class="row"></div>
</div>
</div>
<div id="main-tab-body-new-chat">
<h2>New Conversation</h2>
<div class="container">
<div class="contact-list" class="row"></div>
</div>
</div>
<div id="main-tab-body-conversations">
<div class="container">
<div class="row">
<div class="col-xs-4">
<div id="conversation-list">
</div>
<div class="align-center">
<a class="big-icon text-gray-dark" href="#/new-chat"><i class="cursor-interactive icon ion-plus-circled"></i></a>
</div>
</div>
<div class="col-xs-8">
<p class="align-center">
Select a conversation from the column to the left,
or <a href="#/new-chat">create a new conversation</a>.
</p>
</div>
</div>
</div>
</div>
<div id="main-tab-body-permissions">
<h2>Permissions I enjoy</h2>
<ul id="permissions"></ul>
<h2>Permissions I have granted to others</h2>
<ul id="grants"></ul>
</div>
<div id="main-tab-body-questions">
<h2>Questions</h2>
<p class="show-only-zero-count count{{questionCount}}">There are no questions waiting for you to answer.</p>
<div class="container">
<div id="question-container" class="row"></div>
</div>
<div class="hide-zero-count count{{otherRequestCount}}">
<p>
<label for="show-all-requests-from-others">Show all pending requests from others? </label>
<input type="checkbox" id="show-all-requests-from-others" {{#showRequestsFromOthers}}checked{{/showRequestsFromOthers}}>
</p>
{{#showRequestsFromOthers}}
<div id="all-requests-from-others-div">
<h2>All requests from others</h2>
<ul id="others-permission-requests"></ul>
</div>
{{/showRequestsFromOthers}}
</div>
</div>
<div id="main-tab-body-my-requests">
<h2>Requests I have made</h2>
<p class="show-only-zero-count count{{myRequestCount}}">You have no outstanding requests waiting for responses from others.</p>
<ul id="my-permission-requests"></ul>
</div>
<hr>
<!-- <pre id="debug-space"></pre> -->
</div>

View File

@ -0,0 +1,11 @@
<h2>Add a new contact</h2>
<form class="form-inline">
<label for="add-contact-email">New contact email: </label>
<input class="form-control" id="add-contact-email" type="email">
<button class="btn btn-default" id="add-contact">Add contact</button>
</form>
<h2>Contact List</h2>
<div class="container">
<div class="contact-list" class="row"></div>
</div>

View File

@ -0,0 +1,17 @@
<div class="container">
<div class="row">
<div class="col-xs-4">
<div id="conversation-list">
</div>
<div class="align-center">
<a class="big-icon text-gray-dark" href="#/new-chat"><i class="cursor-interactive icon ion-plus-circled"></i></a>
</div>
</div>
<div class="col-xs-8">
<p class="align-center">
Select a conversation from the column to the left,
or <a href="#/new-chat">create a new conversation</a>.
</p>
</div>
</div>
</div>

View File

@ -0,0 +1,3 @@
<h2>Requests I have made</h2>
<p class="show-only-zero-count count{{myRequestCount}}">You have no outstanding requests waiting for responses from others.</p>
<ul id="my-permission-requests"></ul>

View File

@ -0,0 +1,4 @@
<h2>New Conversation</h2>
<div class="container">
<div class="contact-list" class="row"></div>
</div>

View File

@ -0,0 +1,5 @@
<h2>Permissions I enjoy</h2>
<ul id="permissions"></ul>
<h2>Permissions I have granted to others</h2>
<ul id="grants"></ul>

View File

@ -0,0 +1,17 @@
<h2>Questions</h2>
<p class="show-only-zero-count count{{questionCount}}">There are no questions waiting for you to answer.</p>
<div class="container">
<div id="question-container" class="row"></div>
</div>
<div class="hide-zero-count count{{otherRequestCount}}">
<p>
<label for="show-all-requests-from-others">Show all pending requests from others? </label>
<input type="checkbox" id="show-all-requests-from-others" {{#showRequestsFromOthers}}checked{{/showRequestsFromOthers}}>
</p>
{{#showRequestsFromOthers}}
<div id="all-requests-from-others-div">
<h2>All requests from others</h2>
<ul id="others-permission-requests"></ul>
</div>
{{/showRequestsFromOthers}}
</div>

View File

@ -88,6 +88,8 @@
actor {
this.ui = new Syndicate.UI.Anchor();
var mainpage_c = this.ui.context('mainpage');
field this.connectedTo = null;
field this.myRequestCount = 0; // requests *I* have made of others
field this.otherRequestCount = 0; // requests *others* have made of me
@ -101,60 +103,48 @@
on asserted brokerConnected($url) { this.connectedTo = url; }
on retracted brokerConnected(_) { this.connectedTo = null; }
var mainpage_c = this.ui.context('mainpage');
during inbound(uiTemplate("mainpage.html", $mainpage)) {
assert mainpage_c.html('div#main-div', Mustache.render(
mainpage,
{
questionCount: this.questionCount,
myRequestCount: this.myRequestCount,
otherRequestCount: this.otherRequestCount,
globallyVisible: this.globallyVisible,
showRequestsFromOthers: this.showRequestsFromOthers
}));
}
during inbound(online()) {
on start { this.globallyVisible = true; }
on stop { this.globallyVisible = false; }
}
during mainpage_c.fragmentVersion($mainpageVersion) {
// We track mainpageVersion so that changes to mainpage.html force re-creation
// of nested widgetry. If we didn't include mainpageVersion in each subwidget's
// context, then so long as the subwidget's content itself remained unchanged,
// the user would see the subwidget disappear when mainpage.html changed.
on asserted Syndicate.UI.locationHash($hash) {
var tab = hash.substr(1);
console.log("Switching tab to", tab);
$('#main-tabs-bodies > div').hide();
$('#main-tabs-tabs a.nav-link').removeClass('active');
$('#main-tab-body-' + tab).show();
$('#main-tab-tab-' + tab).addClass('active');
during inbound(uiTemplate("nav-account.html", $entry)) {
var c = this.ui.context('nav', 0, 'account');
assert outbound(online()) when (this.locallyVisible);
assert c.html('#nav-ul', Mustache.render(
entry,
{
email: sessionInfo.email,
avatar: avatar(sessionInfo.email),
questionCount: this.questionCount,
myRequestCount: this.myRequestCount,
otherRequestCount: this.otherRequestCount,
globallyVisible: this.globallyVisible,
locallyVisible: this.locallyVisible
}));
on message c.event('.toggleInvisible', 'click', _) {
this.locallyVisible = !this.locallyVisible;
}
}
during inbound(uiTemplate("nav-account.html", $entry)) {
var c = this.ui.context(mainpageVersion, 'nav', 0, 'account');
assert outbound(online()) when (this.locallyVisible);
assert c.html('#nav-ul', Mustache.render(
entry,
{
email: sessionInfo.email,
avatar: avatar(sessionInfo.email),
questionCount: this.questionCount,
myRequestCount: this.myRequestCount,
otherRequestCount: this.otherRequestCount,
globallyVisible: this.globallyVisible,
locallyVisible: this.locallyVisible
}));
on message c.event('.toggleInvisible', 'click', _) {
this.locallyVisible = !this.locallyVisible;
}
// assert mainpage_c.html('div#main-div', Mustache.render(
// mainpage,
// {
// questionCount: this.questionCount,
// myRequestCount: this.myRequestCount,
// otherRequestCount: this.otherRequestCount,
// globallyVisible: this.globallyVisible,
// showRequestsFromOthers: this.showRequestsFromOthers
// }));
during Syndicate.UI.locationHash('/contacts') {
during inbound(uiTemplate("page-contacts.html", $mainEntry)) {
assert mainpage_c.html('div#main-div', Mustache.render(mainEntry, {}));
}
during inbound(uiTemplate("contact-entry.html", $entry)) {
during Syndicate.UI.locationHash('/contacts') {
during mainpage_c.fragmentVersion($mainpageVersion) {
during inbound(contactListEntry(sessionInfo.email, $contact)) {
field this.pendingContactRequest = false;
field this.isPresent = false;
@ -167,13 +157,12 @@
on stop { this.pendingContactRequest = false; }
}
var c = this.ui.context(mainpageVersion, 'all-contacts', contact);
assert c.html('#main-tab-body-contacts .contact-list',
Mustache.render(entry, {
email: contact,
avatar: avatar(contact),
pendingContactRequest: this.pendingContactRequest,
isPresent: this.isPresent
}));
assert c.html('.contact-list', Mustache.render(entry, {
email: contact,
avatar: avatar(contact),
pendingContactRequest: this.pendingContactRequest,
isPresent: this.isPresent
}));
on message c.event('.delete-contact', 'click', _) {
if (confirm((this.pendingContactRequest
? "Cancel contact request to "
@ -189,146 +178,199 @@
}
}
during inputValue('#add-contact-email', $rawContact) {
var contact = rawContact.trim();
if (contact) {
on message mainpage_c.event('#add-contact', 'click', _) {
:: outbound(createResource(grant(sessionInfo.email,
sessionInfo.email,
contact,
pFollow(sessionInfo.email),
false)));
$('#add-contact-email').val('');
during mainpage_c.fragmentVersion($mainpageVersion) {
during inputValue('#add-contact-email', $rawContact) {
var contact = rawContact.trim();
if (contact) {
on message mainpage_c.event('#add-contact', 'click', _) {
:: outbound(createResource(grant(sessionInfo.email,
sessionInfo.email,
contact,
pFollow(sessionInfo.email),
false)));
$('#add-contact-email').val('');
}
}
}
}
}
during Syndicate.UI.locationHash('/permissions') {
during inbound(uiTemplate("page-permissions.html", $mainEntry)) {
assert mainpage_c.html('div#main-div', Mustache.render(mainEntry, {}));
}
during inbound(uiTemplate("permission-entry.html", $entry)) {
during inbound(permitted($i, $e, $p, $d)) {
if (i !== sessionInfo.email) {
var c = this.ui.context(mainpageVersion, 'permitted', i, e, p, d);
assert c.html('#permissions', Mustache.render(entry,
{issuer: i,
email: e,
permission: JSON.stringify(p),
isDelegable: d,
isRelinquishable: i !== e}));
on message c.event('.relinquish', 'click', _) {
:: outbound(deleteResource(permitted(i, e, p, d)));
during mainpage_c.fragmentVersion($mainpageVersion) {
during inbound(permitted($i, $e, $p, $d)) {
if (i !== sessionInfo.email) {
var c = this.ui.context(mainpageVersion, 'permitted', i, e, p, d);
assert c.html('#permissions', Mustache.render(entry, {
issuer: i,
email: e,
permission: JSON.stringify(p),
isDelegable: d,
isRelinquishable: i !== e
}));
on message c.event('.relinquish', 'click', _) {
:: outbound(deleteResource(permitted(i, e, p, d)));
}
}
}
}
}
during inbound(uiTemplate("grant-entry.html", $entry)) {
during inbound(grant($i, sessionInfo.email, $ge, $p, $d)) {
var c = this.ui.context(mainpageVersion, 'granted', i, ge, p, d);
assert c.html('#grants', Mustache.render(entry, {issuer: i,
grantee: ge,
permission: JSON.stringify(p),
isDelegable: d}));
on message c.event('.revoke', 'click', _) {
:: outbound(deleteResource(grant(i, sessionInfo.email, ge, p, d)));
during mainpage_c.fragmentVersion($mainpageVersion) {
during inbound(grant($i, sessionInfo.email, $ge, $p, $d)) {
var c = this.ui.context(mainpageVersion, 'granted', i, ge, p, d);
assert c.html('#grants', Mustache.render(entry, {
issuer: i,
grantee: ge,
permission: JSON.stringify(p),
isDelegable: d
}));
on message c.event('.revoke', 'click', _) {
:: outbound(deleteResource(grant(i, sessionInfo.email, ge, p, d)));
}
}
}
}
}
during Syndicate.UI.locationHash('/my-requests') {
during inbound(uiTemplate("page-my-requests.html", $mainEntry)) {
assert mainpage_c.html('div#main-div', Mustache.render(mainEntry, {
myRequestCount: this.myRequestCount
}));
}
during inbound(uiTemplate("permission-request-out-GENERIC.html", $genericEntry)) {
during inbound(permissionRequest($issuer, sessionInfo.email, $permission)) {
on start { this.myRequestCount++; }
on stop { this.myRequestCount--; }
during mainpage_c.fragmentVersion($mainpageVersion) {
during inbound(permissionRequest($issuer, sessionInfo.email, $permission)) {
on start { this.myRequestCount++; }
on stop { this.myRequestCount--; }
var c = this.ui.context(mainpageVersion, 'my-permission-request', issuer, permission);
field this.entry = genericEntry;
assert c.html('#my-permission-requests',
Mustache.render(this.entry,
{issuer: issuer,
permission: permission,
permissionJSON: JSON.stringify(permission)}))
when (this.entry);
var specificTemplate = "permission-request-out-" +
encodeURIComponent(permission.meta.label) + ".html";
on asserted inbound(uiTemplate(specificTemplate, $specificEntry)) {
this.entry = specificEntry || genericEntry;
}
on message c.event('.cancel', 'click', _) {
:: outbound(deleteResource(permissionRequest(issuer, sessionInfo.email, permission)));
}
}
}
during inputValue('#show-all-requests-from-others', $showRequestsFromOthers) {
on start { this.showRequestsFromOthers = showRequestsFromOthers; }
}
during inbound(uiTemplate("permission-request-in-GENERIC.html", $genericEntry)) {
during inbound(permissionRequest($issuer, $grantee, $permission)) {
if (grantee !== sessionInfo.email) {
on start { this.otherRequestCount++; }
on stop { this.otherRequestCount--; }
var c = this.ui.context(mainpageVersion, 'others-permission-request', issuer, grantee, permission);
var c = this.ui.context(mainpageVersion, 'my-permission-request', issuer, permission);
field this.entry = genericEntry;
assert c.html('#others-permission-requests',
Mustache.render(this.entry,
{issuer: issuer,
grantee: grantee,
permission: permission,
permissionJSON: JSON.stringify(permission)}))
when (this.entry);
var specificTemplate = "permission-request-in-" +
assert c.html('#my-permission-requests', Mustache.render(this.entry, {
issuer: issuer,
permission: permission,
permissionJSON: JSON.stringify(permission)
})) when (this.entry);
var specificTemplate = "permission-request-out-" +
encodeURIComponent(permission.meta.label) + ".html";
on asserted inbound(uiTemplate(specificTemplate, $specificEntry)) {
this.entry = specificEntry || genericEntry;
}
on message c.event('.grant', 'click', _) {
:: outbound(createResource(grant(issuer,
sessionInfo.email,
grantee,
permission,
false)));
on message c.event('.cancel', 'click', _) {
:: outbound(deleteResource(permissionRequest(issuer, sessionInfo.email, permission)));
}
on message c.event('.deny', 'click', _) {
:: outbound(deleteResource(permissionRequest(issuer, grantee, permission)));
}
}
}
}
during Syndicate.UI.locationHash('/questions') {
during inbound(uiTemplate("page-questions.html", $mainEntry)) {
assert mainpage_c.html('div#main-div', Mustache.render(mainEntry, {
questionCount: this.questionCount,
otherRequestCount: this.otherRequestCount,
showRequestsFromOthers: this.showRequestsFromOthers
}));
}
during mainpage_c.fragmentVersion($mainpageVersion) {
during inputValue('#show-all-requests-from-others', $showRequestsFromOthers) {
on start { this.showRequestsFromOthers = showRequestsFromOthers; }
}
}
during inbound(uiTemplate("permission-request-in-GENERIC.html", $genericEntry)) {
during mainpage_c.fragmentVersion($mainpageVersion) {
during inbound(permissionRequest($issuer, $grantee, $permission)) {
if (grantee !== sessionInfo.email) {
on start { this.otherRequestCount++; }
on stop { this.otherRequestCount--; }
var c = this.ui.context(mainpageVersion, 'others-permission-request', issuer, grantee, permission);
field this.entry = genericEntry;
assert c.html('#others-permission-requests', Mustache.render(this.entry, {
issuer: issuer,
grantee: grantee,
permission: permission,
permissionJSON: JSON.stringify(permission)
})) when (this.entry);
var specificTemplate = "permission-request-in-" +
encodeURIComponent(permission.meta.label) + ".html";
on asserted inbound(uiTemplate(specificTemplate, $specificEntry)) {
this.entry = specificEntry || genericEntry;
}
on message c.event('.grant', 'click', _) {
:: outbound(createResource(grant(issuer,
sessionInfo.email,
grantee,
permission,
false)));
}
on message c.event('.deny', 'click', _) {
:: outbound(deleteResource(permissionRequest(issuer, grantee, permission)));
}
}
}
}
}
during inbound(question($qid, $timestamp, $klass, sessionInfo.email, $title, $blurb, $qt))
{
on start { this.questionCount++; }
on stop { this.questionCount--; }
during mainpage_c.fragmentVersion($mainpageVersion) {
during
inbound(question($qid, $timestamp, $klass, sessionInfo.email, $title, $blurb, $qt))
{
on start { this.questionCount++; }
on stop { this.questionCount--; }
var c = this.ui.context(mainpageVersion, 'question', timestamp, qid);
var c = this.ui.context(mainpageVersion, 'question', timestamp, qid);
switch (qt.meta.label) {
case "option-question": {
var options = qt.fields[0];
during inbound(uiTemplate("option-question.html", $entry)) {
assert c.html('#question-container',
Mustache.render(entry, {questionClass: klass,
title: title,
blurb: blurb,
options: options}));
on message c.event('.response', 'click', $e) {
react { assert outbound(answer(qid, e.target.dataset.value)); }
switch (qt.meta.label) {
case "option-question": {
var options = qt.fields[0];
during inbound(uiTemplate("option-question.html", $entry)) {
assert c.html('#question-container', Mustache.render(entry, {
questionClass: klass,
title: title,
blurb: blurb,
options: options
}));
on message c.event('.response', 'click', $e) {
react { assert outbound(answer(qid, e.target.dataset.value)); }
}
}
break;
}
default: {
break;
}
break;
}
default: {
break;
}
}
}
}
during Syndicate.UI.locationHash('/conversations') {
during inbound(uiTemplate("page-conversations.html", $mainEntry)) {
assert mainpage_c.html('div#main-div', Mustache.render(mainEntry, {}));
}
}
during Syndicate.UI.locationHash('/new-chat') {
during inbound(uiTemplate("page-new-chat.html", $mainEntry)) {
assert mainpage_c.html('div#main-div', Mustache.render(mainEntry, {}));
}
}
}
}
G.dataspace.setOnStateChange(function (mux, patch) {
$("#debug-space").text(Syndicate.prettyTrie(mux.routingTable));
});
// G.dataspace.setOnStateChange(function (mux, patch) {
// $("#debug-space").text(Syndicate.prettyTrie(mux.routingTable));
// });
}
})();

View File

@ -1 +1,2 @@
testing.rktd
compiled/main_rkt.*