Merge branch 'staging' of github.com:xwiki-labs/cryptpad into login

This commit is contained in:
ansuz 2016-12-22 16:54:51 +01:00
commit 5534da8abf
16 changed files with 411 additions and 117 deletions

View File

@ -10,8 +10,7 @@ define([
var main = function () {
var url = window.location.pathname;
var isHtml = /\.html/.test(url) || url === '/' || url === '';
var isPoll = /\/poll\//.test(url);
if (!isHtml && !isPoll) {
if (!isHtml) {
Messages._applyTranslation();
return;
}

View File

@ -86,6 +86,14 @@ define([
cb();
};
Store.addTemplate = function (href) {
filesOp.addTemplate(href);
};
Store.listTemplates = function () {
return filesOp.listTemplates();
};
Store.getProxy = function () {
return exp;
};
@ -146,11 +154,6 @@ define([
if (!Cryptpad.getUserHash()) {
localStorage.FS_hash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
}
window.patchText = TextPatcher.create({
realtime: realtime,
logging: true,
});
}).on('ready', function () {
if (!rt.proxy[Cryptpad.storageKey] || !Cryptpad.isArray(rt.proxy[Cryptpad.storageKey])) {
var oldStore = Cryptpad.getStore(true);
@ -171,7 +174,7 @@ define([
}
return;
}
Cryptpad.alert(Messages.common_connectionLost);
//Cryptpad.alert(Messages.common_connectionLost);
});
};

View File

@ -315,6 +315,37 @@ tr {
font-family: lato, Helvetica, sans-serif;
font-size: 1.02em;
}
#loading {
position: fixed;
z-index: 9999;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
background: #302B28;
text-align: center;
font-size: 1.5em;
}
#loading .loadingContainer {
margin-top: 50vh;
transform: translateY(-50%);
}
#loading .cryptofist {
margin-left: auto;
margin-right: auto;
}
@media screen and (max-height: 450px) {
#loading .cryptofist {
display: none;
}
}
#loading .spinnerContainer {
position: relative;
height: 100px;
}
#loading .spinnerContainer > div {
height: 100px;
}
#main {
width: 70vw;
margin: auto;

View File

