1
+ <!DOCTYPE html>
2
+ < html >
3
+
4
+ < head >
5
+ < meta http-equiv ="content-type " content ="text/html; charset=utf-8 " />
6
+ < link rel ="stylesheet " href ="./index.css ">
7
+ </ head >
8
+
9
+ < body >
10
+ < h2 > Scuttle Shell Browser example</ h2 >
11
+ < h1 > Review our product</ h1 >
12
+ < p > The #6 BunaB is a quality product meeting and exceeding the highest requirements in
13
+ regards to quality and long term user satisfaction.
14
+ </ p >
15
+ < p >
16
+ However, don't just take our word for it, read the following reviews. To guarantee that the
17
+ reviews are genuine and from people you can trust we use Scuttlebut so that the reviews are
18
+ stored on the decentralized Secure Scuttlebutt network outside our control.
19
+ </ p >
20
+ < img src ="images/BunaB.jpg " style ="width: 50% " />
21
+ < div id ="output ">
22
+ < div style ="background-color: yellow; " class ="after_wait ">
23
+ This Page needs to access Scuttlebut. Make sure that Scuttle Shell Browser is installed and that "SSB access" is
24
+ switched on for this page.
25
+ </ div >
26
+ </ div >
27
+ < script src ="https://cdn.jsdelivr.net/npm/marked/marked.min.js "> </ script >
28
+ < script src ="connect-ssb.js "> </ script >
29
+ < script type ="module ">
30
+ import daysPosts from './source/days-posts.js'
31
+ import getName from './async/get-name.js'
32
+ import getAvatar from './async/get-avatar.js'
33
+
34
+ const outElem = document . getElementById ( 'output' )
35
+
36
+ connectSsb ( ) . then ( server => {
37
+ outElem . innerHTML = 'Loading reviews from Scuttlebutt...'
38
+ console . time ( 'get posts' )
39
+ const item = 'No. 6 BunaB'
40
+ const opts = {
41
+ limit : 5 ,
42
+ reverse : true ,
43
+ query : [
44
+ {
45
+ $filter : {
46
+ value : {
47
+ content : {
48
+ type : 'post' ,
49
+ 'channel' : 'reviews' ,
50
+ item
51
+ }
52
+ }
53
+ }
54
+ } , {
55
+ $map : {
56
+ author : [ 'value' , 'author' ] ,
57
+ timestamp : [ 'value' , 'timestamp' ] ,
58
+ text : [ 'value' , 'content' , 'text' ] ,
59
+ root : [ 'value' , 'content' , 'root' ] // the root messages of a thread, this is present if this post is a reply to another message
60
+ }
61
+ }
62
+ ]
63
+ }
64
+ pull (
65
+ server . query . read ( opts ) ,
66
+ pull . paraMap ( addName , 50 ) , // run up to 50 asynchronous maps in parallel
67
+ pull . paraMap ( addAvatar , 50 ) , // run up to 50 asynchronous maps in parallel
68
+ pull . collect ( onDone )
69
+ )
70
+
71
+ function addName ( data , cb ) {
72
+ console . log ( 'adding name' , data )
73
+ getName ( server ) ( data . author , ( err , name ) => {
74
+ if ( err ) cb ( err )
75
+ else {
76
+ data . authorName = name
77
+ console . log ( 'added name' , name )
78
+ cb ( null , data )
79
+ }
80
+ } )
81
+ }
82
+ function addAvatar ( data , cb ) {
83
+ getAvatar ( server ) ( data . author , ( err , avatar ) => {
84
+ if ( err ) cb ( err )
85
+ else {
86
+ data . avatar = avatar
87
+ console . log ( 'added avatar' , avatar )
88
+ cb ( null , data )
89
+ }
90
+ } )
91
+ }
92
+
93
+ function onDone ( err , data ) {
94
+ console . log ( 'finally' )
95
+ if ( err ) {
96
+ console . error ( 'oh noes' , err )
97
+ return
98
+ }
99
+
100
+ outElem . innerHTML = Messages ( data )
101
+
102
+ addForm ( )
103
+
104
+ console . log ( `${ data . length } messages` )
105
+ console . timeEnd ( 'get posts' )
106
+
107
+ }
108
+
109
+
110
+ function Messages ( data ) {
111
+ return `
112
+ <div style="font-family: arial;">
113
+ ${ data . map ( Message ) }
114
+ </div>
115
+ `
116
+ }
117
+
118
+ function Message ( msgData ) {
119
+ const { avatar, authorName, timestamp, text, root } = msgData
120
+
121
+ return `
122
+ <div style="margin: 2rem;">
123
+ ${ avatar ? Avatar ( avatar ) : '' }
124
+ <strong>${ authorName } </strong> - ${ new Date ( timestamp ) . toLocaleString ( ) }
125
+ <p>${ text ? window . marked ( text ) : '' } </p>
126
+ </div>
127
+ `
128
+ }
129
+
130
+ function Avatar ( blobId ) {
131
+ if ( ! blobId ) return
132
+
133
+ const url = `http://localhost:8989/blobs/get/${ blobId } `
134
+ // this may be patchbay specific
135
+
136
+ return `
137
+ <img src=${ url } style="width: 2rem; height: 2rem;"/>
138
+ `
139
+ }
140
+
141
+ function addForm ( ) {
142
+ const form = `
143
+ <h2>Publish your own review of ${ item } </h2>
144
+ <textarea id="review" style="width: 80%">
145
+ # Review of ${ item }
146
+
147
+ </textarea>
148
+ <br/>
149
+ <button id="publish">Publish</button>
150
+ `
151
+ outElem . innerHTML += form
152
+ document . getElementById ( 'publish' ) . addEventListener ( 'click' , ( ) => publishReview ( document . getElementById ( 'review' ) . value ) )
153
+ }
154
+
155
+ function publishReview ( review ) {
156
+ const text = review + `\n\n---\n\nPublished on ${ window . location } with Scuttle Shell Browser`
157
+ server . publish ( {
158
+ type : 'post' ,
159
+ 'channel' : 'reviews' ,
160
+ item,
161
+ text
162
+ } , function ( err , msg ) {
163
+ console . log ( msg ) ;
164
+ window . location . reload ( )
165
+ } ) ;
166
+ }
167
+
168
+ } )
169
+ setTimeout ( ( ) => document . body . classList . add ( 'waited' ) , 1000 )
170
+ </ script >
171
+ </ body >
172
+
173
+ </ html >
0 commit comments