improve pad naming UX, slight refactoring

* prevent naming conflicts
* migrate localestorage to use named attributes
* use ctime and atime
* display default names in table
* sort pads by most recent atime
* move more functions into cryptpad common
* change table styles
pull/1/head
ansuz 9 years ago
parent ec0dba3f7c
commit 7da58a0de9

@ -49,7 +49,7 @@
tbody { border-top: 2px solid black; }
tbody td, thead th {
tbody td {
/* width: 20%; */ /* Optional */
border-right: 1px solid black;
/* white-space: nowrap; */
@ -61,9 +61,19 @@
tbody td:last-child, thead th:last-child {
border-right: none;
}
tbody tr:nth-child(even) {
tbody tr:nth-child(odd) {
background-color: #ddd;
}
tbody tr th {
box-sizing: border-box;
border: 1px solid black;
}
tbody tr th:last-child {
border-right: 0px;
}
tbody tr th:first-of-type {
border-left: 0px;
}
.remove {
cursor: pointer;
@ -129,77 +139,73 @@
<script>
require([
'/customize/DecorateToolbar.js',
'/common/cryptpad-common.js',
'/bower_components/lil-uri/uri.min.js',
'/bower_components/jquery/dist/jquery.min.js'
], function (Dt, LilUri) {
], function (DecorateToolbar, Cryptpad, LilUri) {
var $ = window.$;
Dt.main($('#bottom-bar'));
var localStorageKey = 'CryptPad_RECENTPADS';
var recentPadsStr = localStorage[localStorageKey];
var recentPads;
if (recentPadsStr) { recentPads = JSON.parse(recentPadsStr); }
if (!recentPads) { return; }
recentPads.sort(function (a,b) { return b[1] - a[1]; });
DecorateToolbar.main($('#bottom-bar'));
var $table = $('table.scroll');
var $tbody = $table.find('tbody');
var $tryit = $('#tryit');
var now = new Date();
var hasRecent = false;
var memorySpan = 1000 * 60 * 60 * 24 * 30; // thirty days
var memorySpan = Cryptpad.timeframe; // thirty days
var forgetPad = function (url) {
if (recentPads) {
recentPads = recentPads.filter(function (pad) {
// remove the pad in question
return pad[0] !== url;
});
localStorage[localStorageKey] = JSON.stringify(recentPads);
}
};
var forgetPad = Cryptpad.forgetPad;
var padTypes = {
'/pad/': 'Pad',
'/code/': 'Code'
};
var recentPads = Cryptpad.getRecentPads();
recentPads.sort(Cryptpad.mostRecent);
var makeRecentPadsTable = function () {
recentPads.length && recentPads.some(function (pad, index) {
if (!pad) return true;
if (!pad) return;
console.log(pad);
// don't link to old pads
if (now.getTime() - pad[1] > memorySpan) return true;
if (now.getTime() - new Date(pad.atime).getTime() > memorySpan) return true;
hasRecent = true;
// split up the uri
var uri = LilUri(pad[0]);
var uri = LilUri(pad.href);
// derive the name
var name = padTypes[uri.path()];
var title = pad[2] || uri.parts.hash.slice(0,8);
var title = pad.title || uri.parts.hash.slice(0,8);
var date = new Date(pad.atime).toLocaleDateString();
var created = new Date(pad.ctime).toLocaleDateString();
var date = new Date(pad[1]).toLocaleDateString();
if (date === now.toLocaleDateString()) {
date = new Date(pad[1]).toLocaleTimeString().replace(/ /g, '');
date = new Date(pad.atime).toLocaleTimeString().replace(/ /g, '');
}
var id = 'pad-'+index;
$tbody.append('<tr id="'+id+'">' +
'<td>' + name + '</td>' +
'<td>' + title + '</td>' +
'<td><a href="' + pad[0] + '">' + pad[0] + '</a></td>' +
'<td><a href="' + pad.href + '">' + pad.href + '</a></td>' +
'<td>' + created + '</td>' + // created
'<td>' + date + '</td>' +
'<td class="remove"></td>'+
'</tr>');
var $row = $('#'+id);
$row.find('.remove').click(function () {
forgetPad(pad[0]);
forgetPad(pad.href);
$row.fadeOut(750, function () {
$row.remove();
if (!$table.find('tr').length) {
if (!$table.find('tr').find('td').length) {
$table.remove();
$tryit.text("Try it out!");
}
@ -209,10 +215,7 @@
};
if (recentPads.length) {
recentPads.sort(function (a, b) {
// b - a
return new Date(b[1]).getTime() - new Date(a[1]).getTime();
});
recentPads.sort(Cryptpad.mostRecent);
makeRecentPadsTable();
}
if (hasRecent) {
@ -225,6 +228,16 @@
<table class="recent scroll" style="display:none">
<tbody>
<tr>
<th>Type</th>
<th>Title</th>
<th>Link</th>
<th>Created</th>
<th>Last Accessed</th>
<th></th> <!-- remove column -->
</tr>
</tbody>
</table>

@ -220,7 +220,9 @@ define([
var title = window.prompt("How would you like this pad to be titled?",
Cryptpad.getPadTitle());
if (title === null) {
if (title === null) { return; }
if (Cryptpad.causesNamingConflict(title)) {
window.alert("Another pad already has that title");
return;
}
Cryptpad.setPadTitle(title);

@ -2,9 +2,17 @@ define([
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/jquery/dist/jquery.min.js',
], function (Crypto) {
/* 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.
Additionally, there is some basic functionality for import/export.
*/
var $ = window.jQuery;
var common = {};
var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; };
var getSecrets = common.getSecrets = function () {
var secret = {};
if (!/#/.test(window.location.href)) {
@ -20,7 +28,42 @@ define([
var storageKey = common.storageKey = 'CryptPad_RECENTPADS';
var timeframe = common.timeframe = 1000 * 60 * 60 * 24 * 30;
var getRecentPads = function () {
/*
the first time this gets called, your local storage will migrate to a
new format. No more indices for values, everything is named now.
* href
* atime (access time)
* title
* ??? // what else can we put in here?
*/
var migrateRecentPads = common.migrateRecentPads = function (pads) {
return pads.map(function (pad) {
if (isArray(pad)) {
return {
href: pad[0],
atime: pad[1],
title: pad[2],
};
} else if (typeof(pad) === 'object') {
if (!pad.ctime) { pad.ctime = pad.atime; }
/*
if (pad.date) {
pad.atime = pad.date;
delete pad.date;
pad.date = undefined;
}*/
return pad;
} else {
console.error("[Cryptpad.migrateRecentPads] pad had unexpected value");
console.log(pad);
return {};
}
});
};
/* fetch and migrate your pad history from localStorage */
var getRecentPads = common.getRecentPads = function () {
var recentPadsStr = localStorage[storageKey];
var recentPads = [];
@ -32,28 +75,60 @@ define([
// just overwrite it.
}
}
return recentPads;
return migrateRecentPads(recentPads);
};
var setRecentPads = function (pads) {
localStorage[storageKey] = JSON.stringify(pads);
/* commit a list of pads to localStorage */
var setRecentPads = common.setRecentPads = function (pads) {
localStorage.setItem(storageKey, JSON.stringify(pads));
};
/* 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 forgetPad = common.forgetPad = function (href) {
var recentPads = getRecentPads().filter(function (pad) {
return pad.href !== href;
});
setRecentPads(recentPads);
};
var rememberPad = common.rememberPad = window.rememberPad = function (title) {
// bail out early
if (!/#/.test(window.location.hash)) { return; }
var recentPads = getRecentPads();
var pads = getRecentPads();
var now = new Date();
var href = window.location.href;
var isUpdate = false;
var out = pads.map(function (pad) {
if (pad && pad.href === href) {
isUpdate = true;
// bump the atime
pad.atime = now;
var out = recentPads.filter(function (pad) {
return (pad && pad[0] !== window.location.href &&
(now.getTime() - new Date(pad[1]).getTime()) < timeframe);
pad.title = title;
}
return pad;
}).filter(function (pad) {
// remove pads with an expired atime
return (now.getTime() - new Date(pad.atime).getTime()) < timeframe;
});
// href, atime, name
out.push([window.location.href, now, title || '']);
if (!isUpdate) {
// href, atime, name
out.push({
href: href,
atime: now,
ctime: now,
title: title || window.location.hash.slice(1,9),
});
}
setRecentPads(out);
};
@ -62,14 +137,13 @@ define([
var recent = getRecentPads();
var renamed = recent.map(function (pad) {
if (pad[0] === href) {
if (pad.href === href) {
// update the atime
pad[1] = new Date().toISOString();
pad.atime = new Date().toISOString();
// set the name
pad[2] = name;
pad.title = name;
}
//console.log(pad);
return pad;
});
@ -81,14 +155,22 @@ define([
var hashSlice = window.location.hash.slice(1,9);
var title = '';
getRecentPads().some(function (pad) {
if (pad[0] === href) {
title = pad[2] || hashSlice;
if (pad.href === href) {
title = pad.title || hashSlice;
return true;
}
});
return title;
};
var causesNamingConflict = common.causesNamingConflict = function (title) {
var href = window.location.href;
return getRecentPads().some(function (pad) {
return pad.title === title &&
pad.href !== href;
});
};
var importContent = common.importContent = function (type, f) {
return function () {
var $files = $('<input type="file">').click();

@ -381,6 +381,10 @@ define([
var title = window.prompt("How would you like to title this pad?", suggestion);
if (title === null) { return; }
if (Cryptpad.causesNamingConflict(title)) {
window.alert("Another pad already has that title");
return;
}
Cryptpad.setPadTitle(title);
document.title = title;

Loading…
Cancel
Save