mirror of
https://github.com/amark/gun.git
synced 2025-06-05 21:56:51 +00:00
updated examples!
This commit is contained in:
parent
f43a0212b0
commit
c804df9b77
@ -1,66 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="../../gun.js"></script>
|
||||
</head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
html, body { font-size: 14pt; }
|
||||
.hide { display: none; }
|
||||
form .who { width: 10%; }
|
||||
form .what { width: 80%; }
|
||||
ul { list-style: none; padding: 0; }
|
||||
ul .when {color: #555; font-size: 12pt; float: right; display: none; }
|
||||
li:hover .when {display: inline;}
|
||||
</style>
|
||||
<ul><li class="hide">
|
||||
<b class="who"></b>:
|
||||
<span class="what"></span>
|
||||
<u class="hide sort">0</u>
|
||||
<i class="when">0</i>
|
||||
</li></ul>
|
||||
<form>
|
||||
<input class="who" placeholder="alias">
|
||||
<input class="what" placeholder="message">
|
||||
<button>send</button>
|
||||
</form>
|
||||
<script>
|
||||
var $ = function(s, e){ return (e || document).querySelector(s) } // make native look like jQuery.
|
||||
;(function(){var H=HTMLElement,C=H.prototype; // jQuery chaining replacement!
|
||||
for(var i in C){(function(j,i){if(j&&j!=i){
|
||||
try{C[j]=C[j]||C[i]}catch(e){C[j]=function(){return this[i]}}
|
||||
}}(i.replace(/[A-Z](.*)/g,''),i));
|
||||
}}());
|
||||
$.sort = function(g, e){ return (g > ($('.sort', e)[$.text] || -Infinity))? e : $.sort(g, e.previousSibling) }
|
||||
$.text = document.body.textContent? 'textContent' : 'innerText'; // because browsers are stupid.
|
||||
</script>
|
||||
<script>
|
||||
($.model = $('ul li').clone(true)).removeAttribute('class');
|
||||
var gun = Gun(location.origin + '/gun');
|
||||
var chat = gun.get('example/chat/data');
|
||||
chat.map().val(function(msg, field){
|
||||
console.log("msg", field, msg);
|
||||
var $ul = $('ul'), $last = $.sort(field, $ul.last()), $msg;
|
||||
($msg = $("#msg-" + field) || $ul.insertBefore($.model.clone(true), $last.next())).id = 'msg-' + field;
|
||||
$('.who', $msg)[$.text] = msg.who;
|
||||
$('.what', $msg)[$.text] = msg.what;
|
||||
$('.when', $msg)[$.text] = new Date(msg.when).toLocaleString().toLowerCase();
|
||||
$('.sort', $msg)[$.text] = field;
|
||||
if(document.body.scrollHeight - (window.scrollY + window.innerHeight) <= $last.scrollHeight + 50){
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
<div id="converse" class="hue2 page">
|
||||
<link href='https://fonts.googleapis.com/css?family=Poiret+One' rel='stylesheet' type='text/css'>
|
||||
<style>
|
||||
#converse {
|
||||
font-size: 16pt;
|
||||
}
|
||||
});
|
||||
$('.who', $('form')).value = (document.cookie.match(/alias\=(.*?)(\&|$|\;)/i)||[])[1]||'';
|
||||
$('.what', $('form')).focus();
|
||||
$('form').onsubmit = function(e){
|
||||
var msg = {when: Gun.time.is()};
|
||||
document.cookie = ('alias=' + (msg.who = $('.who', this).value || 'user' + Gun.text.random(6)));
|
||||
msg.what = $('.what', this).value || '';
|
||||
if(msg.what){ chat.path(msg.when + '_' + Gun.text.random(4)).put(msg) }
|
||||
$('.what', this).value = '';
|
||||
return (e && e.preventDefault()), false;
|
||||
};
|
||||
</script>
|
||||
#converse .box {
|
||||
margin-bottom: 0.2em;
|
||||
padding: 1em;
|
||||
border-radius: 0.1em;
|
||||
}
|
||||
#converse b:after {
|
||||
content: " ";
|
||||
}
|
||||
#converse li .when {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -2em;
|
||||
padding: 0.5em 1em;
|
||||
background: rgba(100%,100%,100%,0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
#converse li:hover .when {
|
||||
opacity: 1;
|
||||
right: 0em;
|
||||
}
|
||||
.poiret {
|
||||
font-family: 'Poiret One', sans-serif;
|
||||
}
|
||||
.large {
|
||||
font-size: 200%;
|
||||
}
|
||||
#converse .what, #converse .who {
|
||||
cursor: text;
|
||||
outline: none;
|
||||
display: inline;
|
||||
min-width: 1em;
|
||||
padding-left: 1px;
|
||||
}
|
||||
[contentEditable=true]:empty:not(:focus):before{
|
||||
content:attr(data-text)
|
||||
}
|
||||
</style>
|
||||
<div class="pad">
|
||||
<div class="poiret large rubric whitet" style="margin-bottom: 0.5em;">Have a Conversation...</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li class="none"></li>
|
||||
</ul>
|
||||
<form class="white huet2 box">
|
||||
<div>
|
||||
<div class="send hue2 right whitet box act" style="margin: 0 0 0.4em 0.4em; padding: 0.2em 0.5em;">send</div>
|
||||
<b class="jot left who" contenteditable="true" data-text="Name" style="margin-top: 0.5em; margin-right: 0.5em;"></b>
|
||||
<p class="jot left what" contenteditable="true" data-text="Write a message..." style="margin-top: 0.5em;"></p>
|
||||
</div>
|
||||
</form>
|
||||
<div class="model">
|
||||
<li class="white huet2 box"><div class="when"></div><b class="who"></b><p class="what"></p><span class="sort none">0</span></li>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script>
|
||||
var gun = Gun(location.origin+'/gun');
|
||||
var chat = gun.get('ex/test3/converse');
|
||||
chat.map().val(function(msg, field){
|
||||
var ul = $('ul'), last = sort(field, ul.children('li').last()), li;
|
||||
li = $($("#msg-" + field)[0] || $('.model li').clone(true).attr('id', 'msg-'+field).insertAfter(last));
|
||||
li.find('.who').text(msg.who);
|
||||
li.find('.what').text(msg.what);
|
||||
li.find('.sort').text(field);
|
||||
var time = new Date(msg.when);
|
||||
li.find('.when').text(time.toDateString() +', '+ time.toLocaleTimeString());
|
||||
$('body').stop(true, true).animate({scrollTop: ul.height()});
|
||||
});
|
||||
$("form .send").on('click', submit);
|
||||
$("form .what").on('keydown', function(e){
|
||||
if(e.which == 13){ submit(e) }
|
||||
});
|
||||
function submit(e){
|
||||
e.preventDefault();
|
||||
var msg = {when: Gun.time.is()};
|
||||
msg.who = $('form .who').text();
|
||||
if(!msg.who){ $('form .who').text(msg.who = 'user'+Gun.text.random(3)) }
|
||||
msg.what = $('form .what').text();
|
||||
if(!msg.what){ return }
|
||||
chat.get(msg.when+'r'+Gun.text.random(3)).put(msg);
|
||||
$('form .what').text('');
|
||||
}
|
||||
function sort(g, e){
|
||||
return (parseFloat(g) >= parseFloat($(e).find('.sort').text() || -Infinity))? e : sort(g, e.prev());
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,10 +0,0 @@
|
||||
function spam(){
|
||||
spam.start = true; spam.lock = false;
|
||||
if(spam.count >= 100){ return }
|
||||
var $f = $('form');
|
||||
$('.what', $f).value = ++spam.count;
|
||||
$f.onsubmit();
|
||||
setTimeout(spam, 0);
|
||||
}; spam.count = 0; spam.lock = true;
|
||||
|
||||
alert("ADD THIS LINE TO THE TOP OF THE MAP.VAL CALLBACK: `if(!spam.lock && !spam.start){ spam() }`");
|
@ -1,30 +0,0 @@
|
||||
console.log("If modules not found, run `npm install` in /example folder!"); // git subtree push -P examples heroku master // OR // git subtree split -P examples master && git push heroku [['HASH']]:master --force
|
||||
var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 80;
|
||||
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
|
||||
var Gun = require('gun');
|
||||
var gun = Gun({
|
||||
file: 'data.json',
|
||||
s3: {
|
||||
key: '', // AWS Access Key
|
||||
secret: '', // AWS Secret Token
|
||||
bucket: '' // The bucket you want to save into
|
||||
}
|
||||
});
|
||||
|
||||
gun.wsp(app/*, function(req, res, next){
|
||||
console.log("auth!", req, req.body['#']);
|
||||
if('get' === req.method){
|
||||
if('example/todo/data' === req.body['#']){
|
||||
next(req, res);
|
||||
}
|
||||
}
|
||||
if('put' === req.method){
|
||||
res({body: {err: "Permission denied!"}});
|
||||
}
|
||||
}*/);
|
||||
app.use(express.static(__dirname)).listen(port);
|
||||
|
||||
console.log('Server started on port ' + port + ' with /gun');
|
19
examples/game/nts.html
Normal file
19
examples/game/nts.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="text-align: center;">
|
||||
<h1 id="when" style="font-size: 7vw; margin-top: 43vh;"></h1>
|
||||
</body>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/lib/nts.js"></script>
|
||||
<script>
|
||||
window.gun = Gun(location.origin+'/gun');
|
||||
requestAnimationFrame(function now(){
|
||||
requestAnimationFrame(now);
|
||||
var time = new Date(Gun.state());
|
||||
var print = time.toLocaleString() +' '+ (time.getMilliseconds()/1000).toFixed(3).slice(1);
|
||||
when.innerHTML = print;
|
||||
});
|
||||
</script>
|
||||
</html>
|
254
examples/game/space.html
Normal file
254
examples/game/space.html
Normal file
@ -0,0 +1,254 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<div id="area">
|
||||
<div id="me" class="ship">
|
||||
<div class="laser"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="../jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/lib/nts.js"></script>
|
||||
<script>
|
||||
// Thanks to https://github.com/dmcinnes/HTML5-Asteroids
|
||||
//var gun = Gun();
|
||||
var gun = Gun(location.origin+'/gun');
|
||||
var game = {gun: gun.get('example/game/space'), area: {}, ships: {}};
|
||||
game.keys = {38: 'up', 37: 'left', 39: 'right', 40: 'down', 32: 'space'};
|
||||
$(document).on('keydown', function(e){
|
||||
//e.preventDefault();
|
||||
var key = e.keyCode, me;
|
||||
game.keys[key = game.keys[key]] = true;
|
||||
if(!(me = game.me)){ return }
|
||||
me.last = game.now;
|
||||
if('space' === key){ game.shoot(game.me) }
|
||||
});
|
||||
$(document).on('keyup', function(e){
|
||||
//e.preventDefault();
|
||||
game.sync();
|
||||
game.keys[game.keys[e.keyCode]] = false;
|
||||
});
|
||||
game.shoot = function(ship, when){
|
||||
if(!ship || ship.l){ return }
|
||||
if(!when && ship.gun && ship.data){
|
||||
ship.data.l = game.now;
|
||||
game.sync(true);
|
||||
return;
|
||||
}
|
||||
if(when + 250 < game.now){ return }
|
||||
ship.l = true;
|
||||
ship.$.children('.laser').show();
|
||||
setTimeout(function(){
|
||||
ship.$.children('.laser').hide();
|
||||
setTimeout(function(){
|
||||
ship.l = false;
|
||||
}, 250);
|
||||
}, 250 - (game.now - when));
|
||||
}
|
||||
game.ship = function(d, el){
|
||||
if(!d){ // spawn our ship
|
||||
var id = Gun.text.random(1, 'abcdefghijklmno');
|
||||
game.me = game.ships[id] = {data: d = {id: id, t: game.now}};
|
||||
game.me.gun = game.gun.get('players').get(d.id).put(d);
|
||||
return;
|
||||
}
|
||||
if(!d.id){ return }
|
||||
if(!game.ships[d.id]){
|
||||
game.ships[d.id] = {};
|
||||
}
|
||||
var s = game.ships[d.id];
|
||||
s.t = d.t || (d.t = 0);
|
||||
s.x = d.x || (d.x = game.area.x * Math.random());
|
||||
s.y = d.y || (d.y = game.area.y * Math.random());
|
||||
s.r = d.r || (d.r = 0);
|
||||
s.vx = d.vx || (d.vx = 0);
|
||||
s.vy = d.vy || (d.vy = 0);
|
||||
s.vr = d.vr || (d.vr = 0);
|
||||
s.ax = s.ax || 0;
|
||||
s.ay = s.ay || 0;
|
||||
s.ar = s.ar || 0;
|
||||
s.data = d;
|
||||
s.$ = s.$ || (s.gun? ($('#me'))
|
||||
: $('#me').clone(true).attr('id', d.id).appendTo('#area'));
|
||||
if(!s.l){
|
||||
game.shoot(s, d.l);
|
||||
}
|
||||
s.frame = s.frame || function(t, now){
|
||||
if(s.gun){
|
||||
s.fly(t, now);
|
||||
}
|
||||
if(s.calc(t, now)){ return }
|
||||
s.draw();
|
||||
}
|
||||
var keys = game.keys;
|
||||
var area = game.area;
|
||||
s.fly = s.fly || function(t, now){
|
||||
if(keys.left){
|
||||
s.r += -6;
|
||||
} else
|
||||
if(keys.right) {
|
||||
s.r += 6;
|
||||
}
|
||||
if(keys.up){
|
||||
var rad = ((s.r - 90) * Math.PI)/180;
|
||||
s.ax = 0.0001 * Math.cos(rad);
|
||||
s.ay = 0.0001 * Math.sin(rad);
|
||||
} else {
|
||||
s.ax = 0;
|
||||
s.ay = 0;
|
||||
}
|
||||
|
||||
Gun.obj.map(game.ships, function(ship){
|
||||
if(ship.gun){ return }
|
||||
if(!ship.l){ return }
|
||||
if(ship.x-50 <= s.x && s.x <= ship.x+50
|
||||
&& ship.y-50 <= s.y && s.y <= ship.y+50){
|
||||
s.data.t = -1;
|
||||
game.sync(true);
|
||||
s.boom = true;
|
||||
}
|
||||
});
|
||||
|
||||
s.vx += s.ax * t;
|
||||
s.x += s.vx * t;
|
||||
s.vy += s.ay * t;
|
||||
s.y += s.vy * t;
|
||||
var data = s.data;
|
||||
if(!data){ return }
|
||||
data.r = s.r;
|
||||
data.vx = s.vx;
|
||||
data.x = s.x;
|
||||
data.vy = s.vy;
|
||||
data.y = s.y;
|
||||
if(data.t < 0){ return }
|
||||
data.t = now;
|
||||
s.t = data.t;
|
||||
}
|
||||
s.calc = s.calc || function(t, now){
|
||||
var d = s.data;
|
||||
var dt = (now - d.t) || 0;
|
||||
if(dt > 30 * 1000){
|
||||
Gun.obj.del(game.ships, d.id);
|
||||
s.$.remove();
|
||||
return true;
|
||||
}
|
||||
if(!d){ return }
|
||||
var speed = Math.sqrt(d.vx * d.vx + d.vy * d.vy);
|
||||
if(speed > 0.15){
|
||||
s.vy = d.vy = d.vy / speed * 0.15;
|
||||
s.vx = d.vx = d.vx / speed * 0.15;
|
||||
}
|
||||
s.x = d.x + d.vx * dt;
|
||||
s.y = d.y + d.vy * dt;
|
||||
|
||||
s.x = s.x % area.x;
|
||||
if(s.x < 0){
|
||||
s.x += area.x;
|
||||
}
|
||||
s.y = s.y % area.y;
|
||||
if(s.y < 0){
|
||||
s.y += area.y;
|
||||
}
|
||||
}
|
||||
s.draw = s.draw || function(){
|
||||
s.css = 'rotate('+s.r+'deg)';
|
||||
s.$.css({left: s.x, top: s.y, transform: s.css});
|
||||
}
|
||||
return s;
|
||||
}
|
||||
localStorage.clear();
|
||||
game.sync = function(shoot){
|
||||
var me = game.me;
|
||||
if(!me || me.boom){ return }
|
||||
var keys = game.keys;
|
||||
if(shoot || keys.up || keys.right || keys.left || keys.down){
|
||||
var data = Gun.obj.to(me.data);
|
||||
data.x = data.x / game.area.x;
|
||||
data.y = data.y / game.area.y;
|
||||
me.gun.put(data);
|
||||
}
|
||||
}
|
||||
game.frame = window.requestAnimationFrame || setTimeout;
|
||||
game.resize = function(){
|
||||
game.area.x = $('#area').innerWidth();
|
||||
game.area.y = $('#area').innerHeight();
|
||||
}
|
||||
$(window).on('resize', game.resize);
|
||||
game.start = function(){
|
||||
game.now = Gun.state();
|
||||
game.resize();
|
||||
game.gun.get('players').map().on(function(data, id){
|
||||
data = Gun.obj.copy(data);
|
||||
data.x = data.x * game.area.x;
|
||||
data.y = data.y * game.area.y;
|
||||
data.id = data.id || id;
|
||||
game.ship(data);
|
||||
});
|
||||
game.ship();
|
||||
var frame = game.frame, ships = game.ships;
|
||||
var last = game.now, now, diff, delta;
|
||||
setInterval(game.sync, 99);
|
||||
frame(function next(t){
|
||||
frame(next, 1000/60);
|
||||
now = game.now = Gun.state();
|
||||
diff = now - last;
|
||||
last = now;
|
||||
Gun.obj.map(ships, function(ship){
|
||||
if(!ship.frame){ return }
|
||||
ship.frame(diff, now);
|
||||
});
|
||||
}, 1000/60);
|
||||
}
|
||||
$(function(){
|
||||
game.start();
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #111;
|
||||
}
|
||||
html, body, div {
|
||||
position: relative;
|
||||
}
|
||||
#area {
|
||||
width: 95%;
|
||||
width: 1024px;
|
||||
height: 768px;
|
||||
margin: 0 auto;
|
||||
background: black;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ship {
|
||||
position: absolute;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-bottom: 15px solid red;
|
||||
transform-origin: 50% 50%;
|
||||
color: white;
|
||||
}
|
||||
#me {
|
||||
border-bottom: 15px solid limegreen;
|
||||
}
|
||||
.boom {
|
||||
border: 1vmax dotted yellow;
|
||||
border-bottom: 1vmax dotted yellow;
|
||||
height: 5vmax;
|
||||
width: 1vmax;
|
||||
}
|
||||
.laser {
|
||||
display: none;
|
||||
position: relative;
|
||||
background: transparent;
|
||||
border: 2px dotted yellow;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
top: -50px;
|
||||
left: -50px;
|
||||
}
|
||||
</style>
|
||||
</html>
|
@ -6,18 +6,23 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Examples Directory <button style="float: right;" onclick="localStorage.clear()">Clear Local Storage</button></h1>
|
||||
<!-- h1>Examples Directory <button style="float: right;" onclick="localStorage.clear()">Clear Local Storage</button></h1 -->
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
border: none;
|
||||
border-top: ridge 2em skyblue;
|
||||
b-order-top: ridge 2em skyblue;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
<a href="/todo/index.html"><iframe src="/todo/index.html"></iframe></a>
|
||||
<a href="/json/index.html"><iframe src="/json/index.html"></iframe></a>
|
||||
<!-- a href="/json/index.html"><iframe src="/json/index.html"></iframe></a -->
|
||||
<a href="/chat/index.html"><iframe src="/chat/index.html"></iframe></a>
|
||||
<script src="../gun.js"></script>
|
||||
<!-- script src="../gun.js"></script -->
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,175 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>gun - react examples</title>
|
||||
<style>
|
||||
html, body { font-size: 14pt; padding: 10px 2.5%;}
|
||||
.hide { display: none; }
|
||||
form .who { width: 10%; }
|
||||
form .what { width: 80%; }
|
||||
ul { list-style: none; padding: 0; }
|
||||
ul .when {color: #555; font-size: 12pt; float: right; display: none; }
|
||||
li:hover .when {display: inline;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.23.1/babel.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.js"></script>
|
||||
<script src="../gun.js"></script>
|
||||
|
||||
<script type="text/babel" data-presets="react,latest,stage-0">
|
||||
const { Component } = React
|
||||
const { render } = ReactDOM
|
||||
const todos = Gun().get('todos')
|
||||
const formatTodos = todos => Object.keys(todos)
|
||||
.map(key => ({ key, val: todos[key] }))
|
||||
.filter(t => Boolean(t.val) && t.key !== '_')
|
||||
|
||||
class Todos extends Component {
|
||||
constructor() {
|
||||
super()
|
||||
this.state = {newTodo: '', todos: []}
|
||||
}
|
||||
componentWillMount() {
|
||||
todos.on(todos => this.setState({
|
||||
todos: formatTodos(todos)
|
||||
}))
|
||||
}
|
||||
add = _ => {
|
||||
todos.path(Gun.text.random()).put(this.state.newTodo)
|
||||
this.setState({newTodo: ''})
|
||||
}
|
||||
del = key => gun.path(key).put(null)
|
||||
handleChange = e => this.setState({ newTodo: e.target.value})
|
||||
render() {
|
||||
return <div>
|
||||
<input value={this.state.newTodo} onChange={this.handleChange} />
|
||||
<button onClick={this.add}>Add</button>
|
||||
<br />
|
||||
<ul>
|
||||
{this.state.todos.map(todo => <li key={todo.key} onClick={_=>this.del(todo.key)}>{todo.val}</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
const json = Gun().get('json')
|
||||
const formatJson = json =>
|
||||
Object.keys(json)
|
||||
.map(key => ({ key, val: json[key]}))
|
||||
.filter(el => el.key !== '_')
|
||||
|
||||
class Json extends Component {
|
||||
constructor() {
|
||||
super()
|
||||
this.state = { newField: '', json: [] }
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
json.on(json => this.setState({ json: formatJson(json) }))
|
||||
}
|
||||
|
||||
edit = key => e => {
|
||||
e.preventDefault()
|
||||
json.path(key).put(e.target.value)
|
||||
}
|
||||
|
||||
add = e => {
|
||||
e.preventDefault()
|
||||
json.path(this.state.newField).put('value')
|
||||
this.setState({newField: ''})
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div>
|
||||
<ul>
|
||||
{this.state.json.map(({ key, val }) =>
|
||||
<li key={key}><b>{key}:</b> <input value={val} onChange={this.edit(key)} /></li>
|
||||
)}
|
||||
</ul>
|
||||
<form onSubmit={this.add}>
|
||||
<input value={this.state.newField} onChange={e => this.setState({ newField: e.target.value})} />
|
||||
<button onClick={this.add}>Add Field</button>
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const chat = Gun().get('chat')
|
||||
const formatMsgs = msgs => Object.keys(msgs)
|
||||
.map(key => ({ key, ...msgs[key] }))
|
||||
.filter(m => Boolean(m.when) && m.key !== '_')
|
||||
.sort((a, b) => a.when - b.when)
|
||||
.map(m => ((m.whenFmt = new Date(m.when).toLocaleString().toLowerCase()), m))
|
||||
|
||||
class Chat extends Component {
|
||||
constructor() {
|
||||
super()
|
||||
this.state = {
|
||||
newMsg: '',
|
||||
name: (document.cookie.match(/alias\=(.*?)(\&|$|\;)/i)||[])[1]||'',
|
||||
msgs: {},
|
||||
}
|
||||
}
|
||||
componentWillMount() {
|
||||
const tmpState = {}
|
||||
chat.map().val((msg, key) => {
|
||||
tmpState[key] = msg
|
||||
this.setState({msgs: Object.assign({}, this.state.msgs, tmpState)})
|
||||
})
|
||||
|
||||
}
|
||||
send = e => {
|
||||
e.preventDefault()
|
||||
const who = this.state.name || 'user' + Gun.text.random(6)
|
||||
this.setState({name: who})
|
||||
document.cookie = ('alias=' + who)
|
||||
const when = Gun.time.is()
|
||||
const key = `${when}_${Gun.text.random(4)}`
|
||||
chat.path(key).put({
|
||||
who,
|
||||
when,
|
||||
what: this.state.newMsg,
|
||||
})
|
||||
this.setState({newMsg: ''})
|
||||
}
|
||||
render() {
|
||||
const msgs = formatMsgs(this.state.msgs)
|
||||
return <div>
|
||||
<ul>
|
||||
{msgs.map(msg =>
|
||||
<li key={msg.key}><b>{msg.who}:</b> {msg.what}<span className="when">{msg.whenFmt}</span></li>
|
||||
)}
|
||||
</ul>
|
||||
<form onSubmit={this.send}>
|
||||
<input value={this.state.name} className="who" onChange={e => this.setState({ name: e.target.value})} />
|
||||
<input value={this.state.newMsg} className="what" onChange={e => this.setState({ newMsg: e.target.value})} />
|
||||
<button onClick={this.send}>Send</button>
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
const App = _ =>
|
||||
<div>
|
||||
<h1>React Examples</h1>
|
||||
<h2>Todo</h2>
|
||||
<Todos />
|
||||
<br />
|
||||
<hr />
|
||||
<h2>Chat</h2>
|
||||
<Chat />
|
||||
<br />
|
||||
<hr />
|
||||
<h2>Json</h2>
|
||||
<Json />
|
||||
</div>
|
||||
|
||||
render(<App />, document.getElementById('app'))
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
279
examples/style.css
Normal file
279
examples/style.css
Normal file
@ -0,0 +1,279 @@
|
||||
@import url(https://fonts.googleapis.com/css?family=Oxygen);
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Oxygen', 'Trebuchet MS', arial;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div, ul, li, form, p, span, input, textarea {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
-webkit-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
ul, li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 18pt;
|
||||
}
|
||||
|
||||
.model { display: none }
|
||||
.mid { margin-left: auto; margin-right: auto; }
|
||||
.row { width: 100%; }
|
||||
.col { max-width: 33em; }
|
||||
input, textarea {
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.red {
|
||||
background: #ea3224;
|
||||
}
|
||||
.green {
|
||||
background: #33cc33;
|
||||
}
|
||||
.blue {
|
||||
background: #4D79D8;
|
||||
}
|
||||
.yellow {
|
||||
background: #f2b919;
|
||||
}
|
||||
.black {
|
||||
background: black;
|
||||
}
|
||||
.white {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.redt {
|
||||
color: #ea3224;
|
||||
}
|
||||
.greent {
|
||||
color: #33cc33;
|
||||
}
|
||||
.bluet {
|
||||
color: #4D79D8;
|
||||
}
|
||||
.yellowt {
|
||||
color: #f2b919;
|
||||
}
|
||||
.blackt {
|
||||
color: black;
|
||||
}
|
||||
.whitet {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.pad {
|
||||
margin: 5% auto;
|
||||
min-width: 250px;
|
||||
width: 95%;
|
||||
max-width: 50em;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
}
|
||||
.left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.act {
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
-webkit-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rubric {
|
||||
font-size: 150%;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.jot {
|
||||
border-bottom: 1px dashed #95B2CA;
|
||||
}
|
||||
.sap {
|
||||
border-radius: 0.1em;
|
||||
}
|
||||
|
||||
.hue {
|
||||
background: #4D79D8;
|
||||
-webkit-animation: hue 900s infinite;
|
||||
animation: hue 900s infinite;
|
||||
}
|
||||
|
||||
@keyframes hue {
|
||||
0% {background: #4D79D8;}
|
||||
25% {background: #33cc33;}
|
||||
50% {background: #f2b919;}
|
||||
75% {background: #ea3224;}
|
||||
100% {background: #4D79D8;}
|
||||
} @-webkit-keyframes hue {
|
||||
0% {background: #4D79D8;}
|
||||
25% {background: #33cc33;}
|
||||
50% {background: #f2b919;}
|
||||
75% {background: #ea3224;}
|
||||
100% {background: #4D79D8;}
|
||||
}
|
||||
|
||||
.huet {
|
||||
color: #4D79D8;
|
||||
-webkit-animation: huet 900s infinite;
|
||||
animation: huet 900s infinite;
|
||||
}
|
||||
|
||||
@keyframes huet {
|
||||
0% {color: #4D79D8;}
|
||||
25% {color: #33cc33;}
|
||||
50% {color: #f2b919;}
|
||||
75% {color: #ea3224;}
|
||||
100% {color: #4D79D8;}
|
||||
} @-webkit-keyframes huet {
|
||||
0% {color: #4D79D8;}
|
||||
25% {color: #33cc33;}
|
||||
50% {color: #f2b919;}
|
||||
75% {color: #ea3224;}
|
||||
100% {color: #4D79D8;}
|
||||
}
|
||||
|
||||
.hue2 {
|
||||
background: #ea3224;
|
||||
-webkit-animation: hue2 900s infinite;
|
||||
animation: hue2 900s infinite;
|
||||
}
|
||||
|
||||
@keyframes hue2 {
|
||||
0% {background: #ea3224;}
|
||||
25% {background: #4D79D8;}
|
||||
50% {background: #33cc33;}
|
||||
75% {background: #f2b919;}
|
||||
100% {background: #ea3224;}
|
||||
} @-webkit-keyframes hue2 {
|
||||
0% {background: #ea3224;}
|
||||
25% {background: #4D79D8;}
|
||||
50% {background: #33cc33;}
|
||||
75% {background: #f2b919;}
|
||||
100% {background: #ea3224;}
|
||||
}
|
||||
|
||||
.huet2 {
|
||||
color: #ea3224;
|
||||
-webkit-animation: huet2 900s infinite;
|
||||
animation: huet2 900s infinite;
|
||||
}
|
||||
|
||||
@keyframes huet2 {
|
||||
0% {color: #ea3224;}
|
||||
25% {color: #4D79D8;}
|
||||
50% {color: #33cc33;}
|
||||
75% {color: #f2b919;}
|
||||
100% {color: #ea3224;}
|
||||
} @-webkit-keyframes huet2 {
|
||||
0% {color: #ea3224;}
|
||||
25% {color: #4D79D8;}
|
||||
50% {color: #33cc33;}
|
||||
75% {color: #f2b919;}
|
||||
100% {color: #ea3224;}
|
||||
}
|
||||
|
||||
.hue3 {
|
||||
background: #33cc33;
|
||||
-webkit-animation: hue3 900s infinite;
|
||||
animation: hue3 900s infinite;
|
||||
}
|
||||
|
||||
@keyframes hue3 {
|
||||
0% {background: #33cc33;}
|
||||
25% {background: #f2b919;}
|
||||
50% {background: #ea3224;}
|
||||
75% {background: #4D79D8;}
|
||||
100% {background: #33cc33;}
|
||||
} @-webkit-keyframes hue3 {
|
||||
0% {background: #33cc33;}
|
||||
25% {background: #f2b919;}
|
||||
50% {background: #ea3224;}
|
||||
75% {background: #4D79D8;}
|
||||
100% {background: #33cc33;}
|
||||
}
|
||||
|
||||
.huet3 {
|
||||
color: #33cc33;
|
||||
-webkit-animation: huet3 900s infinite;
|
||||
animation: huet3 900s infinite;
|
||||
}
|
||||
|
||||
@keyframes huet3 {
|
||||
0% {color: #33cc33;}
|
||||
25% {color: #f2b919;}
|
||||
50% {color: #ea3224;}
|
||||
75% {color: #4D79D8;}
|
||||
100% {color: #33cc33;}
|
||||
} @-webkit-keyframes huet3 {
|
||||
0% {color: #33cc33;}
|
||||
25% {color: #f2b919;}
|
||||
50% {color: #ea3224;}
|
||||
75% {color: #4D79D8;}
|
||||
100% {color: #33cc33;}
|
||||
}
|
||||
|
||||
.hue4 {
|
||||
background: #f2b919;
|
||||
-webkit-animation: hue4 900s infinite;
|
||||
animation: hue4 900s infinite;
|
||||
}
|
||||
|
||||
@keyframes hue4 {
|
||||
0% {background: #f2b919;}
|
||||
25% {background: #ea3224;}
|
||||
50% {background: #4D79D8;}
|
||||
75% {background: #33cc33;}
|
||||
100% {background: #f2b919;}
|
||||
} @-webkit-keyframes hue4 {
|
||||
0% {background: #f2b919;}
|
||||
25% {background: #ea3224;}
|
||||
50% {background: #4D79D8;}
|
||||
75% {background: #33cc33;}
|
||||
100% {background: #f2b919;}
|
||||
}
|
||||
|
||||
.huet4 {
|
||||
color: #f2b919;
|
||||
-webkit-animation: huet4 900s infinite;
|
||||
animation: huet4 900s infinite;
|
||||
}
|
||||
|
||||
@keyframes huet4 {
|
||||
0% {color: #f2b919;}
|
||||
25% {color: #ea3224;}
|
||||
50% {color: #4D79D8;}
|
||||
75% {color: #33cc33;}
|
||||
100% {color: #f2b919;}
|
||||
} @-webkit-keyframes huet4 {
|
||||
0% {color: #f2b919;}
|
||||
25% {color: #ea3224;}
|
||||
50% {color: #4D79D8;}
|
||||
75% {color: #33cc33;}
|
||||
100% {color: #f2b919;}
|
||||
}
|
@ -1,37 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h2>ToDo List</h2>
|
||||
|
||||
<form id="add"><input id="todo"/><button>Add</button></form>
|
||||
<ul id="todos"></ul>
|
||||
|
||||
<script src="../../gun.js"></script>
|
||||
<script> // minimal jQuery polyfill
|
||||
var $ = document.querySelector.bind(document);
|
||||
function clean(text){ return String(text).replace(/\</ig, '<') }
|
||||
</script>
|
||||
<script> // by Forrest Tait! Edited by Mark Nadal.
|
||||
var gun = Gun(location.origin + '/gun');
|
||||
var todo = gun.get('example/todo/data');
|
||||
$("#add").onsubmit = function(){
|
||||
todo.path(Gun.text.random()).put(clean($("#todo").value)); // add the HTML input's value to a random ID in the todo.
|
||||
$("#todo").value = ""; // clear out the input's value so we can add more.
|
||||
return false; // prevent the browser from reloading.
|
||||
};
|
||||
todo.on(function(list){ // subscribe and listen to all updates on the todo.
|
||||
var html = ''; // old school HTML strings! You should probably use a real template system.
|
||||
for(field in list) { // iterate over the list to generate the HTML.
|
||||
if(!list[field] || field == '_') continue; // ignore nulled out values and metadata.
|
||||
html += '<li>'
|
||||
+ clean(list[field])
|
||||
+ '<button style="float:right;" onclick=todone("'+field+'")>X</button>'
|
||||
+ '</li>';
|
||||
<div id="think" class="hue page">
|
||||
<link href='https://fonts.googleapis.com/css?family=Alegreya+Sans:300italic' rel='stylesheet' type='text/css'>
|
||||
<style>
|
||||
#think {
|
||||
font-size: 24pt;
|
||||
font-size: 6vmin;
|
||||
font-family: 'Alegreya Sans', sans-serif;
|
||||
color: white;
|
||||
}
|
||||
$("#todos").innerHTML = html; // set the HTML to our new list.
|
||||
});
|
||||
window.todone = function(field){
|
||||
todo.path(field).put(null); // null out the todo item on this field ID.
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
#think li {
|
||||
width: 90%;
|
||||
margin-top: 0.3em;
|
||||
border-bottom: 1px dashed white;
|
||||
}
|
||||
#think .add {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
line-height: 1em;
|
||||
padding: 0.5em;
|
||||
font-family: Tahoma, arial;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
#think ul, #think li {
|
||||
list-style-type: circle;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
</style>
|
||||
<div class="pad whitet" style="width: 75%;">
|
||||
<div style="margin-top: 2%;">
|
||||
<div class="rubric left center">Add a Thought...</div>
|
||||
<a href="#" class="right huet white act add">+</a>
|
||||
</div>
|
||||
<ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script src="/jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script>
|
||||
var gun = Gun(location.origin+'/gun');
|
||||
var think = gun.get('think');
|
||||
var typing, throttle;
|
||||
$('.add').on('click', function(){
|
||||
$('<li>').attr('contenteditable', true).prependTo('ul');
|
||||
});
|
||||
$(document).on('keyup', "[contenteditable=true]", function(){
|
||||
var li = $(this), id = li.attr('id');
|
||||
if(!id){
|
||||
li.attr('id', id = Gun.text.random());
|
||||
}
|
||||
typing = id;
|
||||
clearTimeout(throttle);
|
||||
throttle = setTimeout(function(){
|
||||
think.get(id).put(li.text());
|
||||
typing = false;
|
||||
},10);
|
||||
});
|
||||
think.map().on(function(thought, id){
|
||||
var li = $('#'+id)[0] || $('<li>').attr('id', id).attr('contenteditable', true).prependTo('ul');
|
||||
if(thought){
|
||||
if(id === typing){ return }
|
||||
$(li).text(thought);
|
||||
} else {
|
||||
$(li).hide();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
7
gun.js
7
gun.js
@ -549,13 +549,14 @@
|
||||
t = time();
|
||||
}
|
||||
if(last < t){
|
||||
return N = 0, last = t;
|
||||
return N = 0, last = t + State.drift;
|
||||
}
|
||||
return last = t + ((N += 1) / D);
|
||||
return last = t + ((N += 1) / D) + State.drift;
|
||||
}
|
||||
var time = Type.time.is, last = -Infinity, N = 0, D = 1000; // WARNING! In the future, on machines that are D times faster than 2016AD machines, you will want to increase D by another several orders of magnitude so the processing speed never out paces the decimal resolution (increasing an integer effects the state accuracy).
|
||||
var perf = (typeof performance !== 'undefined')? (performance.timing && performance) : false, start = (perf && perf.timing && perf.timing.navigationStart) || (perf = false);
|
||||
State._ = '>';
|
||||
State.drift = 0;
|
||||
State.ify = function(n, f, s, v, soul){ // put a field's state on a node.
|
||||
if(!n || !n[N_]){ // reject if it is not node-like.
|
||||
if(!soul){ // unless they passed a soul
|
||||
@ -673,7 +674,7 @@
|
||||
if(!(is = valid(v,f,n, at,env))){ return }
|
||||
if(!f){
|
||||
at.node = at.node || n || {};
|
||||
if(obj_has(v, Node._)){
|
||||
if(obj_has(v, Node._) && !Gun.is(v)){
|
||||
at.node._ = obj_copy(v._);
|
||||
}
|
||||
at.node = Node.soul.ify(at.node, Val.rel.is(at.rel));
|
||||
|
69
lib/nts.js
69
lib/nts.js
@ -1,25 +1,46 @@
|
||||
Gun.on('opt').event(function(gun, opt){
|
||||
if(!gun.tab || !gun.tab.request){ return }
|
||||
Gun.time.now.drift = 0;
|
||||
function ping(){
|
||||
Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){
|
||||
var NTS = {};
|
||||
NTS.start = Gun.time.now();
|
||||
gun.tab.request(url, null, function(err, reply){
|
||||
if(err || !reply || !reply.body){
|
||||
return console.log("Network Time Synchronization not supported", err, (reply || {}).body);
|
||||
}
|
||||
NTS.end = Gun.time.now();
|
||||
NTS.latency = (NTS.end - NTS.start)/2;
|
||||
if(!Gun.obj.has(reply.body, 'time')){ return }
|
||||
NTS.calc = NTS.latency + reply.body.time;
|
||||
Gun.time.now.drift -= (NTS.end - NTS.calc)/2;
|
||||
setTimeout(ping, 250);
|
||||
}, {url: {pathname: '.nts'}});
|
||||
;(function(){
|
||||
|
||||
var env;
|
||||
if(typeof global !== "undefined"){ env = global }
|
||||
if(typeof require !== "undefined"){ var Gun = require('../gun') }
|
||||
if(typeof window !== "undefined"){ var Gun = (env = window).Gun }
|
||||
|
||||
Gun.on('opt', function(at){
|
||||
this.to.next(at);
|
||||
if(at.once){ return }
|
||||
var root = at.gun;
|
||||
root.on('in', function(at){
|
||||
if(!at.NTS){
|
||||
return this.to.next(at);
|
||||
}
|
||||
if(at['@']){
|
||||
(ask[at['@']]||noop)(at);
|
||||
return;
|
||||
}
|
||||
if(env.window){
|
||||
return this.to.next(at);
|
||||
}
|
||||
this.to.next({'@': at['#'], NTS: Gun.time.is()});
|
||||
});
|
||||
}; ping();
|
||||
});
|
||||
// You need to figure out how to make me write tests for this!
|
||||
// maybe we can do human based testing where we load a HTML that just
|
||||
// prints out in BIG FONT the objectiveTime it thinks it is
|
||||
// and we open it up on a couple devices.
|
||||
|
||||
var ask = {}, noop = function(){};
|
||||
if(!env.window){ return }
|
||||
|
||||
Gun.state.drift = Gun.state.drift || 0;
|
||||
function ping(){
|
||||
var NTS = {}, ack = Gun.text.random(), msg = {'#': ack, NTS: true, gun: root};
|
||||
NTS.start = Gun.state();
|
||||
ask[ack] = function(at){
|
||||
NTS.end = Gun.state();
|
||||
Gun.obj.del(ask, ack);
|
||||
NTS.latency = (NTS.end - NTS.start)/2;
|
||||
if(!at.NTS){ return }
|
||||
NTS.calc = NTS.latency + at.NTS;
|
||||
Gun.state.drift -= (NTS.end - NTS.calc)/2;
|
||||
setTimeout(ping, 1000);
|
||||
}
|
||||
Gun.on('out', msg);
|
||||
}; ping();
|
||||
});
|
||||
// test by opening up examples/game/nts.html on devices that aren't NTP synced.
|
||||
}());
|
@ -7,5 +7,14 @@ module.exports = function serve(req, res, next){
|
||||
res.end(serve.js = serve.js || require('fs').readFileSync(__dirname + '/../gun.js'));
|
||||
return true;
|
||||
}
|
||||
if(0 <= req.url.indexOf('gun/')){
|
||||
res.writeHead(200, {'Content-Type': 'text/javascript'});
|
||||
var path = __dirname + '/../' + req.url.split('/').slice(2).join('/'), file;
|
||||
try{file = require('fs').readFileSync(path)}catch(e){}
|
||||
if(file){
|
||||
res.end(file);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return next();
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
;(function(){
|
||||
var Gun = require('../gun');
|
||||
Gun.serve = require('./serve');
|
||||
require('./nts');
|
||||
require('./s3');
|
||||
try{require('./uws');}catch(e){require('./wsp/server');}
|
||||
require('./file');
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gun",
|
||||
"version": "0.6.7",
|
||||
"version": "0.6.8",
|
||||
"description": "Graph engine",
|
||||
"main": "index.js",
|
||||
"browser": "gun.min.js",
|
||||
|
Loading…
x
Reference in New Issue
Block a user