updated examples!

This commit is contained in:
Mark Nadal 2017-03-27 23:36:04 -07:00
parent f43a0212b0
commit c804df9b77
14 changed files with 793 additions and 340 deletions

View File

@ -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>

View File

@ -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() }`");

View File

@ -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
View 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
View 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>

View File

@ -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>

View File

@ -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
View 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;}
}

View File

@ -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, '&lt;') }
</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
View File

@ -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));

View File

@ -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.
}());

View File

@ -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();
}

View File

@ -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');

View 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",