Skip to content

Commit de3a9db

Browse files
license and CI
1 parent 091f5bd commit de3a9db

File tree

5 files changed

+106
-34
lines changed

5 files changed

+106
-34
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
sudo: false
2+
language: node_js

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2017 Mark Terry
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Tiny browser web framework, which communicates to the server via a websocket. All DOM changes are performed using HTML provided by the server.
44

5+
Minified size is 2.25 Kb which when transmitted compressed is 858 Bytes!
6+
57
## Specification
68

79
### Client
@@ -18,7 +20,9 @@ A server must return JSON from websocket requests in the following format:
1820
"action": "append|replace",
1921
"container": "ID of container element to update",
2022
"content": "HTML string"
21-
]}
23+
}]
24+
25+
As this is an array the server may return 0 or more elements that need to updated.
2226

2327
### Demo
2428

@@ -37,14 +41,18 @@ This example shows the following:
3741
* Using a cookie session with a websocket.
3842
* Direct DOM change from user action.
3943
* Indirect DOM change from user action.
44+
* DOM change via timed event.
4045

4146
## Compatibility
4247

4348
Browser shims for modern browser functionality are not included in this project.
4449

50+
The following would be required:
51+
4552
* Array.prototype.forEach
4653
* Websockets
4754

4855
## Todo
4956

5057
* Implement more actionable elements, such as images or links etc.
58+

example/server.js

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
'use strict'
2+
//Server for demo application
23

34
const session = require('express-session')
45
const express = require('express')
56
const url = require('url')
67
const qs = require('qs')
78
const http = require('http')
89
const WebSocket = require('ws')
9-
//const staticGzip = require('static-gzip')
10-
var compression = require('compression')
10+
const compression = require('compression')
1111

1212
const app = express()
1313