@ -139,6 +139,8 @@ define([
});
};
displayCreateButtons();
Cryptpad.ready(function () {
console.log("ready");
@ -149,7 +151,6 @@ define([
DecorateToolbar.main($('#bottom-bar'));
Cryptpad.styleAlerts();
displayCreateButtons();
refreshTable();
if (Cryptpad.store && Cryptpad.store.change) {
Cryptpad.store.change(function (data) {

View File

@ -137,6 +137,36 @@ p, pre, td, a, table, tr {
.lato;
}
#loading {
position: fixed;
z-index: 9999;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
background: @bg-loading;
text-align: center;
font-size: 1.5em;
.loadingContainer {
margin-top: 50vh;
transform: translateY(-50%);
}
.cryptofist {
margin-left: auto;
margin-right: auto;
@media screen and (max-height: 450px) {
display: none;
}
}
.spinnerContainer {
position: relative;
height: 100px;
> div {
height: 100px;
}
}
}
#main {
width: 70vw;
margin: auto;

View File

@ -32,3 +32,4 @@
@alertify-input-bg: @base;
@alertify-input-fg: @fore;
@bg-loading: @base;

View File

@ -19,6 +19,10 @@ define(function () {
].join('');
out.common_connectionLost = 'Connexion au serveur perdue';
out.websocketError = 'Impossible de se connecter au serveur WebSocket...';
out.loading = "Chargement...";
out.error = "Erreur";
out.disconnected = 'Déconnecté';
out.synchronizing = 'Synchronisation';
@ -190,6 +194,10 @@ define(function () {
out.fm_unknownFolderError = "Le dossier sélectionné ou le dernier dossier visité n'existe plus. Ouverture du dossier parent...";
out.fm_contextMenuError = "Impossible d'ouvrir le menu contextuel pour cet élément. Si le problème persiste, essayez de rechercher la page.";
out.fm_selectError = "Impossible de sélectionner l'élément ciblé. Si le problème persiste, essayez de recharger la page.";
out.fm_info_root = "Créez ici autant de dossiers que vous le souhaitez pour trier vos fichiers.";
out.fm_info_unsorted = 'Contient tous les documents que vous avez ouvert et qui ne sont pas triés dans "Mes documents" ou déplacés vers la "Corbeille".'; // "My Documents" should match with the "out.fm_rootName" key, and "Trash" with "out.fm_trashName"
out.fm_info_trash = 'Les fichiers supprimés dans la corbeille sont également enlevés de "Tous les fichiers" et il est impossible de les récupérer depuis l\'explorateur de fichiers.'; // Same here for "All files" and "out.fm_filesDataName"
out.fm_info_allFiles = 'Contient tous les fichiers de "Mes documents", "Fichiers non triés" et "Corbeille". Vous ne pouvez pas supprimer ou déplacer des fichiers d\'ici.'; // Same here
// File - Context menu
out.fc_newfolder = "Nouveau dossier";
out.fc_rename = "Renommer";
@ -208,6 +216,7 @@ define(function () {
out.fo_existingNameError = "Ce nom est déjà utilisé dans ce répertoire. Veuillez en choisir un autre.";
out.fo_moveFolderToChildError = "Vous ne pouvez pas déplacer un dossier dans un de ses descendants";
out.fo_unableToRestore = "Impossible de restaurer ce fichier à son emplacement d'origine. Vous pouvez essayer de le déplacer à un nouvel emplacement.";
out.fo_unavailableName = "Un fichier ou dossier avec le même nom existe déjà au nouvel emplacement. Renommez cet élément avant d'essayer à nouveau.";
// index.html

View File

@ -23,6 +23,9 @@ define(function () {
out.common_connectionLost = 'Server Connection Lost';
out.websocketError = 'Unable to connect to the websocket server...';
out.loading = "Loading...";
out.error = "Error";
out.disconnected = 'Disconnected';
out.synchronizing = 'Synchronizing';
out.reconnecting = 'Reconnecting...';
@ -169,6 +172,7 @@ define(function () {
out.fm_trashName = "Trash";
out.fm_unsortedName = "Unsorted files";
out.fm_filesDataName = "All files";
out.fm_templateName = "Templates";
out.fm_newFolder = "New folder";
out.fm_newFolderButton = "NEW FOLDER";
out.fm_folderName = "Folder name";
@ -189,6 +193,10 @@ define(function () {
out.fm_unknownFolderError = "The selected or last visited directory no longer exist. Opening the parent folder...";
out.fm_contextMenuError = "Unable to open the context menu for that element. If the problem persist, try to reload the page.";
out.fm_selectError = "Unable to select the targetted element. If the problem persist, try to reload the page.";
out.fm_info_root = "Create as many nested folders here as you want to sort your files.";
out.fm_info_unsorted = 'Contains all the files you\'ve visited that are not yet sorted in "My Documents" or moved to the "Trash".'; // "My Documents" should match with the "out.fm_rootName" key, and "Trash" with "out.fm_trashName"
out.fm_info_trash = 'Files deleted from the trash are also removed from "All files" and it is impossible to recover them from the file manager.'; // Same here for "All files" and "out.fm_filesDataName"
out.fm_info_allFiles = 'Contains all the files from "My Documents", "Unsorted" and "Trash". You can\'t move or remove files from here.'; // Same here
// File - Context menu
out.fc_newfolder = "New folder";
out.fc_rename = "Rename";
@ -207,6 +215,7 @@ define(function () {
out.fo_existingNameError = "Name already used in that directory. Please choose another one.";
out.fo_moveFolderToChildError = "You can't move a folder into one of its descendants";
out.fo_unableToRestore = "Unable to restore that file to its original location. You can try to move it to a new location.";
out.fo_unavailableName = "A file or a folder with the same name already exist at the new location. Rename the element and try again.";
// login
out.login_login = "log in";

View File

@ -21,12 +21,10 @@ define([
var module = window.APP = {
Cryptpad: Cryptpad,
spinner: Cryptpad.spinner(document.body),
};
Cryptpad.styleAlerts();
module.spinner.show();
Cryptpad.addLoadingScreen();
var ifrw = module.ifrw = $('#pad-iframe')[0].contentWindow;
var stringify = function (obj) {
@ -43,8 +41,7 @@ define([
}
var onConnectError = function (info) {
module.spinner.hide();
Cryptpad.alert(Messages.websocketError);
Cryptpad.errorLoadingScreen(Messages.websocketError);
};
var andThen = function (CMeditor) {
@ -565,7 +562,7 @@ define([
});
}
$(module.spinner.get().el).fadeOut(750);
Cryptpad.removeLoadingScreen();
setEditable(true);
initializing = false;
//Cryptpad.log("Your document is ready");

View File

@ -409,6 +409,21 @@ define([
return localStorage[attr];
};
// STORAGE - TEMPLATES
var listTemplates = common.listTemplates = function (type) {
var allTemplates = getStore().listTemplates();
if (!type) { return allTemplates; }
var templates = allTemplates.filter(function (f) {
var parsed = parsePadUrl(f.href);
return parsed.type === type;
});
return templates;
};
var addTemplate = common.addTemplate = function (href) {
getStore().addTemplate(href);
};
// STORAGE
/* fetch and migrate your pad history from localStorage */
@ -651,6 +666,26 @@ define([
});
};
var LOADING = 'loading';
common.addLoadingScreen = function () {
var $loading = $('<div>', {id: LOADING});
var $container = $('<div>', {'class': 'loadingContainer'});
$container.append('<img class="cryptofist" src="/customize/cryptofist_small.png" />');
var $spinner = $('<div>', {'class': 'spinnerContainer'});
loadingSpinner = common.spinner($spinner).show();
var $text = $('<p>').text(Messages.loading);
$container.append($spinner).append($text);
$loading.append($container);
$('body').append($loading);
};
common.removeLoadingScreen = function () {
$('#' + LOADING).fadeOut(750);
};
common.errorLoadingScreen = function (error) {
$('.spinnerContainer').hide();
$('#' + LOADING).find('p').text(error || Messages.error);
};
/*
* Saving files
*/
@ -982,17 +1017,17 @@ define([
$(parent).append($target);
var opts = {
lines: 9, // The number of lines to draw
length: 12, // The length of each line
width: 11, // The line thickness
radius: 20, // The radius of the inner circle
lines: 20, // The number of lines to draw
length: 5, // The length of each line
width: 2, // The line thickness
radius: 15, // The radius of the inner circle
scale: 2, // Scales overall size of the spinner
corners: 1, // Corner roundness (0..1)
color: '#777', // #rgb or #rrggbb or array of colors
color: '#ddd', // #rgb or #rrggbb or array of colors
opacity: 0.3, // Opacity of the lines
rotate: 31, // The rotation offset
direction: 1, // 1: clockwise, -1: counterclockwise
speed: 0.9, // Rounds per second
speed: 1, // Rounds per second
trail: 49, // Afterglow percentage
fps: 20, // Frames per second when using setTimeout() as a fallback for CSS
zIndex: 2e9, // The z-index (defaults to 2000000000)
@ -1001,7 +1036,8 @@ define([
left: '50%', // Left position relative to parent
shadow: false, // Whether to render a shadow
hwaccel: false, // Whether to use hardware acceleration
position: 'absolute', // Element positioning
position: 'relative', // Element positioning
height: '100px'
};
var spinner = new Spinner(opts).spin($target[0]);

View File

@ -97,7 +97,7 @@ li {
text-decoration: underline;
}
#tree #trashTree, #tree #unsortedTree, #tree #allfilesTree {
#tree #trashTree, #tree #unsortedTree, #tree #templateTree, #tree #allfilesTree {
margin-top: 2em;
}
@ -186,6 +186,20 @@ li {
padding-left: 10px;
}
#content .info-box {
margin: 0px auto;
padding: 5px;
background: #ddddff;
border: 1px solid #bbb;
border-radius: 5px;
margin-bottom: 10px;
}
#content .info-box span {
cursor: pointer;
margin-left: 10px;
float: right;
}
.topButtonContainer {
border: 1px solid #ccc;
float: right;
@ -249,13 +263,10 @@ li {
flex: 1;
}
#content .list li.file-header {
margin-top: 20px;
}
#content .list li.header {
cursor: default;
color: #008;
margin-top: 10px;
}
#content .list li.header .element span:not(.fa) {
border-right: 1px solid #CCC;

View File

@ -9,6 +9,7 @@ define([
var UNSORTED = "unsorted";
var FILES_DATA = "filesData";
var TRASH = "trash";
var TEMPLATE = "template";
var NEW_FOLDER_NAME = Messages.fm_newFolder;
var init = module.init = function (files, config) {
@ -46,6 +47,12 @@ define([
var isPathInUnsorted = exp.isPathInUnsorted = function (path) {
return path[0] && path[0] === UNSORTED;
};
var isPathInTemplate = exp.isPathInTemplate = function (path) {
return path[0] && path[0] === TEMPLATE;
};
var isPathInHrefArray = exp.isPathInHrefArray = function (path) {
return isPathInUnsorted(path) || isPathInTemplate(path);
};
var isPathInTrash = exp.isPathInTrash = function (path) {
return path[0] && path[0] === TRASH;
};
@ -162,6 +169,13 @@ define([
return files[UNSORTED].slice();
};
var getTemplateFiles = exp.getTemplateFiles = function () {
if (!files[TEMPLATE]) {
files[TEMPLATE] = [];
}
return files[TEMPLATE].slice();
};
var getFilesRecursively = function (root, arr) {
for (var e in root) {
if (isFile(root[e])) {
@ -229,13 +243,15 @@ define([
var checkDeletedFiles = function () {
var rootFiles = getRootFiles();
var unsortedFiles = getUnsortedFiles();
var templateFiles = getTemplateFiles();
var trashFiles = getTrashFiles();
var toRemove = [];
files[FILES_DATA].forEach(function (arr) {
var f = arr.href;
if (rootFiles.indexOf(f) === -1
&& unsortedFiles.indexOf(f) === -1
&& trashFiles.indexOf(f) === -1) {
&& trashFiles.indexOf(f) === -1
&& templateFiles.indexOf(f) === -1) {
toRemove.push(arr);
}
});
@ -254,7 +270,7 @@ define([
var parentEl = exp.findElement(files, parentPath);
if (path.length === 4 && path[0] === TRASH) {
files[TRASH][path[1]].splice(path[2], 1);
} else if (path[0] === UNSORTED) {
} else if (path[0] === UNSORTED) { //TODO || === TEMPLATE
parentEl.splice(key, 1);
} else {
parentEl[key] = undefined;
@ -264,6 +280,7 @@ define([
};
// Find an element in a object following a path, resursively
// NOTE: it is always used with an absolute path and root === files in our code
var findElement = exp.findElement = function (root, pathInput) {
if (!pathInput) {
error("Invalid path:\n", pathInput, "\nin root\n", root);
@ -279,6 +296,7 @@ define([
return findElement(root[key], path);
};
// Get the object {element: element, path: [path]} from a trash root path
var getTrashElementData = exp.getTrashElementData = function (trashPath) {
if (!isInTrashRoot) {
debug("Called getTrashElementData on a element not in trash root: ", trashPath);
@ -289,6 +307,7 @@ define([
return findElement(files, parentPath);
};
// Get data from AllFiles (Cryptpad_RECENTPADS)
var getFileData = exp.getFileData = function (file) {
if (!file) { return; }
var res;
@ -328,6 +347,7 @@ define([
};
// Move to trash
// TODO: rename the function
var removeElement = exp.removeElement = function (path, cb, keepOld) {
if (!path || path.length < 2 || path[0] === TRASH) {
debug("Calling removeElement from a wrong path: ", path);
@ -335,7 +355,7 @@ define([
}
var element = findElement(files, path);
var key = path[path.length - 1];
var name = isPathInUnsorted(path) ? getTitle(element) : key;
var name = isPathInHrefArray(path) ? getTitle(element) : key;
var parentPath = path.slice();
parentPath.pop();
pushToTrash(name, element, parentPath);
@ -353,19 +373,21 @@ define([
var newParent = findElement(files, newParentPath);
// Never move a folder in one of its children
if (isFolder(element) && isSubpath(newParentPath, elementPath)) {
log(Messages.fo_moveFolderToChildError);
return;
}
if (isPathInUnsorted(newParentPath)) {
if (isPathInHrefArray(newParentPath)) {
if (isFolder(element)) {
log(Messages.fo_moveUnsortedError);
log(Messages.fo_moveUnsortedError); //TODO or template
return;
} else {
if (isPathInUnsorted(elementPath)) { return; }
if (files[UNSORTED].indexOf(element) === -1) {
files[UNSORTED].push(element);
if (elementPath[0] === newParentPath[0]) { return; }
var fileRoot = newParentPath[0];
if (files[fileRoot].indexOf(element) === -1) {
files[fileRoot].push(element);
}
if (!keepOld) { deleteFromObject(elementPath); }
if(cb) { cb(); }
@ -375,7 +397,7 @@ define([
var name;
if (isPathInUnsorted(elementPath)) {
if (isPathInHrefArray(elementPath)) {
name = getTitle(element);
} else if (isInTrashRoot(elementPath)) {
// Element from the trash root: elementPath = [TRASH, "{dirName}", 0, 'element']
@ -386,7 +408,7 @@ define([
var newName = !isPathInRoot(elementPath) ? getAvailableName(newParent, name) : name;
if (typeof(newParent[newName]) !== "undefined") {
log("A file with the same name already exist at the new location. Rename the file and try again.");
log(Messages.fo_unavailableName);
return;
}
newParent[newName] = element;
@ -397,13 +419,16 @@ define([
// "Unsorted" is an array of href: we can't move several of them using "moveElement" in a
// loop because moveElement removes the href from the array and it changes the path for all
// the other elements. We have to move them all and then remove them from unsorted
var moveUnsortedElements = exp.moveUnsortedElements = function (paths, newParentPath, cb) {
var moveHrefArrayElements = exp.moveHrefArrayElements = function (paths, newParentPath, cb) {
if (!paths || paths.length === 0) { return; }
if (isPathInUnsorted(newParentPath)) { return; }
//if (isPathInHrefArray(newParentPath)) { return; }
var elements = {};
// Get the elements
paths.forEach(function (p) {
if (!isPathInUnsorted(p)) { return; }
// Here we move only files from array categories (unsorted, template...)
if (!isPathInHrefArray(p)) { return; }
// And we check that we don't want to move to the same location
if (p[0] === newParentPath[0]) { return; }
var el = findElement(files, p);
if (el) { elements[el] = p; }
});
@ -413,22 +438,21 @@ define([
});
// Remove the elements from their old location
Object.keys(elements).forEach(function (el) {
var idx = files[UNSORTED].indexOf(el);
var fileRoot = elements[el][0];
var idx = files[fileRoot].indexOf(el);
if (idx !== -1) {
files[UNSORTED].splice(idx, 1);
files[fileRoot].splice(idx, 1);
}
});
if (cb) { cb(); }
};
var moveElements = exp.moveElements = function (paths, newParentPath, cb) {
var unsortedPaths = paths.filter(function (p) {
return p[0] === UNSORTED;
});
moveUnsortedElements(unsortedPaths, newParentPath);
var unsortedPaths = paths.filter(isPathInHrefArray);
moveHrefArrayElements(unsortedPaths, newParentPath);
// Copy the elements to their new location
paths.forEach(function (p) {
if (isPathInUnsorted(p)) { return; }
if (isPathInHrefArray(p)) { return; }
moveElement(p, newParentPath, null);
});
if(cb) { cb(); }
@ -471,12 +495,13 @@ define([
var element = findElement(files, path);
var parentEl = getTrashElementData(path);
var newPath = parentEl.path;
if (isPathInUnsorted(newPath)) {
if (files[UNSORTED].indexOf(element) === -1) {
files[UNSORTED].push(element);
removeFromTrashArray(parentEl, path[1]);
cb();
if (isPathInHrefArray(newPath)) {
var fileRoot = newPath[0];
if (files[fileRoot].indexOf(element) === -1) {
files[fileRoot].push(element);
}
removeFromTrashArray(parentEl, path[1]);
cb();
return;
}
// Find the new parent element
@ -523,6 +548,7 @@ define([
var emptyTrash = exp.emptyTrash = function (cb) {
files[TRASH] = {};
checkDeletedFiles();
if(cb) { cb(); }
};
@ -569,7 +595,12 @@ define([
var unsortedFiles = getUnsortedFiles();
var rootFiles = getRootFiles();
var trashFiles = getTrashFiles();
if (path && name) {
var templateFiles = getTemplateFiles();
if (path && isPathInHrefArray(path)) {
var parentEl = findElement(files, newPath);
parentEl.push(href);
}
else if (path && name) {
var newPath = decodeURIComponent(path).split(',');
var parentEl = findElement(files, newPath);
if (parentEl) {
@ -578,11 +609,38 @@ define([
return;
}
}
if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1 && trashFiles.indexOf(href) === -1) {
if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1&& templateFiles.indexOf(href) === -1 && trashFiles.indexOf(href) === -1) {
files[UNSORTED].push(href);
}
};
// addTemplate is called when we want to add a new pad, never visited, to the templates list
// first, we must add it to FILES_DATA, so the input has to be an fileDAta object
var addTemplate = exp.addTemplate = function (fileData) {
if (typeof fileData !== "object" || !fileData.href || !fileData.title) { return; }
var href = fileData.href;
var test = files[FILES_DATA].some(function (o) {
o.href === href;
});
if (!test) {
files[FILES_DATA].push(fileData);
}
if (files[TEMPLATE].indexOf(href) === -1) {
files[TEMPLATE].push(href);
}
};
var listTemplates = exp.listTemplates = function (type) {
var templateFiles = getTemplateFiles();
var res = [];
templateFiles.forEach(function (f) {
var data = getFileData(f);
res.push(JSON.parse(JSON.stringify(data)));
});
return res;
};
var uniq = function (a) {
var seen = {};
return a.filter(function(item) {
@ -592,7 +650,7 @@ define([
var fixFiles = exp.fixFiles = function () {
// Explore the tree and check that everything is correct:
// * 'root', 'trash' and 'filesData' exist and are objects
// * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects
// * ROOT: Folders are objects, files are href
// * TRASH: Trash root contains only arrays, each element of the array is an object {element:.., path:..}
// * FILES_DATA: - Data (title, cdate, adte) are stored in filesData. filesData contains only href keys linking to object with title, cdate, adate.
@ -601,16 +659,13 @@ define([
// * UNSORTED: Contains only files (href), and does not contains files that are in ROOT
debug("Cleaning file system...");
// Create a backup
if (typeof(localStorage.oldFileSystem) === "undefined") {
localStorage.oldFileSystem = '[]';
}
var before = JSON.stringify(files);
if (typeof(files[ROOT]) !== "object") { debug("ROOT was not an object"); files[ROOT] = {}; }
if (typeof(files[TRASH]) !== "object") { debug("TRASH was not an object"); files[TRASH] = {}; }
if (!$.isArray(files[FILES_DATA])) { debug("FILES_DATA was not an array"); files[FILES_DATA] = []; }
if (!$.isArray(files[UNSORTED])) { debug("UNSORTED was not an array"); files[UNSORTED] = []; }
if (!$.isArray(files[TEMPLATE])) { debug("TEMPLATE was not an array"); files[TEMPLATE] = []; }
var fixRoot = function (element) {
for (var el in element) {
@ -650,16 +705,42 @@ define([
var fixUnsorted = function (us) {
var rootFiles = getRootFiles().slice();
var templateFiles = getTemplateFiles();
var toClean = [];
us.forEach(function (el, idx) {
if (!isFile(el) || rootFiles.indexOf(el) !== -1) {
if (!isFile(el) || rootFiles.indexOf(el) !== -1 || templateFiles.indexOf(el) !== -1) {
toClean.push(idx);
}
});
toClean.forEach(function (el) {
var idx = us.indexOf(el);
if (idx !== -1) {
us.splice(idx, 1);
}
});
};
files[UNSORTED] = uniq(files[UNSORTED]);
fixUnsorted(files[UNSORTED]);
var fixTemplate = function (us) {
var rootFiles = getRootFiles().slice();
var unsortedFiles = getUnsortedFiles();
var toClean = [];
us.forEach(function (el, idx) {
if (!isFile(el) || rootFiles.indexOf(el) !== -1 || unsortedFiles.indexOf(el) !== -1) {
toClean.push(idx);
}
});
toClean.forEach(function (el) {
var idx = us.indexOf(el);
if (idx !== -1) {
us.splice(idx, 1);
}
});
};
files[TEMPLATE] = uniq(files[TEMPLATE]);
fixUnsorted(files[TEMPLATE]);
var fixFilesData = function (fd) {
var rootFiles = getRootFiles();
var unsortedFiles = getUnsortedFiles();

View File

@ -18,9 +18,15 @@ define([
var $iframe = $('#pad-iframe').contents();
var ifrw = $('#pad-iframe')[0].contentWindow;
//Cryptpad.addLoadingScreen();
var onConnectError = function (info) {
Cryptpad.errorLoadingScreen(Messages.websocketError);
};
var APP = window.APP = {
$bar: $iframe.find('#toolbar'),
editable: false
editable: false,
Cryptpad: Cryptpad
};
var ROOT = "root";
@ -29,6 +35,8 @@ define([
var UNSORTED_NAME = Messages.fm_unsortedName;
var FILES_DATA = Cryptpad.storageKey;
var FILES_DATA_NAME = Messages.fm_filesDataName;
var TEMPLATE = "template";
var TEMPLATE_NAME = Messages.fm_templateName;
var TRASH = "trash";
var TRASH_NAME = Messages.fm_trashName;
var LOCALSTORAGE_LAST = "cryptpad-file-lastOpened";
@ -48,19 +56,13 @@ define([
console.error.apply(console, arguments);
};
var log = config.log = Cryptpad.log;
var DEBUG_LS = APP.DEBUG_LS = {
resetLocalStorage : function () {
delete localStorage[LOCALSTORAGE_OPENED];
delete localStorage[LOCALSTORAGE_LAST];
}
};
var getLastOpenedFolder = function () {
var path;
try {
path = localStorage[LOCALSTORAGE_LAST] ? JSON.parse(localStorage[LOCALSTORAGE_LAST]) : [ROOT];
path = localStorage[LOCALSTORAGE_LAST] ? JSON.parse(localStorage[LOCALSTORAGE_LAST]) : [UNSORTED];
} catch (e) {
path = [ROOT];
path = [UNSORTED];
}
return path;
};
@ -147,7 +149,9 @@ define([
// TOOLBAR
var getLastName = function (cb) {
cb(null, files['cryptpad.username'] || '');
Cryptpad.getAttribute('username', function (err, userName) {
cb(err, userName || '');
});
};
var setName = APP.setName = function (newName) {
@ -157,11 +161,16 @@ define([
myUserNameTemp = myUserNameTemp.substr(0, 32);
}
var myUserName = myUserNameTemp;
files['cryptpad.username'] = myUserName;
APP.userName.lastName = myUserName;
var $button = APP.$userNameButton;
var $span = $('<div>').append($button.find('span').clone()).html();
$button.html($span + myUserName);
Cryptpad.setAttribute('username', myUserName, function (err, data) {
if (err) {
logError("Couldn't set username", err);
return;
}
APP.userName.lastName = myUserName;
var $button = APP.$userNameButton;
var $span = $('<div>').append($button.find('span').clone()).html();
$button.html($span + myUserName);
});
};
var $userBlock = APP.$bar.find('.' + Toolbar.constants.username);
@ -198,6 +207,7 @@ define([
var $fileIcon = $('<span>', {"class": "fa fa-file-text-o file"});
var $upIcon = $('<span>', {"class": "fa fa-arrow-circle-up"});
var $unsortedIcon = $('<span>', {"class": "fa fa-files-o"});
var $templateIcon = $('<span>', {"class": "fa fa-cubes"});
var $trashIcon = $('<span>', {"class": "fa fa-trash"});
var $trashEmptyIcon = $('<span>', {"class": "fa fa-trash-o"});
var $collapseIcon = $('<span>', {"class": "fa fa-minus-square-o expcol"});
@ -206,6 +216,7 @@ define([
var $gridIcon = $('<span>', {"class": "fa fa-th"});
var $sortAscIcon = $('<span>', {"class": "fa fa-angle-up"});
var $sortDescIcon = $('<span>', {"class": "fa fa-angle-down"});
var $closeIcon = $('<span>', {"class": "fa fa-window-close"});
if (!APP.readOnly) {
setEditable(true);
@ -389,7 +400,7 @@ define([
var openDirectoryContextMenu = function (e) {
var $element = $(e.target).closest('li');
$contextMenu.find('li').show();
if ($element.hasClass('file-element')) {
if ($element.find('.file-element').length) {
$contextMenu.find('a.newfolder').parent('li').hide();
}
openContextMenu(e, $contextMenu);
@ -451,6 +462,7 @@ define([
var andThen = function () {
filesOp.moveElements(paths, newPath, cb);
};
// "force" is currently unused but may be configurable by user
if (newPath[0] !== TRASH || force) {
andThen();
return;
@ -662,6 +674,7 @@ define([
if (name === ROOT && path.length === 1) { name = ROOT_NAME; }
else if (name === TRASH && path.length === 1) { name = TRASH_NAME; }
else if (name === UNSORTED && path.length === 1) { name = UNSORTED_NAME; }
else if (name === TEMPLATE && path.length === 1) { name = TEMPLATE_NAME; }
else if (name === FILES_DATA && path.length === 1) { name = FILES_DATA_NAME; }
else if (filesOp.isPathInTrash(path)) { name = getTrashTitle(path); }
var $title = $('<h1>').text(name);
@ -682,6 +695,42 @@ define([
return $title;
};
var createInfoBox = function (path) {
var $box = $('<div>', {'class': 'info-box'});
var msg;
switch (path[0]) {
case 'root':
msg = Messages.fm_info_root;
break;
case 'unsorted':
msg = Messages.fm_info_unsorted;
break;
case 'trash':
msg = Messages.fm_info_trash;
break;
case Cryptpad.storageKey:
msg = Messages.fm_info_allFiles;
break;
default:
msg = undefined;
}
if (!msg || Cryptpad.getLSAttribute('hide-info-' + path[0]) === '1') {
$box.hide();
} else {
$box.text(msg);
var $close = $closeIcon.clone().css({
'cursor': 'pointer',
'margin-left': '10px',
title: Messages.fm_closeInfoBox
}).on('click', function () {
$box.hide();
Cryptpad.setLSAttribute('hide-info-' + path[0], '1');
});
$box.prepend($close);
}
return $box;
};
// Create the button allowing the user to switch from list to icons modes
var createViewModeButton = function () {
var $block = $('<div>', {
@ -743,17 +792,25 @@ define([
var SORT_FOLDER_DESC = 'sortFoldersDesc';
var SORT_FILE_BY = 'sortFilesBy';
var SORT_FILE_DESC = 'sortFilesDesc';
var getSortFileDesc = function () {
return Cryptpad.getLSAttribute(SORT_FILE_DESC) === "true";
};
var getSortFolderDesc = function () {
return Cryptpad.getLSAttribute(SORT_FOLDER_DESC) === "true";
};
var onSortByClick = function (e) {
var $span = $(this);
var value;
if ($span.hasClass('foldername')) {
value = Cryptpad.getLSAttribute(SORT_FOLDER_DESC);
value = getSortFolderDesc();
Cryptpad.setLSAttribute(SORT_FOLDER_DESC, value ? false : true);
refresh();
return;
}
value = Cryptpad.getLSAttribute(SORT_FILE_BY);
var descValue = Cryptpad.getLSAttribute(SORT_FILE_DESC);
var descValue = getSortFileDesc();
if ($span.hasClass('filename')) {
if (value === '') {
descValue = descValue ? false : true;
@ -763,7 +820,7 @@ define([
}
} else {
var found = false;
['title', 'atime', 'ctime'].forEach(function (c) {
['title', 'type', 'atime', 'ctime'].forEach(function (c) {
if (!found && $span.hasClass(c)) {
found = true;
if (value === c) { descValue = descValue ? false : true; }
@ -782,7 +839,7 @@ define([
var addFolderSortIcon = function ($list) {
var $icon = $sortAscIcon.clone();
if (Cryptpad.getLSAttribute(SORT_FOLDER_DESC)) {
if (getSortFolderDesc()) {
$icon = $sortDescIcon.clone();
}
if (typeof(Cryptpad.getLSAttribute(SORT_FOLDER_DESC)) !== "undefined") {
@ -801,7 +858,7 @@ define([
};
var addFileSortIcon = function ($list) {
var $icon = $sortAscIcon.clone();
if (Cryptpad.getLSAttribute(SORT_FILE_DESC)) {
if (getSortFileDesc()) {
$icon = $sortDescIcon.clone();
}
var classSorted;
@ -816,7 +873,7 @@ define([
var $fihElement = $('<span>', {'class': 'element'}).appendTo($fileHeader);
var $fhName = $('<span>', {'class': 'name filename'}).text(Messages.fm_fileName).click(onSortByClick);
var $fhTitle = $('<span>', {'class': 'title '}).text(Messages.fm_title).click(onSortByClick);
var $fhType = $('<span>', {'class': 'type'}).text(Messages.table_type);
var $fhType = $('<span>', {'class': 'type'}).text(Messages.table_type).click(onSortByClick);
var $fhAdate = $('<span>', {'class': 'atime'}).text(Messages.fm_lastAccess).click(onSortByClick);
var $fhCdate = $('<span>', {'class': 'ctime'}).text(Messages.fm_creation).click(onSortByClick);
$fihElement.append($fhName);
@ -847,6 +904,10 @@ define([
if (prop) {
var element = useHref || useData ? el : root[el];
var e = useData ? element : filesOp.getFileData(element);
if (prop === 'type') {
var hrefData = Cryptpad.parsePadUrl(e.href);
return hrefData.type;
}
if (prop === 'atime' || prop === 'ctime') {
return new Date(e[prop]);
}
@ -889,20 +950,20 @@ define([
};
// Unsorted element are represented by "href" in an array: they don't have a filename
// and they don't hav a hierarchical structure (folder/subfolders)
var displayUnsorted = function ($container) {
var unsorted = files[UNSORTED];
if (allFilesSorted()) { return; }
var displayHrefArray = function ($container, rootName) {
var unsorted = files[rootName];
if (rootName === UNSORTED && allFilesSorted()) { return; }
var $fileHeader = getFileListHeader(false);
$container.append($fileHeader);
var keys = unsorted;
var sortedFiles = sortElements(false, [UNSORTED], keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !Cryptpad.getLSAttribute(SORT_FILE_DESC), true);
var sortedFiles = sortElements(false, [rootName], keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !getSortFileDesc(), true);
sortedFiles.forEach(function (href) {
var file = filesOp.getFileData(href);
if (!file) {
debug("getUnsortedFiles returns an element not present in filesData: ", href);
debug("Unsorted or template returns an element not present in filesData: ", href);
return;
}
var idx = files[UNSORTED].indexOf(href);
var idx = files[rootName].indexOf(href);
var $icon = $fileIcon.clone();
var $name = $('<span>', { 'class': 'file-element element' });
addFileData(href, file.title, $name, false);
@ -911,7 +972,7 @@ define([
}).append($icon).append($name).dblclick(function () {
openFile(href);
});
var path = [UNSORTED, idx];
var path = [rootName, idx];
$element.data('path', path);
$element.click(function(e) {
e.stopPropagation();
@ -928,7 +989,7 @@ define([
var $fileHeader = getFileListHeader(false);
$container.append($fileHeader);
var keys = allfiles;
var sortedFiles = sortElements(false, [FILES_DATA], keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !Cryptpad.getLSAttribute(SORT_FILE_DESC), false, true);
var sortedFiles = sortElements(false, [FILES_DATA], keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !getSortFileDesc(), false, true);
sortedFiles.forEach(function (file) {
var $icon = $fileIcon.clone();
var $name = $('<span>', { 'class': 'file-element element' });
@ -969,8 +1030,8 @@ define([
});
});
});
var sortedFolders = sortTrashElements(true, filesList, null, !Cryptpad.getLSAttribute(SORT_FOLDER_DESC));
var sortedFiles = sortTrashElements(false, filesList, Cryptpad.getLSAttribute(SORT_FILE_BY), !Cryptpad.getLSAttribute(SORT_FILE_DESC));
var sortedFolders = sortTrashElements(true, filesList, null, !getSortFolderDesc());
var sortedFiles = sortTrashElements(false, filesList, Cryptpad.getLSAttribute(SORT_FILE_BY), !getSortFileDesc());
if (filesOp.hasSubfolder(root, true)) { $list.append($folderHeader); }
sortedFolders.forEach(function (f) {
var $element = createElement([TRASH], f.spath, root, true);
@ -995,6 +1056,7 @@ define([
}
var isTrashRoot = filesOp.comparePath(path, [TRASH]);
var isUnsorted = filesOp.comparePath(path, [UNSORTED]);
var isTemplate = filesOp.comparePath(path, [TEMPLATE]);
var isAllFiles = filesOp.comparePath(path, [FILES_DATA]);
var root = filesOp.findElement(files, path);
@ -1012,6 +1074,7 @@ define([
setLastOpenedFolder(path);
var $title = createTitle(path);
var $info = createInfoBox(path);
var $dirContent = $('<div>', {id: FOLDER_CONTENT_ID});
$dirContent.data('path', path);
@ -1032,8 +1095,8 @@ define([
var $folderHeader = getFolderListHeader();
var $fileHeader = getFileListHeader(true);
if (isUnsorted) {
displayUnsorted($list);
if (isUnsorted || isTemplate) {
displayHrefArray($list, path[0]);
} else if (isAllFiles) {
displayAllFiles($list);
} else if (isTrashRoot) {
@ -1044,8 +1107,8 @@ define([
if (filesOp.hasSubfolder(root)) { $list.append($folderHeader); }
// display sub directories
var keys = Object.keys(root);
var sortedFolders = sortElements(true, path, keys, null, !Cryptpad.getLSAttribute(SORT_FOLDER_DESC));
var sortedFiles = sortElements(false, path, keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !Cryptpad.getLSAttribute(SORT_FILE_DESC));
var sortedFolders = sortElements(true, path, keys, null, !getSortFolderDesc());
var sortedFiles = sortElements(false, path, keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !getSortFileDesc());
sortedFolders.forEach(function (key) {
if (filesOp.isFile(root[key])) { return; }
var $element = createElement(path, key, root, true);
@ -1059,7 +1122,7 @@ define([
$element.appendTo($list);
});
}
$content.append($title).append($dirContent);
$content.append($title).append($info).append($dirContent);
appStatus.ready(true);
};
@ -1166,6 +1229,15 @@ define([
$container.append($unsortedList);
};
var createTemplate = function ($container, path) {
var $icon = $templateIcon.clone();
var isOpened = filesOp.comparePath(path, currentPath);
var $element = createTreeElement(TEMPLATE_NAME, $icon, [TEMPLATE], false, true, false, isOpened);
$element.addClass('root');
var $list = $('<ul>', { id: 'templateTree' }).append($element);
$container.append($list);
};
var createAllFiles = function ($container, path) {
var $icon = $unsortedIcon.clone();
var isOpened = filesOp.comparePath(path, currentPath);
@ -1199,6 +1271,7 @@ define([
$tree.html('');
createTree($tree, [ROOT]);
createUnsorted($tree, [UNSORTED]);
createTemplate($tree, [TEMPLATE]);
createAllFiles($tree, [FILES_DATA]);
createTrash($tree, [TRASH]);
};
@ -1360,6 +1433,7 @@ define([
pressKey(e.which, false);
});
$(ifrw).on('keydown', function (e) {
// "Del"
if (e.which === 46) {
var $selected = $iframe.find('.selected');
if (!$selected.length) { return; }
@ -1381,7 +1455,7 @@ define([
if (paths.length === 1) {
var path = paths[0];
var element = filesOp.findElement(files, path);
var name = filesOp.isInTrashRoot(path) ? path[1] : (filesOp.isPathInUnsorted(path) ? filesOp.getTitle(element) : path[path.length - 1]);
var name = filesOp.isInTrashRoot(path) ? path[1] : (filesOp.isPathInHrefArray(path) ? filesOp.getTitle(element) : path[path.length - 1]);
msg = Messages._getKey("fm_removePermanentlyDialog", [name]);
}
Cryptpad.confirm(msg, function(res) {
@ -1408,6 +1482,7 @@ define([
files.on('change', [], function (o, n, p) {
var path = arguments[2];
if ((filesOp.isPathInUnsorted(currentPath) && filesOp.isPathInUnsorted(path)) ||
(filesOp.isPathInTemplate(currentPath) && filesOp.isPathInTemplate(path)) ||
(path.length >= currentPath.length && filesOp.isSubpath(path, currentPath)) ||
(filesOp.isPathInTrash(currentPath) && filesOp.isPathInTrash(path))) {
// Reload after a few ms to make sure all the change events have been received
@ -1420,6 +1495,7 @@ define([
}).on('remove', [], function (o, p) {
var path = arguments[1];
if ((filesOp.isPathInUnsorted(currentPath) && filesOp.isPathInUnsorted(path)) ||
(filesOp.isPathInTemplate(currentPath) && filesOp.isPathInTemplate(path)) ||
(path.length >= currentPath.length && filesOp.isSubpath(path, currentPath)) ||
(filesOp.isPathInTrash(currentPath) && filesOp.isPathInTrash(path))) {
// Reload after a few to make sure all the change events have been received
@ -1432,8 +1508,6 @@ define([
refresh();
};
// don't initialize until the store is ready.
Cryptpad.ready(function () {
var storeObj = Cryptpad.getStore().getProxy && Cryptpad.getStore().getProxy().proxy ? Cryptpad.getStore().getProxy() : undefined;
@ -1507,6 +1581,7 @@ define([
var $backupButton = Cryptpad.createButton('', true);
$backupButton.on('click', function() {
var url = window.location.origin + window.location.pathname + '#' + editHash;
//TODO change text & transalte
Cryptpad.alert("Backup URL for this pad. It is highly recommended that you do not share it with other people.<br>Anybody with that URL can remove all the files in your file manager.<br>" + url);
});
$userBlock.append($backupButton);
@ -1521,12 +1596,15 @@ define([
proxy[FILES_DATA] = s;
initLocalStorage();
init(proxy);
APP.userList.onChange();
Cryptpad.removeLoadingScreen();
});
return;
}
initLocalStorage();
init(proxy);
APP.userList.onChange();
Cryptpad.removeLoadingScreen();
};
var onDisconnect = function (info) {
setEditable(false);
@ -1548,6 +1626,11 @@ define([
onDisconnect();
});
});
Cryptpad.onError(function (info) {
if (info) {
onConnectError();
}
});
});

View File

@ -27,6 +27,7 @@ define([
var DiffDom = window.diffDOM;
Cryptpad.styleAlerts();
Cryptpad.addLoadingScreen();
var stringify = function (obj) {
return JSONSortify(obj);
@ -60,7 +61,6 @@ define([
logFights: true,
fights: [],
Cryptpad: Cryptpad,
spinner: Cryptpad.spinner(document.body),
};
var toolbar;
@ -78,8 +78,7 @@ define([
};
var onConnectError = function (info) {
module.spinner.hide();
Cryptpad.alert(Messages.websocketError);
Cryptpad.errorLoadingScreen(Messages.websocketError);
};
var andThen = function (Ckeditor) {
@ -122,7 +121,6 @@ define([
el.setAttribute('class', 'non-realtime');
});
editor.execCommand('maximize');
var documentBody = ifrw.$('iframe')[0].contentDocument.body;
var inner = window.inner = documentBody;
@ -140,9 +138,6 @@ define([
$(inner).css({
color: '#333',
});
$(module.spinner.get().el).fadeOut(750);
} else {
module.spinner.show();
}
if (!readOnly || !bool) {
inner.setAttribute('contenteditable', bool);
@ -633,6 +628,8 @@ define([
// this should only ever get called once, when the chain syncs
var onReady = realtimeOptions.onReady = function (info) {
editor.execCommand('maximize');
module.patchText = TextPatcher.create({
realtime: info.realtime,
//logging: true,
@ -657,6 +654,7 @@ define([
console.log("Unlocking editor");
setEditable(true);
initializing = false;
Cryptpad.removeLoadingScreen();
// Update the toolbar list:
// Add the current user in the metadata if he has edit rights
if (readOnly) { return; }

View File

@ -22,6 +22,11 @@ define([
var secret = Cryptpad.getSecrets();
var readOnly = secret.keys && !secret.keys.editKeyStr;
Cryptpad.addLoadingScreen();
var onConnectError = function (info) {
Cryptpad.errorLoadingScreen(Messages.websocketError);
};
var APP = window.APP = {
Toolbar: Toolbar,
Hyperjson: Hyperjson,
@ -566,6 +571,7 @@ define([
} else {
publish(true);
}
Cryptpad.removeLoadingScreen();
// Update the toolbar list:
// Add the current user in the metadata if he has edit rights
@ -662,11 +668,7 @@ define([
var disconnect = function (info) {
//setEditable(false); // TODO
if (info.error) {
Cryptpad.alert(Messages.websocketError);
return;
}
//Cryptpad.alert(Messages.common_connectionLost); // TODO
Cryptpad.alert(Messages.common_connectionLost);
};
var config = {
@ -715,5 +717,10 @@ define([
}
});
});
Cryptpad.onError(function (info) {
if (info) {
onConnectError();
}
});
});

View File

@ -22,7 +22,6 @@ define([
var module = window.APP = {
Cryptpad: Cryptpad,
spinner: Cryptpad.spinner(document.body),
TextPatcher: TextPatcher,
Slide: Slide,
};
@ -32,7 +31,7 @@ define([
var SLIDE_COLOR_ID = "cryptpad-color";
Cryptpad.styleAlerts();
module.spinner.show();
Cryptpad.addLoadingScreen();
var stringify = function (obj) {
return JSONSortify(obj);
@ -60,8 +59,7 @@ define([
var presentMode = Slide.isPresentURL();
var onConnectError = function (info) {
module.spinner.hide();
Cryptpad.alert(Messages.websocketError);
Cryptpad.errorLoadingScreen(Messages.websocketError);
};
var andThen = function (CMeditor) {
@ -663,7 +661,7 @@ define([
document.title = APP.title;
});
$(module.spinner.get().el).fadeOut(750);
Cryptpad.removeLoadingScreen();
setEditable(true);
initializing = false;
//Cryptpad.log("Your document is ready");