Merge branch 'better-slides'

pull/1/head
ansuz 8 years ago
commit 8e86be81b2

@ -72,9 +72,7 @@
<th>Link</th>
<th>Created</th>
<th>Last Accessed</th>
<th class="table-refresh" title="refresh list">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 861.143 861.144" style="enable-background:new 0 0 861.143 861.144;" xml:space="preserve"><path d="M803.661,613.847c21.129-49.956,31.842-102.991,31.842-157.634c0-46.664-7.883-92.431-23.43-136.031 c-15.025-42.134-36.846-81.294-64.859-116.393c-27.734-34.751-60.746-64.539-98.117-88.534 c-38.072-24.445-79.621-42.192-123.492-52.748c-28.191-6.782-56.543,10.571-63.326,38.761s10.572,56.542,38.762,63.325 c64.291,15.47,122.572,52.651,164.109,104.694c20.75,26.001,36.908,54.99,48.023,86.162c11.5,32.249,17.332,66.151,17.332,100.764 c0,80.114-31.197,155.435-87.848,212.083c-56.65,56.649-131.971,87.848-212.084,87.848c-80.114,0-155.434-31.198-212.083-87.849 c-56.65-56.648-87.848-131.969-87.848-212.083c0-59.197,17.208-116.435,49.763-165.521c28.053-42.3,66.007-76.562,110.547-100.007 v58.027c0,28.995,23.505,52.5,52.5,52.5s52.5-23.505,52.5-52.5V52.5c0-28.995-23.505-52.5-52.5-52.5H144.567 c-28.995,0-52.5,23.505-52.5,52.5c0,28.995,23.505,52.5,52.5,52.5h84.328C174.456,136.276,127.939,179.822,92.9,232.655 c-44.001,66.346-67.259,143.65-67.259,223.557c0,54.643,10.714,107.679,31.843,157.634c20.398,48.225,49.587,91.524,86.759,128.695 c37.171,37.171,80.471,66.361,128.696,86.759c49.956,21.13,102.991,31.844,157.634,31.844c54.644,0,107.677-10.714,157.634-31.844 c48.225-20.397,91.523-49.587,128.695-86.759C754.073,705.371,783.262,662.071,803.661,613.847z"/></svg>
</th> <!-- remove column -->
<th></th>
</tr>
</tbody>

@ -384,7 +384,8 @@ form.realtime #adduser {
form.realtime #addoption {
border-bottom-left-radius: 5px;
}
div.modal {
div.modal,
div#modal {
box-sizing: border-box;
z-index: 9001;
position: fixed;
@ -395,7 +396,75 @@ div.modal {
display: none;
background-color: #302B28;
}
div.modal .center {
div.modal #content,
div#modal #content {
box-sizing: border-box;
border: 1px solid white;
vertical-align: middle;
padding: 2.5vw;
width: 100vw;
height: 56.25vw;
max-height: 100vh;
max-width: 177.78vh;
margin: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
div.modal #content p,
div#modal #content p,
div.modal #content li,
div#modal #content li,
div.modal #content pre,
div#modal #content pre,
div.modal #content code,
div#modal #content code {
font-size: 2.5vw;
line-height: 3vw;
}
div.modal #content h1,
div#modal #content h1 {
font-size: 5vw;
line-height: 6vw;
}
div.modal #content h2,
div#modal #content h2 {
font-size: 4.2vw;
line-height: 5.04vw;
}
div.modal #content h3,
div#modal #content h3 {
font-size: 3.6vw;
line-height: 4.32vw;
}
div.modal #content h4,
div#modal #content h4 {
font-size: 3vw;
line-height: 3.6vw;
}
div.modal #content h5,
div#modal #content h5 {
font-size: 2.2vw;
line-height: 2.64vw;
}
div.modal #content h6,
div#modal #content h6 {
font-size: 1.6vw;
line-height: 1.92vw;
}
div.modal #content pre > code,
div#modal #content pre > code {
display: block;
position: relative;
border: 1px solid #333;
width: 90%;
margin: auto;
padding-left: .25vw;
}
div.modal .center,
div#modal .center {
position: relative;
width: 80%;
height: 80%;
@ -403,31 +472,39 @@ div.modal .center {
border: 1px solid #685d56;
text-align: center;
}
div.modal.shown {
div.modal.shown,
div#modal.shown {
display: block;
}
div.modal table {
div.modal table,
div#modal table {
margin: 30px;
border-collapse: collapse;
}
div.modal table input {
div.modal table input,
div#modal table input {
height: 100%;
width: 90%;
border: 3px solid #302B28;
}
div.modal table tfoot tr td {
div.modal table tfoot tr td,
div#modal table tfoot tr td {
z-index: 4000;
cursor: pointer;
}
div.modal #addtime,
div.modal #adddate {
div#modal #addtime,
div.modal #adddate,
div#modal #adddate {
color: #46E981;
border: 1px solid #46E981;
padding: 15px;
}
div.modal #adddate {
div.modal #adddate,
div#modal #adddate {
border-top-left-radius: 5px;
}
div.modal #addtime {
div.modal #addtime,
div#modal #addtime {
border-bottom-left-radius: 5px;
}