@@ -19,17 +19,22 @@ const sessionHandler = session({
1919

2020
app.use(compression())
2121
app.use(sessionHandler)
22+
app.use(express.static('dist'))
2223

23-
const server = http.createServer(app);
24+
const server = http.createServer(app)
2425

2526
const wss = new WebSocket.Server({
2627
server: server,
2728
path: '/websocket'
2829
})
2930

30-
app.use(express.static('dist'))
31+
server.listen(3000, () => {
32+
console.log('Listening on %d', server.address().port)
33+
});
3134

32-
app.get('/', function(req, res, next){
35+
//Return the starting HTML to the client
36+
//Just inlined it here as this is just an example server.
37+
app.get('/', (req, res, next) => {
3338
const response = `
3439
<!DOCTYPE html>
3540
<html lang="en">
@@ -45,6 +50,7 @@ app.get('/', function(req, res, next){
4550
<div class="page-header">
4651
<h1>Todo Example</h1>
4752
</div>
53+
<div id="count">${renderTodoCount(req.session)}</div>
4854
<ul id="lists" class="list-group">
4955
${renderTodos(req.session)}
5056
</ul>
@@ -66,57 +72,55 @@ app.get('/', function(req, res, next){
6672
res.send(response)
6773
})
6874

69-
wss.on('connection', function(ws){
70-
let req = {
75+
wss.on('connection', (ws) => {
76+
const req = { //Fake a request that we would normally see over HTTP
7177
originalUrl: '/',
7278
pathname: '/',
7379
headers: ws.upgradeReq.headers
7480
}
75-
sessionHandler(req, {}, function(){
76-
ws.on('message', function(msg){
81+
sessionHandler(req, {}, () => { //Process session once a client connects
82+
ws.on('message', (msg) => {
7783
console.log(msg)
7884
const parsed = url.parse(msg)
79-
processMessage(ws, parsed, req.session)
85+
routeMessage(ws, parsed, req.session)
8086
})
81-
8287
})
8388
})
8489

85-
server.listen(3000, function listening(){
86-
console.log('Listening on %d', server.address().port);
87-
});
88-
89-
90-
const processMessage = function(ws, request, session){
90+
//Simple router
91+
const routeMessage = (ws, request, session) => {
9192
const query = qs.parse(request.query)
93+
//The example app only has these functions
9294
if(request.pathname === '/add'){
93-
addRoute(query, session, function(out){
95+
addRoute(query, session, (out) => {
9496
ws.send(JSON.stringify(out))
9597
})
9698
}
9799
else if(request.pathname === '/delete'){
98-
deleteRoute(query, session, function(out){
100+
deleteRoute(query, session, (out) => {
99101
ws.send(JSON.stringify(out))
100102
})
101103
}
102-
};
104+
}
103105

104-
const deleteRoute = function (query, session, cb){
105-
const filtered = session.todos.filter(function(item){
106+
//Deleting a todo
107+
const deleteRoute = (query, session, cb) => {
108+
const filtered = session.todos.filter((item) => {
106109
return item.id !== parseInt(query.id, 10)
107110
})
108111
session.todos = filtered
109-
session.save(function(){
112+
session.save(() => {
110113
const response = [{
111114
action: 'replace',
112115
container: 'lists',
113116
content: renderTodos(session)
114117
}]
115118
cb(response)
116119
})
117-
};
120+
}
118121

119-
const addRoute = function(query, session, cb){
122+
//Adding a todo
123+
const addRoute = (query, session, cb) => {
120124
if(!session.todos){
121125
session.todos = []
122126
}
@@ -126,37 +130,50 @@ const addRoute = function(query, session, cb){
126130
reminder: query.reminder
127131
}
128132
session.todos.push(todo)
129-
session.save(function(){
133+
session.save(() => {
130134
const response = [{
131135
action: 'append',
132136
container: 'lists',
133137
content: '<li class="list-group-item">' + todo.description + ' <button class="pull-right" data-url="/delete?id=' + todo.id + '">Delete</button></li>'
138+
},{
139+
action: 'replace',
140+
container: 'count',
141+
content: renderTodoCount(session)
134142
}]
135143
if(todo.reminder !== '0'){
136144
console.log('scheduling reminder')
137145
sendReminder(todo, cb)
138146
}
139147
cb(response)
140148
})
141-
};
149+
}
142150

143-
const sendReminder = function(todo, cb){
144-
setTimeout(function(){
151+
//Send a message back to the client at some point in the future.
152+
//cb() is the send function on the websocket so we can call it as many times as we need.
153+
const sendReminder = (todo, cb) => {
154+
setTimeout(() => {
145155
const reminderResponse = [{
146156
action: 'replace',
147157
container: 'reminder',
148158
content: '<div class="alert alert-info" role="alert" onclick="this.style.display = \'none\';">Reminder for ' + todo.description + '!</div>'
149159
}]
150160
cb(reminderResponse)
151161
}, todo.reminder * 1000)
152-
};
162+
}
153163

154-
const renderTodos = function(sess){
164+
//Generate the HTML for all the todos
165+
const renderTodos = (sess) => {
155166
if(!sess.todos){
156167
return ''
157168
}
158-
return sess.todos.reduce(function(acc, todo){
169+
return sess.todos.reduce((acc, todo) => {
159170
acc += '<li class="list-group-item">' + todo.description + ' <button class="pull-right" data-url="/delete?id=' + todo.id + '">Delete</button></li>'
160171
return acc
161172
}, '')
162173
}
174+
175+
//Generate the HTML for the number of todos
176+
const renderTodoCount = (sess) => {
177+
const number = sess.todos ? sess.todos.length : 0
178+
return `You have <strong>${number}</strong> todos right now.`
179+
}

package.json

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,32 @@
11
{
2+
"name": "tiny-browser-framework",
3+
"description": "Minimal Client JS Framework ",
4+
"version": "1.0.0",
5+
"homepage": "https://github.com/thedumbterminal/TinyBrowserFramework",
6+
"author": {
7+
"name": "thedumbterminal",
8+
"email": "[email protected]",
9+
"url": "http://www.thedumbterminal.co.uk"
10+
},
11+
"license": "MIT",
12+
"repository": {
13+
"type": "git",
14+
"url": "git://github.com/thedumbterminal/TinyBrowserFramework.git"
15+
},
16+
"bugs": {
17+
"url": "https://github.com/thedumbterminal/TinyBrowserFramework/issues"
18+
},
19+
"licenses": [
20+
{
21+
"type": "MIT",
22+
"url": "https://github.com/thedumbterminal/TinyBrowserFramework/blob/master/LICENSE"
23+
}
24+
],
225
"scripts": {
326
"build": "mkdir -p dist && uglifyjs src/index.js -v -o dist/index.js",
427
"exampleServer": "nodemon example/server.js",
5-
"start": "npm run build && npm run exampleServer"
28+
"start": "npm run build && npm run exampleServer",
29+
"test": "node -c src/index.js"
630
},
731
"devDependencies": {
832
"compression": "^1.6.2",

0 commit comments

Comments
 (0)