remove examples directoryr
parent
72e308994d
commit
31ec784de6
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>What can be built on top of CryptPad?</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="/examples/form/">forms</a></li>
|
||||
<li><a href="/examples/text/">text</a></li>
|
||||
<li><a href="/examples/board/">kanban board</a></li>
|
||||
<!-- <li><a href="/examples/json/">json objects</a></li> -->
|
||||
<li><a href="/examples/read/">ajax-like get/put behaviour</a></li>
|
||||
<li><a href="/examples/render/">render markdown content as html</a></li>
|
||||
<li><a href="/examples/style/">edit a page's style tag</a></li>
|
||||
</ul>
|
||||
|
@ -1,125 +0,0 @@
|
||||
# Realtime Lists and Maps
|
||||
|
||||
Our realtime list/map API has some limitations.
|
||||
|
||||
## Datatype Serialization
|
||||
|
||||
Only datatypes which can be serialized via `JSON.parse(JSON.stringify(yourObject))` will be preserved.
|
||||
|
||||
This means the following types can be serialized:
|
||||
|
||||
1. strings
|
||||
2. objects
|
||||
3. arrays
|
||||
4. booleans
|
||||
5. numbers
|
||||
6. null
|
||||
|
||||
While these cannot be serialized:
|
||||
|
||||
1. undefined
|
||||
2. symbol
|
||||
|
||||
## Object Interaction
|
||||
|
||||
Only 'get' and 'set' methods are supported.
|
||||
This is because we need to limit the operations we support to those supported by all browsers we might use.
|
||||
|
||||
Currently that means we can't rely on `in`, `delete`, or anything other than a `get`/`set` operation to behave as expected.
|
||||
Treat all other features as `Undefined Behaviour`.
|
||||
|
||||
> Your mileage may vary
|
||||
|
||||
`set` methods include all of the [assignment operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Exponentiation_assignment).
|
||||
|
||||
```
|
||||
// where 'x' is the realtime object `{}`
|
||||
|
||||
// assignment
|
||||
x.n = 5;
|
||||
|
||||
x.n += 3;
|
||||
x.n++;
|
||||
++x.n;
|
||||
|
||||
x.a = 5;
|
||||
x.b = 3;
|
||||
x.a *= x.b++;
|
||||
x // {a: 15, b: 4, n: 10}
|
||||
```
|
||||
|
||||
Instead of `delete`, assign `undefined`.
|
||||
`delete` will remove an attribute locally, but the deletion will not propogate to other clients until your next serialization.
|
||||
This is potentially problematic, as it can result in poorly formed patches.
|
||||
|
||||
### Object and array methods
|
||||
|
||||
methods which do not directly use setters and getters can be problematic:
|
||||
|
||||
`Array.push` behaves correctly, however, `Array.pop` does not.
|
||||
|
||||
|
||||
## Deep Equality
|
||||
|
||||
Normally in Javascript objects are passed by reference.
|
||||
That means you can do things like this:
|
||||
|
||||
```
|
||||
var a = {x: 5};
|
||||
var b = a;
|
||||
|
||||
// true
|
||||
console.log(a === b);
|
||||
```
|
||||
|
||||
Using the realtime list/map API, objects are serialized, and are therefore copied by value.
|
||||
|
||||
Since objects are deserialized and created on each client, you will not be able to rely on this kind of equality across objects, despite their having been created in this fashion.
|
||||
|
||||
Object equality _might_ work if the comparison is performed on the same client that initially created the object, but relying on this kind of behaviour is not advisable.
|
||||
|
||||
## Listeners
|
||||
|
||||
You can add a listener to an attribute (via its path relative to the root realtime object).
|
||||
|
||||
There are various types of listeners
|
||||
|
||||
* change
|
||||
* remove
|
||||
* disconnect
|
||||
* ready
|
||||
|
||||
### Semantics
|
||||
|
||||
Suppose you have a realtime object `A` containing nested structures.
|
||||
|
||||
```
|
||||
{
|
||||
a: {
|
||||
b: {
|
||||
c: 5
|
||||
}
|
||||
},
|
||||
d: {
|
||||
e: [
|
||||
1,
|
||||
4,
|
||||
9
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you want to be alerted whenever the second element in the array `e` within `d` changes, you can attach a listener like so:
|
||||
|
||||
```
|
||||
A.on('change', ['d', 'e', 1], function (oldval, newval, path, rootObject) {
|
||||
/* do something with these values */
|
||||
console.log("value changes from %s to %s", oldval, newval);
|
||||
});
|
||||
```
|
||||
|
||||
## Known Bugs
|
||||
|
||||
there is currently an issue with popping the last element of an array.
|
||||
|
@ -1,50 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
|
||||
<style>
|
||||
html, body{
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
form {
|
||||
border: 3px solid black;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
font-weight: bold !important;
|
||||
font-size: 18px !important;
|
||||
}
|
||||
|
||||
input[type="text"]
|
||||
{
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
width: 80%;
|
||||
height: 3em;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
|
||||
}
|
||||
textarea {
|
||||
width: 80%;
|
||||
height: 40vh;
|
||||
}
|
||||
div#content {
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<p>The field below behaves like a <a target="_blank" href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a>, with the realtime object created by this page exposed as the value <code>x</code></p>
|
||||
<p>Open your browser's console to see the output.</p>
|
||||
<input type="text" name="repl" placeholder="Value" autofocus><br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,76 +0,0 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/api/config',
|
||||
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
||||
'/bower_components/chainpad-crypto/crypto.js',
|
||||
'/common/cryptpad-common.js'
|
||||
], function ($, Config, RtListMap, Crypto, Common) {
|
||||
|
||||
var secret = Common.getSecrets();
|
||||
|
||||
var config = {
|
||||
websocketURL: Config.websocketURL,
|
||||
channel: secret.channel,
|
||||
//cryptKey: secret.key,
|
||||
data: {},
|
||||
crypto: Crypto.createEncryptor(secret.key)
|
||||
};
|
||||
|
||||
var module = window.APP = {};
|
||||
|
||||
var $repl = $('[name="repl"]');
|
||||
|
||||
var setEditable = module.setEditable = function (bool) {
|
||||
[$repl].forEach(function ($el) {
|
||||
$el.attr('disabled', !bool);
|
||||
});
|
||||
};
|
||||
|
||||
setEditable(false);
|
||||
|
||||
var rt = module.rt = RtListMap.create(config);
|
||||
rt.proxy.on('create', function (info) {
|
||||
console.log("initializing...");
|
||||
window.location.hash = info.channel + secret.key;
|
||||
}).on('ready', function () {
|
||||
console.log("...your realtime object is ready");
|
||||
|
||||
rt.proxy
|
||||
// on(event, path, cb)
|
||||
.on('change', [], function (o, n, p) {
|
||||
console.log("root change event firing for path [%s]: %s => %s", p.join(','), o, n);
|
||||
})
|
||||
.on('remove', [], function (o, p) {
|
||||
console.log("Removal of value [%s] at path [%s]", o, p.join(','));
|
||||
})
|
||||
.on('change', ['a', 'b', 'c'], function (o, n, p) {
|
||||
console.log("Deeper change event at [%s]: %s => %s", p.join(','), o, n);
|
||||
console.log("preventing propogation...");
|
||||
return false;
|
||||
})
|
||||
// on(event, cb)
|
||||
.on('disconnect', function () {
|
||||
setEditable(false);
|
||||
window.alert("Network connection lost");
|
||||
});
|
||||
|
||||
// set up user interface hooks
|
||||
$repl.on('keyup', function (e) {
|
||||
if (e.which === 13 /* enter keycode */) {
|
||||
var value = $repl.val();
|
||||
|
||||
if (!value.trim()) { return; }
|
||||
|
||||
console.log("evaluating `%s`", value);
|
||||
var x = rt.proxy;
|
||||
x = x; // LOL jshint says this is unused otherwise <3
|
||||
|
||||
console.log('> ', eval(value)); // jshint ignore:line
|
||||
console.log();
|
||||
$repl.val('');
|
||||
}
|
||||
});
|
||||
|
||||
setEditable(true);
|
||||
});
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="cp slide">
|
||||
<head>
|
||||
<title>CryptPad</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="iframe-container">
|
||||
<iframe id="pad-iframe"></iframe><script src="/common/noscriptfix.js"></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,8 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
</head>
|
||||
<body>
|
||||
<h1>PEWPEW
|
@ -1,50 +0,0 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/common/cryptpad-common.js',
|
||||
'/common/pinpad.js'
|
||||
], function ($, Cryptpad, Pinpad) {
|
||||
window.APP = {
|
||||
Cryptpad: Cryptpad,
|
||||
};
|
||||
|
||||
var synchronize = function (call) {
|
||||
// provide a sorted list of unique channels
|
||||
var list = Cryptpad.getCanonicalChannelList();
|
||||
|
||||
var localHash = call.hashChannelList(list);
|
||||
var serverHash;
|
||||
|
||||
call.getFileListSize(function (e, bytes) {
|
||||
if (e) { return void console.error(e); }
|
||||
console.log("total %sK bytes used", bytes / 1000);
|
||||
});
|
||||
|
||||
call.getServerHash(function (e, hash) {
|
||||
if (e) { return void console.error(e); }
|
||||
serverHash = hash;
|
||||
|
||||
if (serverHash === localHash) {
|
||||
return console.log("all your pads are pinned. There is nothing to do");
|
||||
}
|
||||
|
||||
call.reset(list, function (e, response) {
|
||||
if (e) { return console.error(e); }
|
||||
else {
|
||||
return console.log('reset pin list. new hash is [%s]', response);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$(function () {
|
||||
Cryptpad.ready(function () {
|
||||
var network = Cryptpad.getNetwork();
|
||||
var proxy = Cryptpad.getStore().getProxy().proxy;
|
||||
|
||||
Pinpad.create(network, proxy, function (e, call) {
|
||||
if (e) { return void console.error(e); }
|
||||
synchronize(call);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,33 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
|
||||
<link rel="icon" type="image/png"
|
||||
href="/customize/main-favicon.png"
|
||||
|
||||
data-main-favicon="/customize/main-favicon.png"
|
||||
data-alt-favicon="/customize/alt-favicon.png"
|
||||
id="favicon" />
|
||||
<style>
|
||||
input {
|
||||
width: 50vw;
|
||||
padding: 15px;
|
||||
}
|
||||
pre {
|
||||
max-width: 90vw;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<input id="target" type="text" value="/1/edit/xvhI6k6n7qYEtNL8cAv5zw/a4KKGGDY0S8GDj6m9iumX5E4"></input>
|
||||
<button id="get">get</button>
|
||||
<hr />
|
||||
|
||||
<textarea id="putter" type="text"></textarea>
|
||||
<button id="put">put</button>
|
||||
|
||||
<button id="open">open</button>
|
@ -1,32 +0,0 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/common/cryptget.js'
|
||||
], function ($, Crypt) {
|
||||
var $target = $('#target');
|
||||
|
||||
var useDoc = function (err, doc) {
|
||||
if (err) { return console.error(err); }
|
||||
//console.log(doc);
|
||||
$('#putter').val(doc);
|
||||
};
|
||||
|
||||
$('#get').click(function () {
|
||||
var val = $target.val();
|
||||
if (!val.trim()) { return; }
|
||||
Crypt.get(val, useDoc);
|
||||
});
|
||||
|
||||
$('#put').click(function () {
|
||||
var hash = $target.val().trim();
|
||||
Crypt.put(hash, $('#putter').val(), function (e) {
|
||||
if (e) { console.error(e); }
|
||||
$('#get').click();
|
||||
});
|
||||
});
|
||||
|
||||
$('#open').click(function () {
|
||||
window.open('/code/#' + $target.val());
|
||||
});
|
||||
|
||||
if (window.location.hash) { Crypt.get(void 0, useDoc); }
|
||||
});
|
@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="stylesheet" href="render-sd.css" />
|
||||
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
|
||||
<style>
|
||||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body { overflow-y: auto; }
|
||||
|
||||
#inner {
|
||||
display: fixed;
|
||||
width: 95%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
|
||||
margin: 0px auto;
|
||||
padding: 0px;
|
||||
}
|
||||
img { max-width: 100%; }
|
||||
code { font-family: monospace; }
|
||||
|
||||
blockquote, p, pre, code, li { font-size: 20px; }
|
||||
table, thead, tbody, th, tr, td{
|
||||
border: 1pt solid #586e75;
|
||||
background-color: #002b36;
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target">
|
||||
<div id="inner"></div>
|
||||
</div>
|
@ -1,104 +0,0 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/api/config',
|
||||
'/bower_components/chainpad-netflux/chainpad-netflux.js',
|
||||
'/bower_components/chainpad-crypto/crypto.js',
|
||||
'/bower_components/marked/marked.min.js',
|
||||
'/bower_components/hyperjson/hyperjson.js',
|
||||
'/common/cryptpad-common.js',
|
||||
'/bower_components/diff-dom/diffDOM.js',
|
||||
], function ($, Config, Realtime, Crypto, Marked, Hyperjson, Cryptpad) {
|
||||
var DiffDom = window.diffDOM;
|
||||
|
||||
var secret = Cryptpad.getSecrets();
|
||||
|
||||
// set markdown rendering options :: strip html to prevent XSS
|
||||
Marked.setOptions({
|
||||
sanitize: true
|
||||
});
|
||||
|
||||
var module = window.APP = { };
|
||||
|
||||
var $target = module.$target = $('#target');
|
||||
|
||||
var config = {
|
||||
websocketURL: Config.websocketURL,
|
||||
channel: secret.channel,
|
||||
crypto: Crypto.createEncryptor(secret.key)
|
||||
};
|
||||
|
||||
var draw = window.draw = (function () {
|
||||
var target = $target[0],
|
||||
inner = $target.find('#inner')[0];
|
||||
|
||||
if (!target) { throw new Error(); }
|
||||
var DD = new DiffDom({});
|
||||
|
||||
return function (md) {
|
||||
var rendered = Marked(md||"");
|
||||
// make a dom
|
||||
var New = $('<div id="inner">'+rendered+'</div>')[0];
|
||||
|
||||
var patches = (DD).diff(inner, New);
|
||||
DD.apply(inner, patches);
|
||||
return patches;
|
||||
};
|
||||
}());
|
||||
|
||||
var redrawTimeout;
|
||||
var lazyDraw = function (md) {
|
||||
if (redrawTimeout) { clearTimeout(redrawTimeout); }
|
||||
redrawTimeout = setTimeout(function () {
|
||||
draw(md);
|
||||
}, 450);
|
||||
};
|
||||
|
||||
var initializing = true;
|
||||
|
||||
config.onInit = function (info) {
|
||||
window.location.hash = info.channel + secret.key;
|
||||
module.realtime = info.realtime;
|
||||
};
|
||||
|
||||
var getContent = function (userDoc) {
|
||||
try {
|
||||
var parsed = JSON.parse(userDoc);
|
||||
if (typeof(parsed.content) !== 'string') {
|
||||
throw new Error();
|
||||
}
|
||||
return parsed.content;
|
||||
} catch (err) {
|
||||
return userDoc;
|
||||
}
|
||||
};
|
||||
|
||||
// when your editor is ready
|
||||
config.onReady = function () {
|
||||
console.log("Realtime is ready!");
|
||||
var userDoc = module.realtime.getUserDoc();
|
||||
lazyDraw(getContent(userDoc));
|
||||
initializing = false;
|
||||
};
|
||||
|
||||
// when remote editors do things...
|
||||
config.onRemote = function () {
|
||||
if (initializing) { return; }
|
||||
var userDoc = module.realtime.getUserDoc();
|
||||
lazyDraw(getContent(userDoc));
|
||||
};
|
||||
|
||||
config.onLocal = function () {
|
||||
// we're not really expecting any local events for this editor...
|
||||
/* but we might add a second pane in the future so that you don't need
|
||||
a second window to edit your markdown */
|
||||
if (initializing) { return; }
|
||||
var userDoc = module.realtime.getUserDoc();
|
||||
lazyDraw(userDoc);
|
||||
};
|
||||
|
||||
config.onAbort = function () {
|
||||
window.alert("Network Connection Lost");
|
||||
};
|
||||
|
||||
Realtime.start(config);
|
||||
});
|
@ -1,116 +0,0 @@
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
|
||||
/*background-color: #073642;*/
|
||||
color: #839496;
|
||||
|
||||
font-family: 'PT Sans', sans-serif;
|
||||
}
|
||||
body {
|
||||
background-color: #002b36;
|
||||
}
|
||||
|
||||
|
||||
a:focus {
|
||||
outline: thin dotted;
|
||||
}
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
code,
|
||||
pre {
|
||||
font-family: monospace, serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
q {
|
||||
quotes: "\201C" "\201D" "\2018" "\2019";
|
||||
}
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
pre,
|
||||
code {
|
||||
font-family: 'Inconsolata', sans-serif;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'PT Sans Narrow', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
code {
|
||||
background-color: #073642;
|
||||
padding: 2px;
|
||||
}
|
||||
a {
|
||||
color: #b58900;
|
||||
}
|
||||
a:visited {
|
||||
color: #cb4b16;
|
||||
}
|
||||
a:hover {
|
||||
color: #cb4b16;
|
||||
}
|
||||
h1 {
|
||||
color: #d33682;
|
||||
}
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #859900;
|
||||
}
|
||||
pre {
|
||||
background-color: #002b36;
|
||||
color: #839496;
|
||||
border: 1pt solid #586e75;
|
||||
box-shadow: 5pt 5pt 8pt #073642;
|
||||
}
|
||||
pre code {
|
||||
background-color: #002b36;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.8em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 2.4em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
h4 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
h5 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
h6 {
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
Loading…
Reference in New Issue