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
This commit is contained in:
parent
ec0dba3f7c
commit
7da58a0de9
@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
tbody { border-top: 2px solid black; }
|
tbody { border-top: 2px solid black; }
|
||||||
|
|
||||||
tbody td, thead th {
|
tbody td {
|
||||||
/* width: 20%; */ /* Optional */
|
/* width: 20%; */ /* Optional */
|
||||||
border-right: 1px solid black;
|
border-right: 1px solid black;
|
||||||
/* white-space: nowrap; */
|
/* white-space: nowrap; */
|
||||||
@ -61,9 +61,19 @@
|
|||||||
tbody td:last-child, thead th:last-child {
|
tbody td:last-child, thead th:last-child {
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
tbody tr:nth-child(even) {
|
tbody tr:nth-child(odd) {
|
||||||
background-color: #ddd;
|
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 {
|
.remove {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -129,77 +139,73 @@
|
|||||||
<script>
|
<script>
|
||||||
require([
|
require([
|
||||||
'/customize/DecorateToolbar.js',
|
'/customize/DecorateToolbar.js',
|
||||||
|
'/common/cryptpad-common.js',
|
||||||
'/bower_components/lil-uri/uri.min.js',
|
'/bower_components/lil-uri/uri.min.js',
|
||||||
'/bower_components/jquery/dist/jquery.min.js'
|
'/bower_components/jquery/dist/jquery.min.js'
|
||||||
], function (Dt, LilUri) {
|
], function (DecorateToolbar, Cryptpad, LilUri) {
|
||||||
var $ = window.$;
|
var $ = window.$;
|
||||||
Dt.main($('#bottom-bar'));
|
DecorateToolbar.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]; });
|
|
||||||
var $table = $('table.scroll');
|
var $table = $('table.scroll');
|
||||||
var $tbody = $table.find('tbody');
|
var $tbody = $table.find('tbody');
|
||||||
var $tryit = $('#tryit');
|
var $tryit = $('#tryit');
|
||||||
var now = new Date();
|
var now = new Date();
|
||||||
var hasRecent = false;
|
var hasRecent = false;
|
||||||
|
|
||||||
var memorySpan = 1000 * 60 * 60 * 24 * 30; // thirty days
|
var memorySpan = Cryptpad.timeframe; // thirty days
|
||||||
|
|
||||||
var forgetPad = function (url) {
|
var forgetPad = Cryptpad.forgetPad;
|
||||||
if (recentPads) {
|
|
||||||
recentPads = recentPads.filter(function (pad) {
|
|
||||||
// remove the pad in question
|
|
||||||
return pad[0] !== url;
|
|
||||||
});
|
|
||||||
localStorage[localStorageKey] = JSON.stringify(recentPads);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var padTypes = {
|
var padTypes = {
|
||||||
'/pad/': 'Pad',
|
'/pad/': 'Pad',
|
||||||
'/code/': 'Code'
|
'/code/': 'Code'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var recentPads = Cryptpad.getRecentPads();
|
||||||
|
recentPads.sort(Cryptpad.mostRecent);
|
||||||
|
|
||||||
var makeRecentPadsTable = function () {
|
var makeRecentPadsTable = function () {
|
||||||
recentPads.length && recentPads.some(function (pad, index) {
|
recentPads.length && recentPads.some(function (pad, index) {
|
||||||
if (!pad) return true;
|
if (!pad) return;
|
||||||
|
|
||||||
|
console.log(pad);
|
||||||
|
|
||||||
// don't link to old pads
|
// 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;
|
hasRecent = true;
|
||||||
|
|
||||||
// split up the uri
|
// split up the uri
|
||||||
var uri = LilUri(pad[0]);
|
var uri = LilUri(pad.href);
|
||||||
|
|
||||||
// derive the name
|
// derive the name
|
||||||
var name = padTypes[uri.path()];
|
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()) {
|
if (date === now.toLocaleDateString()) {
|
||||||
date = new Date(pad[1]).toLocaleTimeString().replace(/ /g, '');
|
date = new Date(pad.atime).toLocaleTimeString().replace(/ /g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = 'pad-'+index;
|
var id = 'pad-'+index;
|
||||||
$tbody.append('<tr id="'+id+'">' +
|
$tbody.append('<tr id="'+id+'">' +
|
||||||
'<td>' + name + '</td>' +
|
'<td>' + name + '</td>' +
|
||||||
'<td>' + title + '</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>' + date + '</td>' +
|
||||||
'<td class="remove">✖</td>'+
|
'<td class="remove">✖</td>'+
|
||||||
'</tr>');
|
'</tr>');
|
||||||
|
|
||||||
var $row = $('#'+id);
|
var $row = $('#'+id);
|
||||||
$row.find('.remove').click(function () {
|
$row.find('.remove').click(function () {
|
||||||
forgetPad(pad[0]);
|
forgetPad(pad.href);
|
||||||
$row.fadeOut(750, function () {
|
$row.fadeOut(750, function () {
|
||||||
$row.remove();
|
$row.remove();
|
||||||
if (!$table.find('tr').length) {
|
if (!$table.find('tr').find('td').length) {
|
||||||
$table.remove();
|
$table.remove();
|
||||||
$tryit.text("Try it out!");
|
$tryit.text("Try it out!");
|
||||||
}
|
}
|
||||||
@ -209,10 +215,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (recentPads.length) {
|
if (recentPads.length) {
|
||||||
recentPads.sort(function (a, b) {
|
recentPads.sort(Cryptpad.mostRecent);
|
||||||
// b - a
|
|
||||||
return new Date(b[1]).getTime() - new Date(a[1]).getTime();
|
|
||||||
});
|
|
||||||
makeRecentPadsTable();
|
makeRecentPadsTable();
|
||||||
}
|
}
|
||||||
if (hasRecent) {
|
if (hasRecent) {
|
||||||
@ -225,6 +228,16 @@
|
|||||||
|
|
||||||
<table class="recent scroll" style="display:none">
|
<table class="recent scroll" style="display:none">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Link</th>
|
||||||
|
<th>Created</th>
|
||||||
|
<th>Last Accessed</th>
|
||||||
|
<th></th> <!-- remove column -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@ -220,7 +220,9 @@ define([
|
|||||||
var title = window.prompt("How would you like this pad to be titled?",
|
var title = window.prompt("How would you like this pad to be titled?",
|
||||||
Cryptpad.getPadTitle());
|
Cryptpad.getPadTitle());
|
||||||
|
|
||||||
if (title === null) {
|
if (title === null) { return; }
|
||||||
|
if (Cryptpad.causesNamingConflict(title)) {
|
||||||
|
window.alert("Another pad already has that title");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Cryptpad.setPadTitle(title);
|
Cryptpad.setPadTitle(title);
|
||||||
|
|||||||
@ -2,9 +2,17 @@ define([
|
|||||||
'/bower_components/chainpad-crypto/crypto.js',
|
'/bower_components/chainpad-crypto/crypto.js',
|
||||||
'/bower_components/jquery/dist/jquery.min.js',
|
'/bower_components/jquery/dist/jquery.min.js',
|
||||||
], function (Crypto) {
|
], 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 $ = window.jQuery;
|
||||||
var common = {};
|
var common = {};
|
||||||
|
|
||||||
|
var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; };
|
||||||
|
|
||||||
var getSecrets = common.getSecrets = function () {
|
var getSecrets = common.getSecrets = function () {
|
||||||
var secret = {};
|
var secret = {};
|
||||||
if (!/#/.test(window.location.href)) {
|
if (!/#/.test(window.location.href)) {
|
||||||
@ -20,7 +28,42 @@ define([
|
|||||||
var storageKey = common.storageKey = 'CryptPad_RECENTPADS';
|
var storageKey = common.storageKey = 'CryptPad_RECENTPADS';
|
||||||
var timeframe = common.timeframe = 1000 * 60 * 60 * 24 * 30;
|
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 recentPadsStr = localStorage[storageKey];
|
||||||
|
|
||||||
var recentPads = [];
|
var recentPads = [];
|
||||||
@ -32,28 +75,60 @@ define([
|
|||||||
// just overwrite it.
|
// just overwrite it.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return recentPads;
|
return migrateRecentPads(recentPads);
|
||||||
};
|
};
|
||||||
|
|
||||||
var setRecentPads = function (pads) {
|
/* commit a list of pads to localStorage */
|
||||||
localStorage[storageKey] = JSON.stringify(pads);
|
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) {
|
var rememberPad = common.rememberPad = window.rememberPad = function (title) {
|
||||||
// bail out early
|
// bail out early
|
||||||
if (!/#/.test(window.location.hash)) { return; }
|
if (!/#/.test(window.location.hash)) { return; }
|
||||||
|
|
||||||
var recentPads = getRecentPads();
|
var pads = getRecentPads();
|
||||||
|
|
||||||
var now = new Date();
|
var now = new Date();
|
||||||
|
var href = window.location.href;
|
||||||
|
|
||||||
var out = recentPads.filter(function (pad) {
|
var isUpdate = false;
|
||||||
return (pad && pad[0] !== window.location.href &&
|
|
||||||
(now.getTime() - new Date(pad[1]).getTime()) < timeframe);
|
var out = pads.map(function (pad) {
|
||||||
|
if (pad && pad.href === href) {
|
||||||
|
isUpdate = true;
|
||||||
|
// bump the atime
|
||||||
|
pad.atime = now;
|
||||||
|
|
||||||
|
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
|
if (!isUpdate) {
|
||||||
out.push([window.location.href, now, title || '']);
|
// href, atime, name
|
||||||
|
out.push({
|
||||||
|
href: href,
|
||||||
|
atime: now,
|
||||||
|
ctime: now,
|
||||||
|
title: title || window.location.hash.slice(1,9),
|
||||||
|
});
|
||||||
|
}
|
||||||
setRecentPads(out);
|
setRecentPads(out);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,14 +137,13 @@ define([
|
|||||||
var recent = getRecentPads();
|
var recent = getRecentPads();
|
||||||
|
|
||||||
var renamed = recent.map(function (pad) {
|
var renamed = recent.map(function (pad) {
|
||||||
if (pad[0] === href) {
|
if (pad.href === href) {
|
||||||
// update the atime
|
// update the atime
|
||||||
pad[1] = new Date().toISOString();
|
pad.atime = new Date().toISOString();
|
||||||
|
|
||||||
// set the name
|
// set the name
|
||||||
pad[2] = name;
|
pad.title = name;
|
||||||
}
|
}
|
||||||
//console.log(pad);
|
|
||||||
return pad;
|
return pad;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -81,14 +155,22 @@ define([
|
|||||||
var hashSlice = window.location.hash.slice(1,9);
|
var hashSlice = window.location.hash.slice(1,9);
|
||||||
var title = '';
|
var title = '';
|
||||||
getRecentPads().some(function (pad) {
|
getRecentPads().some(function (pad) {
|
||||||
if (pad[0] === href) {
|
if (pad.href === href) {
|
||||||
title = pad[2] || hashSlice;
|
title = pad.title || hashSlice;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return title;
|
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) {
|
var importContent = common.importContent = function (type, f) {
|
||||||
return function () {
|
return function () {
|
||||||
var $files = $('<input type="file">').click();
|
var $files = $('<input type="file">').click();
|
||||||
|
|||||||
@ -381,6 +381,10 @@ define([
|
|||||||
var title = window.prompt("How would you like to title this pad?", suggestion);
|
var title = window.prompt("How would you like to title this pad?", suggestion);
|
||||||
|
|
||||||
if (title === null) { return; }
|
if (title === null) { return; }
|
||||||
|
if (Cryptpad.causesNamingConflict(title)) {
|
||||||
|
window.alert("Another pad already has that title");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Cryptpad.setPadTitle(title);
|
Cryptpad.setPadTitle(title);
|
||||||
document.title = title;
|
document.title = title;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user