@ -8,6 +8,10 @@ define([
], function (Messages, DecorateToolbar, Cryptpad, LilUri, Email) {
var $ = window.$;
var APP = window.APP = {
Cryptpad: Cryptpad,
};
var email = Email.makeScrambler(1);
// slip past the spammers, then unscramble mailto links
@ -22,14 +26,6 @@ define([
DecorateToolbar.main($('#bottom-bar'));
Cryptpad.styleAlerts();
var $table = $('table.scroll');
var $tbody = $table.find('tbody');
var $tryit = $('#tryit');
var now = new Date();
var hasRecent = false;
var forgetPad = Cryptpad.forgetPad;
var padTypes = {
'/pad/': 'Pad',
'/code/': 'Code',
@ -37,16 +33,13 @@ define([
'/slide/': 'Presentation',
};
var truncateTitle = function (title, len) {
if (typeof(title) === 'string' && title.length > len) {
return title.slice(0, len) + '…';
}
return title;
};
var $table = $('table.scroll');
var $tbody = $table.find('tbody');
var $tryit = $('#tryit');
var now = new Date();
var hasRecent = false;
var fixHTML = function (html) {
return html.replace(/</g, '&lt;');
};
var forgetPad = Cryptpad.forgetPad;
var makeRecentPadsTable = function (recentPads) {
if (!recentPads.length) { return; }
@ -68,7 +61,7 @@ define([
var name = padTypes[uri.path()];
var title = pad.title || uri.parts.hash.slice(0,8);
var shortTitle = truncateTitle(pad.title, 48);
var shortTitle = Cryptpad.truncate(pad.title, 48);
var date = new Date(pad.atime).toLocaleDateString();
var created = new Date(pad.ctime).toLocaleDateString();
@ -87,7 +80,7 @@ define([
'class': 'remove',
title: "forget '"+shortTitle + "'"
}).text('✖').click(function () {
Cryptpad.confirm(Messages.forgetPrompt + ' (' + fixHTML(shortTitle) + ')', function (yes) {
Cryptpad.confirm(Messages.forgetPrompt + ' (' + Cryptpad.fixHTML(shortTitle) + ')', function (yes) {
if (!yes) { return; }
forgetPad(pad.href, function (err, data) {
if (err) {
@ -142,7 +135,14 @@ define([
Cryptpad.ready(function () {
console.log("ready");
refreshTable();
$('.table-refresh').click(refreshTable);
if (Cryptpad.store && Cryptpad.store.change) {
Cryptpad.store.change(function (data) {
if (data.key === 'CryptPad_RECENTPADS') {
refreshTable();
}
});
}
});
});

@ -70,5 +70,8 @@ define(function () {
'*/'
].join('');
out.loginText = '<p>Your username and password are used to generate a unique key which is never known by our server.</p>\n' +
'<p>Be careful not to forget your credentials, as they are impossible to recover</p>';
return out;
});

@ -49,6 +49,15 @@
});
};
var changeHandlers = frame.changeHandlers = [];
var change = frame.change = function (f) {
if (typeof(f) !== 'function') {
throw new Error('[Frame.change] expected callback');
}
changeHandlers.push(f);
};
var _listener = function (e) {
if (!frame.accepts(e.origin)) {
console.log("message from %s rejected!", e.origin);
@ -63,6 +72,14 @@
console.log("No uid!");
return;
}
if (uid === 'change' && changeHandlers.length) {
changeHandlers.forEach(function (f) {
f(data);
});
return;
}
if (timeouts[uid]) {
window.clearTimeout(timeouts[uid]);
}
@ -89,6 +106,11 @@
};
var id = req._uid = uid();
// uid must not equal 'change'
while(id === 'change') {
id = req._uid = uid();
}
if (typeof(cb) === 'function') {
//console.log("setting callback!");
listeners[id] = cb;

@ -81,3 +81,13 @@ window.addEventListener('message', function(e) {
}
});
window.addEventListener('storage', function (ev) {
parent.postMessage(JSON.stringify({
_uid: 'change',
data: {
key: ev.key,
oldValue: ev.oldValue,
newValue: ev.newValue,
}
}), '*');
});

@ -471,7 +471,63 @@ form.realtime {
#addoption { .bottom-left; }
}
div.modal {
.viewportRatio (@x, @y, @p: 100) {
width: @p * 100vw;
height: @y * (@p * 100vw) / @x;
max-width: @x / @y * (@p * 100vh);
max-height: (@p * 100vh);
}
div.modal, div#modal {
#content {
box-sizing: border-box;
.size (@n) {
font-size: @n * 1vw;
line-height: @n * 1.2vw;
}
border: 1px solid white;
vertical-align: middle;
padding: 2.5vw;
width: 100vw;
height: 56.25vw; // height:width ratio = 9/16 = .5625
//background: pink;
max-height: 100vh;
max-width: 177.78vh; // 16/9 = 1.778
margin: auto;
position: absolute;
top:0;bottom:0; // vertical center
left:0;right:0; // horizontal center
p, li, pre, code {
.size(2.5);
}
h1 { .size(5); }
h2 { .size(4.2); }
h3 { .size(3.6); }
h4 { .size (3); }
h5 { .size(2.2); }
h6 { .size(1.6); }
pre > code {
display: block;
position: relative;
border: 1px solid #333;
width: 90%;
margin: auto;
padding-left: .25vw;
}
}
box-sizing: border-box;
z-index: 9001;
position: fixed;

@ -71,5 +71,27 @@ define(function () {
}
};
var changeHandlers = Store.changeHandlers = [];
Store.change = function (f) {
if (typeof(f) !== 'function') {
throw new Error('[Store.change] callback must be a function');
}
changeHandlers.push(f);
if (changeHandlers.length === 1) {
// start listening for changes
window.addEventListener('storage', function (e) {
changeHandlers.forEach(function (f) {
f({
key: e.key,
oldValue: e.oldValue,
newValue: e.newValue,
});
});
});
}
};
return Store;
});

@ -0,0 +1,174 @@
define([
'/api/config?cb=' + Math.random().toString().slice(2),
'/customize/messages.js',
'/bower_components/chainpad-listmap/chainpad-listmap.js',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/scrypt-async/scrypt-async.min.js',
'/bower_components/tweetnacl/nacl-fast.min.js',
], function (Config, Messages, Listmap, Crypto) {
var Scrypt = window.scrypt;
var Nacl = window.nacl;
var localKey = 'cryptpad_user_session';
var User = {};
var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; };
var session = User.session = function (secret) {
// TODO use store.js, not localStorage?
if (secret) {
localStorage.setItem(localKey, JSON.stringify(secret));
return;
}
if (secret === null) {
localStorage.removeItem(localKey);
return;
}
var temp = localStorage.getItem(localKey);
try {
return JSON.parse(temp);
} catch (err) {
return null;
}
};
/* 64 uint8s symmetric keys
32 b64 channel
16 b64 key
16 b64 junk
32 uint8s ed signing key
32 uint8s curve public key */
var parse128 = function (A) {
if (A.length !== 128) {
throw new Error("Expected 128 uint8s!");
}
var symmetric = Nacl.util.encodeBase64(A.slice(0, 36));
return {
ed: A.slice(96),
curve: A.slice(64, 96),
channel: symmetric.slice(0, 32),
key: symmetric.slice(32),
extra: A.slice(36, 64),
};
};
var initialize = User.initialize = function (proxy, secret, cb) {
proxy.on('ready', function (info) {
var now = ''+new Date();
// old atime
var otime = proxy.atime;
var atime = proxy.atime = now;
// creation time
proxy.ctime = proxy.ctime || now;
proxy.username = proxy.username || secret.username;
proxy.schema = proxy.schema || 'login_data-v0';
proxy.documents = proxy.documents || [];
cb(void 0, proxy);
});
};
/*
cb(proxy);
*/
var connect = User.connect = function (secret, cb) {
if (!secret) {
// FIXME
return;
}
var config = {
websocketURL: Config.websocketURL,
channel: secret.channel,
data: {},
crypto: Crypto.createEncryptor(secret.key),
logLevel: 0,
};
var rt = Listmap.create(config);
initialize(rt.proxy, secret, cb);
};
/* Asynchronously derive 128 random uint8s given a uname and password
cb(proxy, secret)
*/
var login = User.login = function (uname, pw, cb) {
Scrypt(pw,
uname,
15, // memory cost parameter
8, // block size parameter
128, // derived key length
200, // interruptStep
function (bytes) {
var secret = parse128(bytes);
secret.username = uname;
session(secret);
connect(secret, cb);
});
};
var prepareStore = User.prepareStore = function (proxy) {
var store = {};
var ps = proxy.store = proxy.store || {};
var set = store.set = function (key, val, cb) {
ps[key] = val;
cb();
};
var batchset = store.setBatch = function (map, cb) {
if (isArray(map) || typeof(map) !== 'object') {
cb('[setBatch.TypeError] expected key-value pairs to set');
return;
}
Object.keys(map).forEach(function (k) {
ps[k] = map[k];
});
cb();
};
var get = store.get = function (key, cb) {
cb(void 0, ps[key]);
};
var batchget = store.getBatch = function (keys, cb) {
if (!isArray(keys)) {
cb('[getBatch.TypeError] expected array of keys to return');
return;
}
var map = {};
keys.forEach(function (k) {
map[k] = ps[k];
});
cb(void 0, map);
};
var remove = store.remove = function (key, cb) {
ps[key] = undefined;
cb();
};
var batchremove = store.removeBatch = function (keys, cb) {
if (!isArray(keys)) {
cb('[batchremove.TypeError] expected array of keys to remove');
return;
}
keys.forEach(function (k) {
ps[k] = undefined;
});
cb();
};
var keys = store.keys = function (cb) {
cb(void 0, Object.keys(ps));
};
return store;
};
return User;
});

@ -4,8 +4,11 @@ define([
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/alertifyjs/dist/js/alertify.js',
'/bower_components/spin.js/spin.min.js',
'/customize/user.js',
'/bower_components/jquery/dist/jquery.min.js',
], function (Messages, Store, Crypto, Alertify, Spinner) {
], function (Messages, Store, Crypto, Alertify, Spinner, User) {
/* This file exposes functionality which is specific to Cryptpad, but not to
any particular pad type. This includes functions for committing metadata
about pads to your local storage for future use and improved usability.
@ -14,13 +17,32 @@ define([
*/
var $ = window.jQuery;
var common = {};
var store;
var userProxy;
var userStore;
var getStore = function () {
if (!store) {
var getStore = common.getStore = function (legacy) {
if (!legacy && userStore) { return userStore; }
if (store) { return store; }
throw new Error("Store is not ready!");
};
/*
* cb(err, proxy);
*/
var authorize = common.authorize = function (cb) {
console.log("Authorizing");
var secret = User.session();
if (!secret) {
// user is not authenticated
cb('user is not authenticated', void 0);
}
return store;
// for now we assume that things always work
User.connect(secret, function (err, proxy) {
cb(void 0, proxy);
});
};
Store.ready(function (err, Store) {
@ -31,7 +53,6 @@ define([
store = Store;
});
var common = {};
var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; };
@ -83,6 +104,9 @@ define([
var storageKey = common.storageKey = 'CryptPad_RECENTPADS';
/*
* localStorage formatting
*/
/*
the first time this gets called, your local storage will migrate to a
new format. No more indices for values, everything is named now.
@ -129,21 +153,52 @@ define([
return window.location.hash.slice(1);
};
var setPadAttribute = common.setPadAttribute = function (attr, value, cb) {
getStore().set([getHash(), attr].join('.'), value, function (err, data) {
var parsePadUrl = common.parsePadUrl = function (href) {
var patt = /^https*:\/\/([^\/]*)\/(.*?)\/#(.*)$/i;
var ret = {};
href.replace(patt, function (a, domain, type, hash) {
ret.domain = domain;
ret.type = type;
ret.hash = hash;
return '';
});
return ret;
};
var makePad = function (href, title) {
var now = ''+new Date();
return {
href: href,
atime: now,
ctime: now,
title: title || window.location.hash.slice(1, 9),
};
};
/* Sort pads according to how recently they were accessed */
var mostRecent = common.mostRecent = function (a, b) {
return new Date(b.atime).getTime() - new Date(a.atime).getTime();
};
// STORAGE
var setPadAttribute = common.setPadAttribute = function (attr, value, cb, legacy) {
getStore(legacy).set([getHash(), attr].join('.'), value, function (err, data) {
cb(err, data);
});
};
var getPadAttribute = common.getPadAttribute = function (attr, cb) {
getStore().get([getHash(), attr].join('.'), function (err, data) {
// STORAGE
var getPadAttribute = common.getPadAttribute = function (attr, cb, legacy) {
getStore(legacy).get([getHash(), attr].join('.'), function (err, data) {
cb(err, data);
});
};
// STORAGE
/* fetch and migrate your pad history from localStorage */
var getRecentPads = common.getRecentPads = function (cb) {
getStore().get(storageKey, function (err, recentPads) {
var getRecentPads = common.getRecentPads = function (cb, legacy) {
getStore(legacy).get(storageKey, function (err, recentPads) {
if (isArray(recentPads)) {
cb(void 0, migrateRecentPads(recentPads));
return;
@ -152,32 +207,16 @@ define([
});
};
// STORAGE
/* commit a list of pads to localStorage */
var setRecentPads = common.setRecentPads = function (pads, cb) {
getStore().set(storageKey, pads, function (err, data) {
var setRecentPads = common.setRecentPads = function (pads, cb, legacy) {
getStore(legacy).set(storageKey, pads, function (err, data) {
cb(err, data);
});
};
/* Sort pads according to how recently they were accessed */
var mostRecent = common.mostRecent = function (a, b) {
return new Date(b.atime).getTime() - new Date(a.atime).getTime();
};
var parsePadUrl = common.parsePadUrl = function (href) {
var patt = /^https*:\/\/([^\/]*)\/(.*?)\/#(.*)$/i;
var ret = {};
href.replace(patt, function (a, domain, type, hash) {
ret.domain = domain;
ret.type = type;
ret.hash = hash;
return '';
});
return ret;
};
var forgetPad = common.forgetPad = function (href, cb) {
// STORAGE
var forgetPad = common.forgetPad = function (href, cb, legacy) {
var parsed = parsePadUrl(href);
getRecentPads(function (err, recentPads) {
@ -195,7 +234,7 @@ define([
return;
}
getStore().keys(function (err, keys) {
getStore(legacy).keys(function (err, keys) {
if (err) {
cb(err);
return;
@ -208,24 +247,15 @@ define([
cb();
return;
}
getStore().removeBatch(toRemove, function (err, data) {
getStore(legacy).removeBatch(toRemove, function (err, data) {
cb(err, data);
});
});
});
});
};
var makePad = function (href, title) {
var now = ''+new Date();
return {
href: href,
atime: now,
ctime: now,
title: title || window.location.hash.slice(1, 9),
};
}, legacy);
}, legacy);
};
// STORAGE
var rememberPad = common.rememberPad = window.rememberPad = function (title, cb) {
// bail out early
if (!/#/.test(window.location.hash)) { return; }
@ -265,6 +295,7 @@ define([
});
};
// STORAGE
var setPadTitle = common.setPadTitle = function (name, cb) {
var href = window.location.href;
var parsed = parsePadUrl(href);
@ -301,6 +332,7 @@ define([
});
};
// STORAGE
var getPadTitle = common.getPadTitle = function (cb) {
var href = window.location.href;
var parsed = parsePadUrl(window.location.href);
@ -324,6 +356,7 @@ define([
});
};
// STORAGE
var causesNamingConflict = common.causesNamingConflict = function (title, cb) {
var href = window.location.href;
@ -364,13 +397,30 @@ define([
}
};
state++;
state = 2;
Store.ready(function (err, store) {
env.store = store;
common.store = env.store = store;
cb();
});
// HERE
authorize(function (err, proxy) {
if (err) {
// not logged in
}
if (!proxy) {
cb();
return;
}
userProxy = env.proxy = proxy;
userStore = env.userStore = User.prepareStore(proxy);
cb();
});
};
/*
* Saving files
*/
var fixFileName = common.fixFileName = function (filename) {
return filename.replace(/ /g, '-').replace(/[\/\?]/g, '_')
.replace(/_+/g, '_');
@ -388,6 +438,9 @@ define([
};
};
/*
* Alertifyjs
*/
var styleAlerts = common.styleAlerts = function (href) {
var $link = $('link[href="/customize/alertify.css"]');
if ($link.length) { return; }
@ -492,6 +545,9 @@ define([
Alertify.error(msg);
};
/*
* spinner
*/
common.spinner = function (parent) {
var $target = $('<div>', {
//

@ -102,7 +102,7 @@ define([
console.log("Couldn't get pad title");
return;
}
document.title = title || window.location.hash.slice(1, 9);
document.title = APP.title = title || window.location.hash.slice(1, 9);
Cryptpad.rememberPad(title, function (err, data) {
if (err) {
console.log("Couldn't remember pad");
@ -140,7 +140,7 @@ define([
console.log(err);
return;
}
document.title = window.location.hash.slice(1,9);
document.title = APP.title = window.location.hash.slice(1,9);
});
});
});
@ -167,7 +167,7 @@ define([
console.error(err);
return;
}
document.title = title;
document.title = APP.title = title;
});
});
});
@ -267,6 +267,15 @@ define([
});
}
Slide.onChange(function (o, n, l) {
if (n !== null) {
document.title = APP.title + ' (' + (++n) + '/' + l + ')';
return;
}
console.log("Exiting presentation mode");
document.title = APP.title;
});
setEditable(true);
initializing = false;
};

@ -12,6 +12,7 @@ define([
index: 0,
lastIndex: 0,
content: [],
changeHandlers: [],
};
var $modal;
var $content;
@ -20,6 +21,25 @@ define([
$content = Slide.$content = $c;
};
Slide.onChange = function (f) {
if (typeof(f) === 'function') {
Slide.changeHandlers.push(f);
}
};
var change = function (oldIndex, newIndex) {
if (oldIndex === newIndex) {
return false;
}
if (Slide.changeHandlers.length) {
Slide.changeHandlers.some(function (f, i) {
// HERE
f(oldIndex, newIndex, Slide.content.length);
});
return true;
}
};
var forbiddenTags = Slide.forbiddenTags = [
'SCRIPT',
'IFRAME',
@ -87,10 +107,10 @@ define([
if (typeof(patch) === 'string') {
$content.html(Marked(c));
return;
} else {
DD.apply($content[0], patch);
}
change(Slide.lastIndex, Slide.index);
};
var show = Slide.show = function (bool, content) {
@ -99,8 +119,10 @@ define([
Slide.update(content);
Slide.draw(Slide.index);
$modal.addClass('shown');
change(null, Slide.index);
return;
}
change(Slide.index, null);
$modal.removeClass('shown');
};
@ -115,12 +137,16 @@ define([
var left = Slide.left = function () {
console.log('left');
Slide.lastIndex = Slide.index;
var i = Slide.index = Math.max(0, Slide.index - 1);
Slide.draw(i);
};
var right = Slide.right = function () {
console.log('right');
Slide.lastIndex = Slide.index;
var i = Slide.index = Math.min(Slide.content.length -1, Slide.index + 1);
Slide.draw(i);
};

Loading…
Cancel
Save