From d8c18d0937a27caf15bb2db1cdc3e80a5b5abd97 Mon Sep 17 00:00:00 2001 From: felixboehm Date: Thu, 29 Dec 2016 22:02:03 +0100 Subject: [PATCH 01/88] adding docker and docker-compose --- .dockerignore | 5 ++++ .env | 4 +++ .gitignore | 1 + Dockerfile | 43 +++++++++++++++++++++++++++++ container-start.sh | 23 ++++++++++++++++ cryptpad-docker.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 23 ++++++++++++++++ readme.md | 4 +++ 8 files changed, 172 insertions(+) create mode 100644 .dockerignore create mode 100644 .env create mode 100644 Dockerfile create mode 100644 container-start.sh create mode 100644 cryptpad-docker.md create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..880c21fe3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +data +Dockerfile +docker-compose.yml +.git +.gitignore \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 000000000..95961b566 --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +VERSION=latest +USE_SSL=true +STORAGE='./storage/file' +LOG_TO_STDOUT=true \ No newline at end of file diff --git a/.gitignore b/.gitignore index 354096b87..a251b70b3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ customization /customize/ messages.log .DS_Store +data \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..99b915055 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,43 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y \ + vim \ + wget \ + git \ + curl \ + npm \ + nodejs-legacy + +ARG VERSION=0.3.0 + +# Download stable version +# RUN wget https://github.com/xwiki-labs/cryptpad/archive /${VERSION}.tar.gz -O /cryptpad.tar.gz \ +# && mkdir -p /cryptpad \ +# && tar -xzf /cryptpad.tar.gz -C /cryptpad --strip-components=1 \ +# && rm /cryptpad.tar.gz + +# Download from github +# RUN git clone https://github.com/xwiki-labs/cryptpad.git + +# Add code directly +ADD . /cryptpad + +WORKDIR /cryptpad + +RUN npm install \ + && npm install -g bower \ + && bower install --allow-root + +ADD container-start.sh /container-start.sh +RUN chmod u+x /container-start.sh + +EXPOSE 3000 + +VOLUME /cryptpad/datastore +VOLUME /cryptpad/customize + +ENV USE_SSL=false +ENV STORAGE='./storage/file' +ENV LOG_TO_STDOUT=true + +CMD /container-start.sh \ No newline at end of file diff --git a/container-start.sh b/container-start.sh new file mode 100644 index 000000000..db0bb924a --- /dev/null +++ b/container-start.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Creating customize folder +mkdir -p customize +[[ ! "$(ls -A customize)" ]] && echo "Creating customize folder" \ + && cp -R customize.dist/* customize/ \ + && cp config.js.dist customize/config.js + +# Linking config.js +[[ ! -h config.js ]] && echo "Linking config.js" && ln -s customize/config.js config.js + +# Configure +[[ -n "$USE_SSL" ]] && echo "Using secure websockets: $USE_SSL" \ + && sed -i "s/useSecureWebsockets: .*/useSecureWebsockets: ${USE_SSL},/g" customize/config.js + +[[ -n "$USE_SSL" ]] && echo "Using storage adapter: $STORAGE" \ + && sed -i "s/storage: .*/storage: ${STORAGE},/g" customize/config.js + +[[ -n "$LOG_TO_STDOUT" ]] && echo "Logging to stdout: $LOG_TO_STDOUT" \ + && sed -i "s/logToStdout: .*/logToStdout: ${LOG_TO_STDOUT},/g" customize/config.js + + +exec node ./server.js \ No newline at end of file diff --git a/cryptpad-docker.md b/cryptpad-docker.md new file mode 100644 index 000000000..1beb2412d --- /dev/null +++ b/cryptpad-docker.md @@ -0,0 +1,69 @@ +# Cryptpad Docker Image + +- Configuration via .env file +- Ready for use with traffic +- Using github master for now, release 0.3.0 too old +- Creating customize folder +- Adding config.js to customize folder +- Persistance for datastore and customize folder + +## TODO + +``` +cryptpad_1 | Linking config.js +cryptpad_1 | Using secure websockets: true +cryptpad_1 | Using storage adapter: './storage/file' +cryptpad_1 | sed: -e expression #1, char 27: unknown option to `s' +``` + +## Configuration + +Set configurations Dockerfile or in .env (using docker-compose) file. + +- VERSION=latest +- USE_SSL=false +- STORAGE='./storage/file' +- LOG_TO_STDOUT=true + +The .env variables are read by docker-compose and forwarded to docker container. +On runtime, in `bin/container-start.sh` the settings are written to the `config.js` file. + +## Run + +With docker + +``` +docker build -t xwiki/cryptpad . +docker -d --name cryptpad -p 3000:3000 -v ${PWD}/data:/cryptpad/datastore xwiki/cryptpad +``` + +With docker-compose + +``` +docker-compose up -d +``` + + +## Persistance + +The docker-compose file is preconfigured to persist folders + +- cryptpad/datastore --> ./data/customize +- cryptpad/customize --> ./data/customize + +In customize included find your configuration in `config.js`. + +The data folder is ignored by git, so if you want to add your customizations to git versioning change the volume: + +``` +./customize:/cryptpad/customize:rw +``` + +## SSL Proxy + +The [traefik](https://traefik.io/) proxy has builtin Let'sEncrypt for easy SSL setup. +In the docker-compose file you can find preset lables for usage with traefik. + +[Traefik Docker Image](https://hub.docker.com/_/traefik/) + +Alternativly just use plain old nginx. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..22cc3d59e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +version: '2' +services: + + cryptpad: + build: + context: . + args: + - VERSION=${VERSION} + image: "xwiki/cryptpad:${VERSION}" + hostname: cryptpad + + labels: + - traefik.port=3000 + - traefik.frontend.passHostHeader=true + environment: + - USE_SSL=${USE_SSL} + - STORAGE=${STORAGE} + - LOG_TO_STDOUT=${LOG_TO_STDOUT} + + restart: always + volumes: + - ./data/files:/cryptpad/datastore:rw + - ./data/customize:/cryptpad/customize:rw diff --git a/readme.md b/readme.md index e2dab9d9c..083d44431 100644 --- a/readme.md +++ b/readme.md @@ -82,6 +82,10 @@ To test CryptPad, go to http://your.server:3000/assert/ You can use WebDriver to run this test automatically by running TestSelenium.js but you will need chromedriver installed. If you use Mac, you can `brew install chromedriver`. +# Setup using Docker + +See [Cryptpad-Docker](cryptpad-docker.md) + ## Security CryptPad is *private*, not *anonymous*. Privacy protects your data, anonymity protects you. From 7c0df5aed9ad8b92bd5d093e9194681cfa7f6b21 Mon Sep 17 00:00:00 2001 From: felixboehm Date: Mon, 2 Jan 2017 11:54:50 +0100 Subject: [PATCH 02/88] use wss if useSecureWebsockets is true There are no certs / httpOtps set if proxy doing ssl offloading. Better use useSecureWebsockets from config file. --- server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index f24117bd1..31d536de8 100644 --- a/server.js +++ b/server.js @@ -11,6 +11,7 @@ var WebRTCSrv = require('./WebRTCSrv'); var config = require('./config'); var websocketPort = config.websocketPort || config.httpPort; +var useSecureWebsockets = config.useSecureWebsockets || false; // support multiple storage back ends var Storage = require(config.storage||'./storage/file'); @@ -80,7 +81,7 @@ app.get('/api/config', function(req, res){ res.setHeader('Content-Type', 'text/javascript'); res.send('define(' + JSON.stringify({ websocketPath: config.websocketPath, - websocketURL:'ws' + ((httpsOpts) ? 's' : '') + '://' + host + ':' + + websocketURL:'ws' + ((useSecureWebsockets) ? 's' : '') + '://' + host + ':' + websocketPort + '/cryptpad_websocket', }) + ');'); }); From d5561910d452023061e193cdc7ed6674ffdd6e01 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 6 Jan 2017 18:26:41 +0100 Subject: [PATCH 03/88] Move the file manager into /drive and add a toolbar --- customize.dist/fsStore.js | 2 +- customize.dist/translations/messages.fr.js | 15 ++-- customize.dist/translations/messages.js | 9 ++- www/{file => common}/fileObject.js | 8 ++ www/{file => drive}/file.css | 29 +++++++ www/{file => drive}/index.html | 2 +- www/{file => drive}/inner.html | 0 www/{file => drive}/main.js | 92 +++++++++++++++------- 8 files changed, 117 insertions(+), 40 deletions(-) rename www/{file => common}/fileObject.js (98%) rename www/{file => drive}/file.css (92%) rename www/{file => drive}/index.html (97%) rename www/{file => drive}/inner.html (100%) rename www/{file => drive}/main.js (96%) diff --git a/customize.dist/fsStore.js b/customize.dist/fsStore.js index db94393a9..bea193fa1 100644 --- a/customize.dist/fsStore.js +++ b/customize.dist/fsStore.js @@ -4,7 +4,7 @@ define([ '/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/chainpad-crypto/crypto.js', '/bower_components/textpatcher/TextPatcher.amd.js', - '/file/fileObject.js' + '/common/fileObject.js' ], function (Config, Messages, Listmap, Crypto, TextPatcher, FO) { /* This module uses localStorage, which is synchronous, but exposes an diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index ac72aefc6..31bf2df6b 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -170,7 +170,7 @@ define(function () { // File manager - out.fm_rootName = "Mes documents"; + out.fm_rootName = "Documents"; out.fm_trashName = "Corbeille"; out.fm_unsortedName = "Fichiers non triés"; out.fm_filesDataName = "Tous les fichiers"; @@ -185,6 +185,7 @@ define(function () { out.fm_creation = "Création"; out.fm_forbidden = "Action interdite"; out.fm_originalPath = "Chemin d'origine"; + out.fm_noname = "Document sans titre"; out.fm_emptyTrashDialog = "Êtes-vous sûr de vouloir vider la corbeille ?"; out.fm_removeSeveralPermanentlyDialog = "Êtes-vous sûr de vouloir supprimer ces {0} éléments de manière permanente ?"; out.fm_removePermanentlyDialog = "Êtes-vous sûr de vouloir supprimer {0} de manière permanente ?"; @@ -195,9 +196,9 @@ define(function () { 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_unsorted = 'Contient tous les documents que vous avez ouvert et qui ne sont pas triés dans "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 + out.fm_info_allFiles = 'Contient tous les fichiers de "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"; @@ -234,10 +235,10 @@ define(function () { out.table_created = 'Créé le'; out.table_last = 'Dernier accès'; - out.button_newpad = 'CRÉER UN PAD WYSIWYG'; - out.button_newcode = 'CRÉER UN PAD DE CODE'; - out.button_newpoll = 'CRÉER UN SONDAGE'; - out.button_newslide = 'CRÉER UNE PRÉSENTATION'; + out.button_newpad = 'NOUVEAU DOCUMENT TEXTE'; + out.button_newcode = 'NOUVELLE PAGE DE CODE'; + out.button_newpoll = 'NOUVEAU SONDAGE'; + out.button_newslide = 'NOUVELLE PRÉSENTATION'; // privacy.html diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 36c48315b..146c5f655 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -9,7 +9,7 @@ define(function () { out.main_slogan = "Unity is Strength - Collaboration is Key"; out.type = {}; - out.type.pad = 'Pad'; + out.type.pad = 'Rich text'; out.type.code = 'Code'; out.type.poll = 'Poll'; out.type.slide = 'Presentation'; @@ -171,7 +171,7 @@ define(function () { // File manager - out.fm_rootName = "My documents"; + out.fm_rootName = "Documents"; out.fm_trashName = "Trash"; out.fm_unsortedName = "Unsorted files"; out.fm_filesDataName = "All files"; @@ -187,6 +187,7 @@ define(function () { out.fm_creation = "Creation"; out.fm_forbidden = "Forbidden action"; out.fm_originalPath = "Original path"; + out.fm_noname = "Untitled Document"; out.fm_emptyTrashDialog = "Are you sure you want to empty the trash?"; out.fm_removeSeveralPermanentlyDialog = "Are you sure you want to remove these {0} elements from the trash permanently?"; out.fm_removePermanentlyDialog = "Are you sure you want to remove {0} permanently?"; @@ -197,9 +198,9 @@ define(function () { 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_unsorted = 'Contains all the files you\'ve visited that are not yet sorted in "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 + out.fm_info_allFiles = 'Contains all the files from "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"; diff --git a/www/file/fileObject.js b/www/common/fileObject.js similarity index 98% rename from www/file/fileObject.js rename to www/common/fileObject.js index e29adfb20..2f26f3dab 100644 --- a/www/file/fileObject.js +++ b/www/common/fileObject.js @@ -264,6 +264,14 @@ define([ if (idx !== -1) { debug("Removing", f, "from filesData"); files[FILES_DATA].splice(idx, 1); + Object.keys(files).forEach(function (key) { + var hash = f.href.indexOf('#') !== -1 ? f.href.slice(f.href.indexOf('#') + 1) : null; + if (hash && key.indexOf(hash) === 0) { + debug("Deleting pad attribute in the realtime object"); + files[key] = undefined; + delete files[key]; + } + }); } }); }; diff --git a/www/file/file.css b/www/drive/file.css similarity index 92% rename from www/file/file.css rename to www/drive/file.css index 1d2f7e1ec..fbf914a13 100644 --- a/www/file/file.css +++ b/www/drive/file.css @@ -184,6 +184,7 @@ li { #content h1 { padding-left: 10px; + margin-top: 10px; } #content .info-box { @@ -325,3 +326,31 @@ li { display: inline; } } + +/* Toolbar */ + +#driveToolbar { + background: #ccc; + height: 40px; +} + +.newPadContainer { + display: inline-block; + height: 100%; +} + +button.newElement { + border-radius: 0px; + height: 30px; + margin: 5px 5px; + background: #888; + color: #eee; + font-size: 15px; + border: none; + font-weight: bold; +} + +button.newElement:hover { + box-shadow: 0px 0px 2px #000; +} + diff --git a/www/file/index.html b/www/drive/index.html similarity index 97% rename from www/file/index.html rename to www/drive/index.html index dfb1ab14a..dd6f8c75c 100644 --- a/www/file/index.html +++ b/www/drive/index.html @@ -1,7 +1,7 @@ - CryptFiles + CryptDrive ', {'class': 'type listElement', title: type}).text(type); var $adate = $('', {'class': 'atime listElement', title: getDate(data.atime)}).text(getDate(data.atime)); var $cdate = $('', {'class': 'ctime listElement', title: getDate(data.ctime)}).text(getDate(data.ctime)); - if (displayTitle && ownFileManager()) { + if (displayTitle && !isWorkgroup()) { $span.append($title); } $span.append($type); - if (ownFileManager()) { + if (!isWorkgroup()) { $span.append($adate).append($cdate); } }; @@ -833,12 +839,8 @@ define([ }; var createNewFolderButton = function () { - var $block = $('
', { - 'class': 'btn-group topButtonContainer newFolderButtonContainer' - }); - var $listButton = $('
- diff --git a/customize.dist/src/less/cryptpad.less b/customize.dist/src/less/cryptpad.less index 44b248438..dbed153d3 100644 --- a/customize.dist/src/less/cryptpad.less +++ b/customize.dist/src/less/cryptpad.less @@ -22,6 +22,7 @@ html.cp, .cp body { top: 80px; right: 0px; display: inline-block; + z-index: 2; } } diff --git a/customize.dist/src/less/variables.less b/customize.dist/src/less/variables.less index 1d2230326..c79834a62 100644 --- a/customize.dist/src/less/variables.less +++ b/customize.dist/src/less/variables.less @@ -1,7 +1,7 @@ -@base: #ddd; +@base: #302B28; @light-base: lighten(@base, 20%); @less-light-base: lighten(@base, 10%); -@fore: #111; +@fore: #fafafa; @cp-green: #46E981; @cp-accent: lighten(@cp-green, 20%); diff --git a/customize.dist/terms.html b/customize.dist/terms.html index 6722e3586..abb25586c 100644 --- a/customize.dist/terms.html +++ b/customize.dist/terms.html @@ -25,21 +25,21 @@ - About + About - Privacy + Privacy - ToS + ToS - Contact + Contact - + diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 19e752e05..e3e73dd3b 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -255,6 +255,14 @@ define(function () { out.button_newpoll = 'NOUVEAU SONDAGE'; out.button_newslide = 'NOUVELLE PRÉSENTATION'; + out.form_username = "Nom d'utilisateur"; + out.form_password = "Mot de passe"; + + out.about = "À propos"; + out.privacy = "Vie privée"; + out.contact = "Contact"; + out.terms = "Conditions"; + // privacy.html out.policy_title = 'Politique de confidentialité de Cryptpad'; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 0bf478e03..7a22e6107 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -238,6 +238,7 @@ define(function () { // login out.login_login = "log in"; + out.login_nologin = "use cryptpad without account"; out.login_register = "register"; out.logoutButton = "log out"; @@ -301,6 +302,11 @@ define(function () { out.form_username = "Username"; out.form_password = "Password"; + out.about = "About"; + out.privacy = "Privacy"; + out.contact = "Contact"; + out.terms = "ToS"; + // privacy.html out.policy_title = 'Cryptpad Privacy Policy'; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 9ae31a238..c0fe4498f 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -101,6 +101,11 @@ define([ return hash; }; + var isLoggedIn = common.isLoggedIn = function () { + //return typeof getStore().getLoginName() === "string"; + return typeof getUserHash() === "string"; + }; + // var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; }; var isArray = common.isArray = $.isArray; diff --git a/www/user/main.js b/www/user/main.js index fc159e314..2da1aaebc 100644 --- a/www/user/main.js +++ b/www/user/main.js @@ -287,7 +287,6 @@ define([ }; var rt = APP.rt = Listmap.create(config); - rt.proxy.on('create', function (info) { APP.realtime = info.realtime; }) @@ -350,5 +349,21 @@ define([ }, 75); }); }); + + if (sessionStorage.login) { + $username.val(sessionStorage.login_user); + $password.val(sessionStorage.login_pass); + $remember.attr('checked', sessionStorage.login_rmb === "true"); + $login.click(); + } + if (sessionStorage.register) { + $username.val(sessionStorage.login_user); + $password.val(sessionStorage.login_pass); + $remember.attr('checked', sessionStorage.login_rmb === "true"); + } + ['login', 'register', 'login_user', 'login_pass', 'login_rmb'].forEach(function (k) { + delete sessionStorage[k]; + }); + }); }); From 73d424b506a3f5ed3466aab6e57c650436c648fb Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 17 Jan 2017 16:21:12 +0100 Subject: [PATCH 42/88] Improve the login UI (css and translations) --- customize.dist/index.html | 2 +- customize.dist/main.css | 2 +- customize.dist/src/fragments/index.html | 2 +- customize.dist/src/less/cryptpad.less | 8 +--- customize.dist/translations/messages.fr.js | 49 ++++++++++++++++++++-- customize.dist/translations/messages.js | 20 ++++----- www/common/toolbar.js | 12 +++++- www/user/index.html | 8 +++- www/user/main.js | 37 +++++++++++++--- 9 files changed, 105 insertions(+), 35 deletions(-) diff --git a/customize.dist/index.html b/customize.dist/index.html index 9a874b38f..a8cd4a4f5 100644 --- a/customize.dist/index.html +++ b/customize.dist/index.html @@ -76,7 +76,7 @@
-

Join Us!

+



diff --git a/customize.dist/main.css b/customize.dist/main.css index c31dc4408..f3327e0df 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -618,7 +618,6 @@ html.cp, margin-left: 50px; display: inline-block; width: 400px; - height: 350px; background-color: rgba(34, 177, 221, 0.8); padding: 10px; box-sizing: border-box; @@ -628,6 +627,7 @@ html.cp, .cp #main #userForm h1, .cp #main_other #userForm h1 { color: black; + padding: 0; } .cp #main #userForm [type="text"], .cp #main_other #userForm [type="text"], diff --git a/customize.dist/src/fragments/index.html b/customize.dist/src/fragments/index.html index e9190eae6..37a5cba34 100644 --- a/customize.dist/src/fragments/index.html +++ b/customize.dist/src/fragments/index.html @@ -15,7 +15,7 @@
-

Join Us!

+



diff --git a/customize.dist/src/less/cryptpad.less b/customize.dist/src/less/cryptpad.less index dbed153d3..2f06decbf 100644 --- a/customize.dist/src/less/cryptpad.less +++ b/customize.dist/src/less/cryptpad.less @@ -158,12 +158,6 @@ body.html { //margin-top: 100px; font-size: medium; - //padding-bottom: 1em; - - // Vertical positioning (middle) - //margin-top: 50vh; - //transform: translateY( ~"calc(40px - 50%)" ); //" - #data { p { @@ -191,7 +185,6 @@ body.html { margin-left: 50px; display: inline-block; width: 400px; - height: 350px; background-color: rgba(34, 177, 221, 0.8); padding: 10px; box-sizing: border-box; @@ -200,6 +193,7 @@ body.html { h1 { color: black; + padding: 0; } [type="text"], [type="password"] { diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index e3e73dd3b..9fa43247a 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -1,6 +1,8 @@ define(function () { var out = {}; + // translations must set this key for their language to be available in + // the language dropdowns that are shown throughout Cryptpad's interface out._languageName = "Français"; out.main_title = "Cryptpad: Éditeur collaboratif en temps réel, zero knowledge"; @@ -61,9 +63,7 @@ define(function () { out.userButton = 'UTILISATEUR'; out.userButtonTitle = "Changer votre nom d'utilisateur"; out.changeNamePrompt = 'Changer votre nom (laisser vide pour rester anonyme) : '; - out.user_login = "Connexion"; - out.user_logout = "Déconnexion"; - out.user_rename = "Changer le nom affiché"; + out.user_rename = "Changer le nmm affiché"; out.user_displayName = "Nom affiché"; out.user_accountName = "Nom d'utilisateur"; @@ -118,10 +118,12 @@ define(function () { out.recentPadsIframe = 'Vos documents récents'; out.okButton = 'OK (Entrée)'; + + out.cancel = "Annuler"; out.cancelButton = 'Annuler (Echap)'; out.loginText = '

Votre nom d\'utilisateur et votre mot de passe sont utilisés pour générer une clé unique qui reste inconnue de notre serveur.

\n' + - '

Faites attention de ne pas oublier vos identifiants puisqu\'ils seront impossible à récupérer.

'; + '

Faites attention de ne pas oublier vos identifiants puisqu\'ils seront impossible à récupérer.

'; //TODO out.forget = "Oublier"; @@ -181,6 +183,7 @@ define(function () { out.fm_trashName = "Corbeille"; out.fm_unsortedName = "Fichiers non triés"; out.fm_filesDataName = "Tous les fichiers"; + out.fm_templateName = "Modèles"; out.fm_newButton = "Nouveau"; out.fm_newFolder = "Nouveau dossier"; out.fm_folder = "Dossier"; @@ -234,6 +237,43 @@ define(function () { 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."; + // login + out.login_login = "Connexion"; + out.login_nologin = "Utiliser une session anonyme"; + out.login_register = "Inscription"; + out.logoutButton = "Déconnexion"; + + out.login_migrate = "Souhaitez-vous importer les données existantes de votre session anonyme ?"; + + out.username_label = "Nom d'utilisateur : "; + out.displayname_label = "Nom affiché : "; + + out.login_username = "votre nom d'utilisateur"; + out.login_password = "votre mot de passe"; + out.login_confirm = "confirmer votre mot de passe"; + out.login_remember = "Se souvenir de moi"; + + out.login_cancel_prompt = "...ou si vous avez entré le mauvais nom d'utilisateur ou mot de passe, annulez pour essayer à nouveau."; + + out.login_registerSuccess = "Inscription réalisée avec succès. Prenez soin de ne pas oublier votre mot de passe !"; + out.login_passwordMismatch = "Les deux mots de passe entrés sont différents. Essayez à nouveau."; + + out.login_warning = [ + '

ATTENTION

', + '

Cryptpad sauve vos données personnelles dans un document temps-réel chiffré, comme pour tous les autres types de documents temps-réel.

', + '

Votre nom d\'utilisateur et votre mot de passe ne sont jamais envoyés au serveur de manière non-chiffré.

', + '

Ainsi, si vous oubliez votre nom d\'utilisateur ou votre mot de passe, il n\'y a absolument rien que nous puissions faire pour retrouver vos informations perdues.

', + '

Prenez soin de ne surtout pas oublier votre nom d\'utilisateur OU votre mot de passe !

', + ].join('\n'); + + out.login_hashing = "Traitement de vos identifiants, cela peut nécessiter quelques instants."; + + out.login_no_user = "Il n'y a aucun utilisateur associé au nom et au mot de passe que vous avez entré."; + out.login_confirm_password = "Veuillez taper de nouveau votre mot de passe pour vous inscrire..."; + + out.loginText = '

Votre nom d\'utilisateur et votre mot d epasse sont utilisés pour générer une clé unique qui reste inconnue de notre serveur.

\n' + + '

Faîtes attention de ne pas perdre vos identifiants, puisqu\'il est impossible de les récupérer

'; + // index.html out.main_p1 = 'CryptPad est l\'éditeur collaboratif en temps réel zero knowledge. Le chiffrement est effectué depuis votre navigateur, ce qui protège les données contre le serveur, le cloud, et la NSA. La clé de chiffrement est stockée dans l\'identifieur de fragment de l\'URL qui n\'est jamais envoyée au serveur mais est accessible depuis javascript, de sorte qu\'en partageant l\'URL, vous donnez l\'accès au pad à ceux qui souhaitent participer.'; @@ -255,6 +295,7 @@ define(function () { out.button_newpoll = 'NOUVEAU SONDAGE'; out.button_newslide = 'NOUVELLE PRÉSENTATION'; + out.form_title = "Tous vos pads, partout où vous allez !"; out.form_username = "Nom d'utilisateur"; out.form_password = "Mot de passe"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 7a22e6107..c0df35751 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -63,8 +63,6 @@ define(function () { out.userButton = 'USER'; out.userButtonTitle = 'Change your username'; out.changeNamePrompt = 'Change your name (leave empty to be anonymous): '; - out.user_login = "Log in"; - out.user_logout = "Log out"; out.user_rename = "Change display name"; out.user_displayName = "Display name"; out.user_accountName = "Account name"; @@ -121,7 +119,7 @@ define(function () { out.okButton = 'OK (enter)'; - out.cancel = "cancel"; + out.cancel = "Cancel"; out.cancelButton = 'Cancel (esc)'; out.forget = "Forget"; @@ -237,10 +235,10 @@ define(function () { 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"; - out.login_nologin = "use cryptpad without account"; - out.login_register = "register"; - out.logoutButton = "log out"; + out.login_login = "Log in"; + out.login_nologin = "Use an anonymous session"; + out.login_register = "Sign up"; + out.logoutButton = "Log out"; out.login_migrate = "Would you like to migrate existing data from your anonymous session?"; @@ -250,7 +248,7 @@ define(function () { out.login_username = "your username"; out.login_password = "your password"; out.login_confirm = "confirm your password"; - out.login_remember = "remember me"; + out.login_remember = "Remember me"; out.login_cancel_prompt = "...or if you may have entered the wrong username or password, cancel to try again."; @@ -265,11 +263,6 @@ define(function () { '

Make sure you do not forget your username and password!

', ].join('\n'); - out.login_logout = [ - //'

It seems you are already logged in

', - //'

Would you like to log out and authenticate as another user?

', - ].join('\n'); - out.login_hashing = "Hashing your password, this might take some time."; out.login_no_user = "There is no user associated with the username and password that you entered."; @@ -299,6 +292,7 @@ define(function () { out.button_newpoll = 'NEW POLL'; out.button_newslide = 'NEW PRESENTATION'; + out.form_title = "All your pads, everywhere!"; out.form_username = "Username"; out.form_password = "Password"; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index ada2534aa..83a6e02c6 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -389,13 +389,18 @@ define([ options.push({ tag: 'a', attributes: {'class': 'logout'}, - content: Messages.user_logout + content: Messages.logoutButton }); } else { options.push({ tag: 'a', attributes: {'class': 'login'}, - content: Messages.user_login + content: Messages.login_login + }); + options.push({ + tag: 'a', + attributes: {'class': 'register'}, + content: Messages.login_register }); } var $icon = $('', {'class': 'fa fa-user'}); @@ -418,6 +423,9 @@ define([ $userAdmin.find('a.login').click(function (e) { window.open('/user'); }); + $userAdmin.find('a.register').click(function (e) { + window.open('/user#register'); + }); if (config.userName && config.userName.setName && config.userName.lastName) { $userAdmin.find('a.' + USERBUTTON_CLS).click(function (e) { diff --git a/www/user/index.html b/www/user/index.html index 5f27377ba..b4e7eb2ac 100644 --- a/www/user/index.html +++ b/www/user/index.html @@ -25,6 +25,11 @@ display: none; border-radius: 5px; } + + .register { + display: none; + } + @media (max-width: 1000px) { div.panel { width: 90%; } } @@ -49,6 +54,7 @@


+
@@ -83,6 +89,6 @@

-

View your file manager.

+

View your CryptDrive.

diff --git a/www/user/main.js b/www/user/main.js index 2da1aaebc..b658ef76a 100644 --- a/www/user/main.js +++ b/www/user/main.js @@ -23,8 +23,10 @@ define([ // login elements var $loginBox = $('#login-panel'); var $login = $('#login'); + var $login_register = $('#login_register'); var $username = $('#username'); var $password = $('#password'); + var $password_register = $('#confirm_register'); var $remember = $('#remember'); // hashing elements @@ -61,7 +63,13 @@ define([ var revealConfirm = APP.revealConfirm = revealer($confirmBox); var revealLogout = APP.revealLogout= revealer($logoutBox); - var revealUser = APP.revealUser = revealer($userBox); + var revealUser_false = APP.revealUser_false = revealer($userBox); + var revealUser = APP.revealUser = function (state) { + if (!state) { + revealUser_false(state); + } + document.location.href = '/drive'; + }; var getDisplayName = APP.getDisplayName = function (proxy) { return proxy['cryptpad.username']; @@ -186,9 +194,9 @@ define([ }; }; - var handleNewUser = function (proxy, opt) { + var handleNewUser = function (proxy, opt, force) { // could not find a profile for that username/password - confirmPassword(proxy, opt.password, function () { + var todo = function () { APP.confirming = false; APP.setAccountName((proxy.login_name = opt.name)); APP.setDisplayName(APP.getDisplayName(proxy)); @@ -229,7 +237,12 @@ define([ }); }); }); - }); + }; + if (force) { + todo(); + return; + } + confirmPassword(proxy, opt.password, todo); }; var handleUser = function (proxy, opt) { @@ -237,6 +250,9 @@ define([ var now = opt.now = +(new Date()); if (!proxyKeys.length) { + if (opt.register) { + return handleNewUser(proxy, opt, true); + } return handleNewUser(proxy, opt); } handleRegisteredUser(proxy, opt); @@ -309,6 +325,11 @@ define([ revealUser(true); } else { + if (sessionStorage.register || document.location.hash.slice(1) === 'register') { + document.location.hash = 'register'; + $login.text(Cryptpad.Messages.login_register); + $('#login-panel .register').show(); + } revealLogin(true); } @@ -317,9 +338,15 @@ define([ $login.click(function () { var uname = $username.val().trim(); var passwd = $password.val(); + var passwd_confirm = $password_register.val(); var confirm = $confirm.val(); var remember = $remember[0].checked; + var register = document.location.hash.slice(1) === 'register'; + + if (passwd !== passwd_confirm && register) { + return void Cryptpad.alert("Passwords are not the same"); + } if (!Cred.isValidUsername(uname)) { return void Cryptpad.alert('invalid username'); } @@ -340,7 +367,7 @@ define([ window.setTimeout(function () { useBytes(bytes, { remember: remember, - //register: register, + register: register, name: uname, password: passwd, }); From 82e80410547a745e2f97074e9c8c11df336c2828 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 17 Jan 2017 18:19:45 +0100 Subject: [PATCH 43/88] Use bootstrap 4 in the main page --- customize.dist/about.html | 6 +- customize.dist/bg2.jpg | Bin 0 -> 261738 bytes customize.dist/contact.html | 6 +- customize.dist/index.html | 25 +++-- customize.dist/main.css | 114 ++++++++++++++++------- customize.dist/main.js | 1 + customize.dist/privacy.html | 6 +- customize.dist/src/fragments/fork.html | 2 +- customize.dist/src/fragments/index.html | 19 ++-- customize.dist/src/fragments/topbar.html | 1 + customize.dist/src/less/cryptpad.less | 62 ++++++++---- customize.dist/src/less/dropdown.less | 2 +- customize.dist/src/less/topbar.less | 32 +++++-- customize.dist/src/less/variables.less | 4 + customize.dist/src/template.html | 3 +- customize.dist/terms.html | 6 +- customize.dist/toolbar.css | 2 +- customize.dist/translations/messages.js | 5 +- 18 files changed, 201 insertions(+), 95 deletions(-) create mode 100644 customize.dist/bg2.jpg diff --git a/customize.dist/about.html b/customize.dist/about.html index 682422a80..3ce8dee6e 100644 --- a/customize.dist/about.html +++ b/customize.dist/about.html @@ -6,6 +6,8 @@ + + + + + + + diff --git a/www/poll/main.js b/www/poll/main.js index e97935dae..8ad1b4c0e 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -12,7 +12,7 @@ define([ '/common/notify.js', '/bower_components/file-saver/FileSaver.min.js', '/bower_components/jquery/dist/jquery.min.js', -], function (Config, Messages, TextPatcher, Listmap, Crypto, Cryptpad, Hyperjson, Renderer, Toolbar) { +], function (Config, Messages, TextPatcher, Listmap, Crypto, Cryptpad, Hyperjson, Renderer, Toolbar, Visible, Notify) { var $ = window.jQuery; var unlockHTML = ''; @@ -187,6 +187,9 @@ define([ /* Any time the realtime object changes, call this function */ var change = function (o, n, path, throttle) { + if (!Cryptpad.isArray(path)) { + return; + } if (path && path.join) { console.log("Change from [%s] to [%s] at [%s]", o, n, path.join(', ')); @@ -210,6 +213,7 @@ define([ https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion */ + notify(); if (throttle) { if (APP.throttled) { window.clearTimeout(APP.throttled); } @@ -391,87 +395,101 @@ define([ }); }; - var userData = APP.userData = {}; // List of pretty names for all users (mapped with their ID) - var userList; // List of users still connected to the channel (server IDs) - var addToUserData = function(data) { - var users = userList ? userList.users : undefined; - //var userData = APP.proxy.info.userData; - for (var attrname in data) { userData[attrname] = data[attrname]; } + var unnotify = function () { + if (APP.tabNotification && + typeof(APP.tabNotification.cancel) === 'function') { + APP.tabNotification.cancel(); + } + }; - if (users && users.length) { - for (var userKey in userData) { - if (users.indexOf(userKey) === -1) { delete userData[userKey]; } - } - } + var notify = function () { + if (Visible.isSupported() && !Visible.currently()) { + unnotify(); + APP.tabNotification = Notify.tab(1000, 10); + } + }; - if(userList && typeof userList.onChange === "function") { - userList.onChange(userData); - } + var userData = APP.userData = {}; // List of pretty names for all users (mapped with their ID) + var userList; // List of users still connected to the channel (server IDs) + var addToUserData = function(data) { + var users = userList ? userList.users : undefined; + //var userData = APP.proxy.info.userData; + for (var attrname in data) { userData[attrname] = data[attrname]; } - APP.proxy.info.userData = userData; - }; + if (users && users.length) { + for (var userKey in userData) { + if (users.indexOf(userKey) === -1) { delete userData[userKey]; } + } + } - //var myData = {}; - var getLastName = function (cb) { - Cryptpad.getAttribute('username', function (err, userName) { - cb(err, userName || ''); - }); - }; + if(userList && typeof userList.onChange === "function") { + userList.onChange(userData); + } - var setName = APP.setName = function (newName) { - if (typeof(newName) !== 'string') { return; } - var myUserNameTemp = Cryptpad.fixHTML(newName.trim()); - if(myUserNameTemp.length > 32) { - myUserNameTemp = myUserNameTemp.substr(0, 32); - } - var myUserName = myUserNameTemp; - var myID = APP.myID; - var myData = {}; - myData[myID] = { - name: myUserName - }; - addToUserData(myData); - Cryptpad.setAttribute('username', newName, function (err, data) { - if (err) { - console.error("Couldn't set username"); - return; - } - APP.userName.lastName = myUserName; - //change(); - }); - }; - - var updateTitle = function (newTitle) { - if (newTitle === document.title) { return; } - // Change the title now, and set it back to the old value if there is an error - var oldTitle = document.title; - document.title = newTitle; - Cryptpad.renamePad(newTitle, function (err, data) { - if (err) { - console.log("Couldn't set pad title"); - console.error(err); - document.title = oldTitle; - return; - } - document.title = data; - APP.$bar.find('.' + Toolbar.constants.title).find('span.title').text(data); - APP.$bar.find('.' + Toolbar.constants.title).find('input').val(data); - }); - }; + APP.proxy.info.userData = userData; + }; - var updateDefaultTitle = function (defaultTitle) { - defaultName = defaultTitle; - APP.$bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); - }; - var renameCb = function (err, title) { - if (err) { return; } - document.title = title; - APP.proxy.info.title = title; - }; + //var myData = {}; + var getLastName = function (cb) { + Cryptpad.getAttribute('username', function (err, userName) { + cb(err, userName || ''); + }); + }; - var suggestName = function (fallback) { - return document.title || defaultName || ""; - }; + var setName = APP.setName = function (newName) { + if (typeof(newName) !== 'string') { return; } + var myUserNameTemp = Cryptpad.fixHTML(newName.trim()); + if(myUserNameTemp.length > 32) { + myUserNameTemp = myUserNameTemp.substr(0, 32); + } + var myUserName = myUserNameTemp; + var myID = APP.myID; + var myData = {}; + myData[myID] = { + name: myUserName + }; + addToUserData(myData); + Cryptpad.setAttribute('username', newName, function (err, data) { + if (err) { + console.error("Couldn't set username"); + return; + } + APP.userName.lastName = myUserName; + //change(); + }); + }; + + var updateTitle = function (newTitle) { + if (newTitle === document.title) { return; } + // Change the title now, and set it back to the old value if there is an error + var oldTitle = document.title; + document.title = newTitle; + Cryptpad.renamePad(newTitle, function (err, data) { + if (err) { + console.log("Couldn't set pad title"); + console.error(err); + document.title = oldTitle; + return; + } + document.title = data; + APP.$bar.find('.' + Toolbar.constants.title).find('span.title').text(data); + APP.$bar.find('.' + Toolbar.constants.title).find('input').val(data); + }); + }; + + var updateDefaultTitle = function (defaultTitle) { + defaultName = defaultTitle; + APP.$bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); + }; + var renameCb = function (err, title) { + if (err) { return; } + document.title = title; + APP.proxy.info.title = title; + }; + + var suggestName = function (fallback) { + return document.title || defaultName || ""; + }; var copyObject = function (obj) { @@ -575,6 +593,7 @@ define([ .on('change', ['info'], function (o, n, p) { if (p[1] === 'title') { updateTitle(n); + notify(); } else if (p[1] === "userData") { addToUserData(APP.proxy.info.userData); } else if (p[1] === 'description') { @@ -591,6 +610,7 @@ define([ el.selectionStart = selects[0]; el.selectionEnd = selects[1]; } + notify(); } console.log("change: (%s, %s, [%s])", o, n, p.join(', ')); @@ -600,6 +620,13 @@ define([ addToUserData(APP.proxy.info.userData); + if (Visible.isSupported()) { + Visible.onChange(function (yes) { + if (yes) { unnotify(); } + }); + } + + getLastName(function (err, lastName) { APP.ready = true; From 1e1bfd275cdb47719a2be9da970a98f71eab0f6c Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 19 Jan 2017 15:17:21 +0100 Subject: [PATCH 52/88] Don't show the tab notification when someone has joined the pad --- www/code/main.js | 5 +++-- www/pad/main.js | 14 +++++++++++++- www/slide/main.js | 4 +++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/www/code/main.js b/www/code/main.js index 3af11316d..9a37efa99 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -684,8 +684,9 @@ define([ module.patchText(shjson2); } } - - notify(); + if (oldDoc !== remoteDoc) { + notify(); + } }; var onAbort = config.onAbort = function (info) { diff --git a/www/pad/main.js b/www/pad/main.js index 852ad7cd5..60f64bce5 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -477,6 +477,8 @@ define([ var onRemote = realtimeOptions.onRemote = function (info) { if (initializing) { return; } + var oldShjson = stringifyDOM(inner); + var shjson = info.realtime.getUserDoc(); // remember where the cursor is @@ -485,6 +487,11 @@ define([ // Update the user list (metadata) from the hyperjson updateMetadata(shjson); + var newInner = JSON.parse(shjson); + if (newInner.length > 2) { + var newSInner = stringify(newInner[2]); + } + // build a dom from HJSON, diff, and patch the editor applyHjson(shjson); @@ -518,7 +525,12 @@ define([ } } } - notify(); + + // Notify only when the content has changed, not when someone has joined/left + var oldSInner = stringify(JSON.parse(oldShjson)[2]); + if (newSInner !== oldSInner) { + notify(); + } }; var getHTML = function (Dom) { diff --git a/www/slide/main.js b/www/slide/main.js index a44f11c85..b580c8ed8 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -768,7 +768,9 @@ define([ } Slide.update(remoteDoc); - notify(); + if (oldDoc !== newDoc) { + notify(); + } }; var onAbort = config.onAbort = function (info) { From ea8667302ca5b723edf62a02fe8c0155f13a3da7 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 19 Jan 2017 15:35:38 +0100 Subject: [PATCH 53/88] Display only a placeholder when the poll title is default --- www/poll/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/poll/main.js b/www/poll/main.js index 8ad1b4c0e..e15adab41 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -488,7 +488,7 @@ define([ }; var suggestName = function (fallback) { - return document.title || defaultName || ""; + return (document.title === defaultName) ? "" : document.title; }; From 99b8898e5448d055144a8dab17b5f2b97ee9e045 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 19 Jan 2017 15:41:25 +0100 Subject: [PATCH 54/88] Apply new title when clicking on the page without pressing enter --- www/common/toolbar.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/www/common/toolbar.js b/www/common/toolbar.js index aeee16456..a4c63a902 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -556,26 +556,34 @@ define([ $container.find('.cryptpad-dropdown').hide(); }; var cancelEditTitle = function (e) { + // Now we want to apply the title even if we click somewhere else if ($(e.target).parents('.' + TITLE_CLS).length || !$titleElement) { return; } + + var e = jQuery.Event("keyup"); + e.which = 13; + $titleElement.find('input').trigger(e); + + /* $titleElement.find('input').hide(); $titleElement.find('span.title').show(); $titleElement.find('span.pencilIcon').css('display', ''); + */ }; $(config.ifrw).on('click', removeDropdowns); $(config.ifrw).on('click', cancelEditTitle); - try { - if (config.ifrw.$('iframe').length) { - var innerIfrw = config.ifrw.$('iframe').each(function (i, el) { - $(el.contentWindow).on('click', removeDropdowns); - $(el.contentWindow).on('click', cancelEditTitle); - }); + try { + if (config.ifrw.$('iframe').length) { + var innerIfrw = config.ifrw.$('iframe').each(function (i, el) { + $(el.contentWindow).on('click', removeDropdowns); + $(el.contentWindow).on('click', cancelEditTitle); + }); + } + } catch (e) { + // empty try catch in case this iframe is problematic } - } catch (e) { - // empty try catch in case this iframe is problematic - } } // Update user list From fd78e4fa92bb86ae7eac858d0aedbd3dff8b8d6f Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 20 Jan 2017 18:21:51 +0100 Subject: [PATCH 55/88] Improve homepage CSS and responsiveness --- customize.dist/images/realtime.png | Bin 2595 -> 3186 bytes customize.dist/index.html | 195 ++++++++++----------- customize.dist/main.css | 161 +++++++++++------ customize.dist/messages.js | 6 + customize.dist/src/fragments/index.html | 195 ++++++++++----------- customize.dist/src/less/cryptpad.less | 120 +++++++++---- customize.dist/src/less/variables.less | 4 +- customize.dist/translations/messages.fr.js | 2 +- 8 files changed, 379 insertions(+), 304 deletions(-) diff --git a/customize.dist/images/realtime.png b/customize.dist/images/realtime.png index 8f4d651684d02f57eeca38c27646ef2ed6f98cd5..d854c4d485d7743065b0748f7b9376381caea690 100644 GIT binary patch literal 3186 zcmds3X;f3!7QPA50G2S8Jc~d`MWsS*LFNDfNdcLMD#}zOKnWlZWQahfRvzS0AQl8c z289BOMT7`eqBs-@$|%SXDnyYf5WtWGnF8-pthKdk_5FH3-n#3od(J-Rp8M@@pMCa6 zcXP3mll@2*0021$ds`0xfH1)3AiW*5)MqB`2Vam=9(Fdswa#5UZ~zOncD4q9+N>RG zf!n~b%s=gqodN(v^Jasb+mBEKjoVK++Svjdo6p5NmD!*L9_!$YgTH_%$;*9i%9srU zO*><8-m!mQ*Sm|B698{pERZHG4Jbk&C^QPNg~6z4R6s!x zhXT$O6%}=4t=CM--}i&#pW*^7LjLV>vY>oMWE3>K4ZkD(L0G=d;lmTWI{%5Q7pM_o z?j~{uxG?PyLQN`XdNg~gT(x{`w8t2%(2r z0H^B*n#MTchfD_fqgbD52ReMPH}LL6^24cmiKP3dV@c^V9dVz=D8r&qtwfZxB7 zx#!I$r1;-`Ra5}b(BD>W67f^{>g)Ngtp2{ocgyHhZ$fn^g9W>Y`9;5*<7gBcjsI$W0#6 z-7BidltyqtPC<%)$Ta`H)s1utkHg`t?VGfjL>u6oA0>;8T!&%!s5e2;iT2dz1vfQH zxAv>1thB3K@nB{X!X^r2enp3q3GaHM72e4qY$4lME64sLfAvyXFPq)!Nm2d;b^mG%P#{bKs z_+EJ4J*WTc$yP9RCfK!1CUf~o!-qtj{QN7a?J9cvl@x#mwvYGQ{Mp21Nk<@k<5t?V zp+}igf5@)?4)u}GNNumKHbt5+qMfS`VO{v63^k%jaX7&O8e?-*?j|j@Fr45AjX@jB z)zebPeLZKC8Oo-jAa^;;vyn?P53{r^J9F4rvn?!U^oc6u7%lA{*wKI- zqo>`QrQ2PA;c;kaD&39+!v~|G1Ik$qGWJrouyt3=&|XxAg5pvhQDlw%2#rQ*SST`D z(xiR%Xpj^c+v(CiyEP<=j4!|rT7#s-_!rngX-Je9Ep+LRm9v^;?BTX&6zO&wupgAs z5A2(RK7jTpDh9$vKSw}#-=%dM2>y{yjkUL(I!pY{4r`{37TIE2cB9ml6%$b!FO?Xb zbZI^1tXi2?!1jzPoxKFZE3m&98&2R3lO*B+p}|ih2lw{gerAhlc)`DKbNmr)H*!vN z|GDHf*NU<>RhBikzVtFn$o7fto0(Kv9tg^^Xjm0?S#@dN6?U4lUXLWruL*FYwdzp) zi`vLn4~f1v`f3#zGk)SB-^?^(L^}0@X(Qx9oZvi0*lxhmBrgS$jf!VRzPU9mK5uF7 zKVHR}cehyOGg+FHwP^BUz-n3=dr`Xe9>T9XbxqXk%Bn0*B#@0Vc@}GV{)u7a+|}u; zHSq_UmPXeie62Rtgmb*glH!u!IV(xW^V+TT zqeOOCqvsX9M~s)n0|5zK%7$buVpl-2;NjYoN%?wluJepl$9<39+kOc>8PU?M&wGe` z3lNyFEZS*ro8`(>+48ZF72(IlZY=(JG4iZHruANC27Bz>QU81pW`{BN*&RWPnvfY> zVPz~?)-#Eh;P4Sm2>e%UvU=-SXOTJU?)pkNNZa0$8< zjsy&rkXa~i5L73%b5N9Wl3id)OkN((6EX$55=@J#<$SGibrPMJbN^;L zWOP0IXPSEJb|<7jM5#OtNubkY^TMnGc=25sFmrz?2G%8-%4R4WfB4-7K|&huav=Q3uBVl7Ueb)jnO* zZDaf9H=U}yez^m2rjHI6JwluzJcHD<&A3LsuQ-}@bgPcV$hNwV{G97wid%+uS8Ii|uWyPc|c$E)Z;DHx9-B`BPrZjr?anwrRWQZANh`Bi`fqj~fimu0wXE)&^-j T`IZH$eZT?dVtdWzt8e}T)XF;$ literal 2595 zcmc&0eK^$V_BRt|VliZCSvBc#(bcnlT<+ZD3<6K>q3i+42_C~Tuz1t$A*Sr>D1V8tgG9B zgTAR6dO#P`jo{>y&^y`BJNe@@Q5NTPD<3(h>^5i!%5AWr(@xG6cZ6kl2`^bDrzG=|n>zD^A3!~ihO{9p z7DA&TB$B~^!1z0{RU^QH53R!(>M8MdFP;5GXwF>hwdyKkutstzS1Ud`;sYo7>j-t; z2)lA65n70+kzN+$mv&@QQPmImL{`j+6Xiu_@pft?R#ju!(5E)!M>ZQs1#9rFxw?+- zAg^d3^X%wMVOT_sDW|htC$2iK>St>|9q|N3wXi1@N-*`mD`*Y!!du=3TtL{h5Ph)k zKPW4K;Ez0h5!qVEb=bq%JiAksqAG;>az z&NCXRdoHrGu}mINXVAYt)esGrYoe?j^FGjRxls0&lBT(_ZkeKNbDLE*PvGH6~ok`4Gz=2xQlFzd%l!!ZrndnV0O5)+W0}25%OVQ zSy1J~%n!{P%^*nkq*6j8&X)+AgCoS$*4y35U2&B{oyWyf5&tqRFvEqG_7+x`pqjxx zVP4|#7;d~ShIxi%MW*~X`FpS1^47NfEcTovq8sc5fo$79i#w7=lv&^5aw(iFhkOVl zN#QQq(T$RIE4akvG~rsbkj>9#I6bQai1T|);6K@HU3H|$gV`&Gc zDqF;4WK%k-pPvR;1-oXCd8y-to6g7mVWUJK!1!htn6SJmDQO{O7z{zFc>_XA3!}Nl z!~huKv?c(l^dya! z3rf7($TF-^Sx6E*Ie(RQ$}$1JI9DxP;Lpx{LBBgYk2AV{o_G2p%M&>LdAi5;7XkR& zyjJCq(OXF-MkAe<9P+>4$?|`2Cx>Ka$L+W(+dL>aKuLKx%^dEE9DG&Fp30~e72yV6 za`LoU^8~yUo(MO&k&!0EAD_N0&d!<&ll#zdGnpFW6Qf!3xV}t%dPvd2wj_al&d$9p z!R7hmhe9v0<1>BnnP{}y*ZZy^ZUy`XVVHzM5OesMjss6F8z7yJ$ZTcg2vG>$e=hvK=ggIs zO~-N7yeu@@@ZNT#kx-`SA2?oimPBu1S~7a?RZ!ooUQTyl*a98ft`hQ1`spH;NT2&D zuZ1#LHt&Gj`z$*VZe2sWo`Iq~N@FTSG>5=Nm)bQts#pTBRuSP81Ol986iL zzC2}f>Rige*lW73=xE0_YsYZ8?q@Texpo33OqKt;J}axEJ3*Asn&*oP45V;UZ+2dm zt>3(B(c-Y|xp!NNKqPS@)R!dOyjjw6Y_CxOO&)wLCJws=>1_W=t}DymBkGx~`eygS zbRR2GEH~aGelc0qe*XkP95B;Qt9tNQ{`}XYqE{d@5^cG*r$q8N z`3@tl?bw09u<`to_GZcGU`q1cC~0r2n3JZ|d}!#6-b2B6f$jH>jYTZU8ce1{ta&Os zCR#hk*Myg(W`;x-)rbG#+Pw9jOA`VO?rD_XxQTX?DegSUOw;$vsUI1JXb2ahsb4>$j4(7kasmO_A7l>p%UM1yoyx{c$6U%?UQ2*FYBo( zH@3%Pv0H*r$kLx0L18QCK(lMEFv{z@ia!%*fC7}l{0r8gXDhT0Xjn)0!{|JEVb}4V zR7L_gK*9|b;ERHFY;jW=@|zbPF^ARdF&NF74G7O}U~K(`15NHM+0TdXH9+;a7K}oU zAmXt@t@_~kSbZ~A{9#0^GF5Hc?Axi -
+
-
+
-
-
-
+ +
+

@@ -97,55 +97,55 @@
-
- Zero Knowledge -
-
-
+
+
+ Zero Knowledge +
+

Zero Knowledge

-
-

- Every tool provided by Cryptpad are based on a Zero Knowledge technology. It means that our server stored only encrypted data, and we have no way to decrypt it. Even data about your account, including your username, are encrypted. Only people with whom you have shared the URL are allowed to decrypt the data and join the collaborative session. The encryption is carried out by your browser, which means that our server has no knowledge of the encryption key. -

+

+ Every tool provided by Cryptpad are based on a Zero Knowledge technology. It means that our server stored only encrypted data, and we have no way to decrypt it. Even data about your account, including your username, are encrypted. +

+
-
-
+
+

Realtime

-
-

- Our tools also use a Realtime technology, which means that you can edit the documents, slides or polls collaboratively with other people. Our unique technology has the advantage of combining both realtime and zero-knowledge at the same time. Other realtime solutions work with a main server containing the document and managing conflicts (when two users want to realize contradictory operations). Our Zero Knowledge principle exclude that solution since the server doesn't know the content of the document, so the conflicts are managed by your browser in a way that all users in the session resolve the conflict with the same result. -

-
-
- User account +

+ Our tools also use a Realtime technology, which means that you can edit the documents, slides or polls collaboratively with other people. Our unique technology has the advantage of combining both realtime and zero-knowledge at the same time. +

+
+
+ User account +
-
- User account -
-
-
+
+
+ User account +
+

Share documents

-
-

- When you want to edit a document with other users or invite them to answer to a poll, you just have to share the URL of that document with them. All the information needed to access and edit it are contained in the "hash" of the URL. A first part of that hash represents the location of the data in our server, the second part allows your browser to decrypt the content of that document and encrypt new modifications you may want to make. -

+

+ When you want to edit a document with other users or invite them to answer to a poll, you just have to share the URL of that document with them. All the information needed to access and edit it are contained in the "hash" of the URL. +

+
-
-
+
+

User Account

-
-

- In order to have Zero Knowledge user accounts, we needed a way to store your settings without knowing your username and password. To do so, our tools generate a unique key from your username and password, directly in your browser. The entire key is never sent to our server and there is no way to determine either your username or your password from it. A small part of that key is used to locate your account data in our server, and the other part is used to encrypt and decrypt it (in your browser). That way, the server never has access to your decrypted data or to your decryption key. -

-
-
- User account +

+ In order to have Zero Knowledge user accounts, we needed a way to store your settings without knowing your username and password. To do so, our tools generate a unique key from your username and password, directly in your browser. +

+
+
+ User account +
@@ -154,68 +154,57 @@
-
- Rich Text application -
-
-
-

Rich Text editor

-
-

- Edit rich text documents collaboratively with our realtime Zero Knowledge CkEditor application. -

-

- -

-
-
-
-
-
-

Code editor

-
-

- Create or debug code from your software (using any programming language) collaboratively with your colleagues with our realtime Zero Knowledge CodeMirror application. -

-

- -

-
-
- Code application -
-
- -
-
- Slide applcation -
-
-
-

Slide editor

-
-

- Create your presentation collaboratively with our CryptSlide application. Slides are written use Markdown syntax and you can choose the background and text colors when presenting it. -

-

- -

-
-
-
-
-
-

Polls

-
-

- Plan your meeting or your event, or determine what is the best solution for your problem using our poll application. Don't worry about sensible data, everything here is also Zero Knowledge and only people with the poll link can access the data. -

-

- -

-
-
- Poll application +
+
+
+
+

Rich Text editor

+ Rich Text application +
+

+ Edit rich text documents collaboratively with our realtime Zero Knowledge CkEditor application. +

+

+ +

+
+
+

Code editor

+ Code application +
+

+ Edit code from your software collaboratively with our realtime Zero Knowledge CodeMirror application. +

+

+ +

+
+
+

Slide editor

+ Slide applcation +
+

+ Create your presentations using the Markdown syntax with our CryptSlide application, and display them in your browser. +

+

+ +

+
+
+

Polls

+ Poll application +
+

+ Plan your meeting or your event, or vote for the best solution regarding your problem using our poll application. +

+

+ +

+
+
diff --git a/customize.dist/main.css b/customize.dist/main.css index b3d8d2b21..5ca09029b 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -18,7 +18,7 @@ } .alertify-logs > *.success { background: #46E981; - color: #f5f5f5; + color: #fff; } .alertify { position: fixed; @@ -80,8 +80,8 @@ } .alertify .dialog input:not(.form-control), .alertify .alert input:not(.form-control) { - background-color: #f5f5f5; - color: #111; + background-color: #fff; + color: #555; border: 0px; border-radius: 5px; margin-bottom: 15px; @@ -211,7 +211,7 @@ height: 2.5em; display: inline-block; width: 100%; - background: #f5f5f5; + background: #fff; border-top: 1px solid #444; } .top-bar a, @@ -227,7 +227,7 @@ display: block; margin-left: 10px; padding-top: 3px; - color: #111; + color: #555; } .top-bar img, .bottom-bar img { @@ -465,8 +465,8 @@ html.cp, .cp body { font-size: .875em; - background-color: #f5f5f5; - color: #111; + background-color: #fff; + color: #555; font-family: Georgia,Cambria,serif; height: 100%; } @@ -505,7 +505,7 @@ html.cp, .cp h4, .cp h5, .cp h6 { - color: #111; + color: #555; font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; -webkit-font-feature-settings: 'dlig' 1, 'liga' 1, 'lnum' 1, 'kern' 1; -moz-font-feature-settings: 'dlig' 1, 'liga' 1, 'lnum' 1, 'kern' 1; @@ -582,54 +582,93 @@ html.cp, width: 100%; margin-left: auto; margin-right: auto; - background: #f5f5f5; - padding: 10px 15vw; + background: #fff; + padding: 10px 0; position: relative; } -.cp .page.first { - margin-top: calc(100vh - 50px); +.cp .page .info-container { + width: 900px; + max-width: 100%; + margin: 0 auto; +} +.cp .page .info-container > div { + padding: 10px; + width: 400px; + max-width: 100%; + position: relative; + display: inline-block; + vertical-align: middle; } @media screen and (max-width: 800px) { - .cp .page.first { - margin-top: 0; + .cp .page .info-container > div:not(.image) { + width: 100%; + left: 0; } } -.cp .page.even { - background: #dcdcdc; +.cp .page .info-container > div.image { + text-align: center; } -.cp .page.category { - background: #c2c2c2; +@media screen and (max-width: 800px) { + .cp .page .info-container > div.image { + display: none; + } } -.cp .page .left { - left: 0; +@media screen and (max-width: 800px) { } -.cp .page .right { - left: 10%; +.cp .page.category { + background: #f7f7f7; } -@media screen and (max-width: 800px) { - .cp .page { - padding: 10px 5vh; +.cp .page .app { + display: inline-block; + width: 300px; + vertical-align: middle; + margin: 0px 25px; + white-space: normal; + max-width: calc(50% - 50px); +} +@media screen and (max-width: 500px) { + .cp .page .app { + display: block; + max-width: 100%; + margin: 0 auto; } } -.cp .page > div { - padding: 10px; - width: 45%; - position: relative; +.cp .page .app-container { + width: 1400px; + max-width: 100%; + margin: 0 auto; +} +.cp .page .app-row { display: inline-block; - vertical-align: middle; + white-space: nowrap; + width: 700px; + max-width: 100%; + margin: 0 auto; +} +@media screen and (max-width: 1399px) { + .cp .page .app-row { + display: block; + } } @media screen and (max-width: 800px) { - .cp .page > div:not(.image) { - width: 100%; - left: 0; + .cp .page .app-row img { + display: none; } } -.cp .page .image { - text-align: center; +.cp .page .right { + left: 100px; +} +.cp .page h1, +.cp .page h2, +.cp .page h3, +.cp .page h4, +.cp .page h5, +.cp .page h6 { + padding: 0; } @media screen and (max-width: 800px) { - .cp .page .image { - display: none; + .cp .page { + padding: 10px 5vh; } } .cp .page p { @@ -649,10 +688,11 @@ html.cp, } .cp #main, .cp #main_other { - position: absolute; + position: relative; left: 0; right: 0; - height: calc(100vh - 50px); + height: calc(100vh - 150px); + min-height: 450px; margin: auto; font-size: medium; } @@ -729,6 +769,22 @@ html.cp, box-sizing: border-box; font-family: lato, Helvetica, sans-serif; color: #fff; + /*.remember { + vertical-align: middle; + line-height: 28px; + height: 28px; + display: inline-block; + margin: 10px 0 20px 0; + } + + + [type="checkbox"] { + vertical-align: text-top; + margin: 0; + //margin-top: 10px; + margin-right: 5px; + } + */ } .cp #main #userForm h1, .cp #main_other #userForm h1 { @@ -741,24 +797,14 @@ html.cp, .cp #main_other #userForm [type="password"] { width: 100%; } -.cp #main #userForm .remember, -.cp #main_other #userForm .remember { - vertical-align: middle; - line-height: 28px; - height: 28px; - display: inline-block; - margin: 10px 0 20px 0; +.cp #main #userForm label, +.cp #main_other #userForm label { + margin-bottom: 0; } .cp #main #userForm [type="checkbox"], .cp #main_other #userForm [type="checkbox"] { - vertical-align: text-top; - margin: 0; margin-right: 5px; } -.cp #main #userForm label, -.cp #main_other #userForm label { - margin-bottom: 0; -} .cp #main #userForm button, .cp #main_other #userForm button { font-weight: bold; @@ -809,7 +855,6 @@ html.cp, .cp #main_other { position: relative; height: auto; - background: #aaa; top: -10px; } } @@ -854,7 +899,7 @@ html.cp, line-height: 1.5em; } .cp .panel { - background-color: #c2c2c2; + background-color: #cccccc; } .cp table { border-collapse: collapse; @@ -891,7 +936,7 @@ html.cp, } .cp tbody tr th, .cp tbody tr td { - color: #111; + color: #555; } .cp tbody tr th.remove, .cp tbody tr td.remove { @@ -1027,7 +1072,7 @@ html.cp, .cp form.realtime table input[type="text"], .cp div.realtime table input[type="text"] { height: auto; - border: 1px solid #f5f5f5; + border: 1px solid #fff; width: 80%; } .cp form.realtime table thead td, @@ -1087,7 +1132,7 @@ html.cp, .cp form.realtime table thead tr th input[type="text"][disabled], .cp div.realtime table thead tr th input[type="text"][disabled] { background-color: transparent; - color: #111; + color: #555; font-weight: bold; } .cp form.realtime table thead tr th .remove, @@ -1294,7 +1339,7 @@ html.cp, .cp div#modal table input { height: 100%; width: 90%; - border: 3px solid #f5f5f5; + border: 3px solid #fff; } .cp div.modal table tfoot tr td, .cp div#modal table tfoot tr td { diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 59be80317..b0cc524cb 100644 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -81,6 +81,11 @@ define(['/customize/languageSelector.js', var key = $el.data('localization'); $el.html(messages[key]); }; + var translateAppend = function (i, e) { + var $el = $(e); + var key = $el.data('localization-append'); + $el.append(messages[key]); + }; var translateTitle = function (i, e) { var $el = $(this); var key = $el.data('localization-title'); @@ -93,6 +98,7 @@ define(['/customize/languageSelector.js', }; messages._applyTranslation = function () { $('[data-localization]').each(translateText); + $('[data-localization-append]').each(translateAppend); $('#pad-iframe').contents().find('[data-localization]').each(translateText); $('[data-localization-title]').each(translateTitle); $('[data-localization-placeholder]').each(translatePlaceholder); diff --git a/customize.dist/src/fragments/index.html b/customize.dist/src/fragments/index.html index 87a87a684..728c71d68 100644 --- a/customize.dist/src/fragments/index.html +++ b/customize.dist/src/fragments/index.html @@ -15,16 +15,16 @@
-
+
-
+
-
-
-
+ +
+

@@ -35,55 +35,55 @@
-
- Zero Knowledge -
-
-
+
+
+ Zero Knowledge +
+

Zero Knowledge

-
-

- Every tool provided by Cryptpad are based on a Zero Knowledge technology. It means that our server stored only encrypted data, and we have no way to decrypt it. Even data about your account, including your username, are encrypted. Only people with whom you have shared the URL are allowed to decrypt the data and join the collaborative session. The encryption is carried out by your browser, which means that our server has no knowledge of the encryption key. -

+

+ Every tool provided by Cryptpad are based on a Zero Knowledge technology. It means that our server stored only encrypted data, and we have no way to decrypt it. Even data about your account, including your username, are encrypted. +

+
-
-
+
+

Realtime

-
-

- Our tools also use a Realtime technology, which means that you can edit the documents, slides or polls collaboratively with other people. Our unique technology has the advantage of combining both realtime and zero-knowledge at the same time. Other realtime solutions work with a main server containing the document and managing conflicts (when two users want to realize contradictory operations). Our Zero Knowledge principle exclude that solution since the server doesn't know the content of the document, so the conflicts are managed by your browser in a way that all users in the session resolve the conflict with the same result. -

-
-
- User account +

+ Our tools also use a Realtime technology, which means that you can edit the documents, slides or polls collaboratively with other people. Our unique technology has the advantage of combining both realtime and zero-knowledge at the same time. +

+
+
+ User account +
-
- User account -
-
-
+
+
+ User account +
+

Share documents

-
-

- When you want to edit a document with other users or invite them to answer to a poll, you just have to share the URL of that document with them. All the information needed to access and edit it are contained in the "hash" of the URL. A first part of that hash represents the location of the data in our server, the second part allows your browser to decrypt the content of that document and encrypt new modifications you may want to make. -

+

+ When you want to edit a document with other users or invite them to answer to a poll, you just have to share the URL of that document with them. All the information needed to access and edit it are contained in the "hash" of the URL. +

+
-
-
+
+

User Account

-
-

- In order to have Zero Knowledge user accounts, we needed a way to store your settings without knowing your username and password. To do so, our tools generate a unique key from your username and password, directly in your browser. The entire key is never sent to our server and there is no way to determine either your username or your password from it. A small part of that key is used to locate your account data in our server, and the other part is used to encrypt and decrypt it (in your browser). That way, the server never has access to your decrypted data or to your decryption key. -

-
-
- User account +

+ In order to have Zero Knowledge user accounts, we needed a way to store your settings without knowing your username and password. To do so, our tools generate a unique key from your username and password, directly in your browser. +

+
+
+ User account +
@@ -92,68 +92,57 @@
-
- Rich Text application -
-
-
-

Rich Text editor

-
-

- Edit rich text documents collaboratively with our realtime Zero Knowledge CkEditor application. -

-

- -

-
-
-
-
-
-

Code editor

-
-

- Create or debug code from your software (using any programming language) collaboratively with your colleagues with our realtime Zero Knowledge CodeMirror application. -

-

- -

-
-
- Code application -
-
- -
-
- Slide applcation -
-
-
-

Slide editor

-
-

- Create your presentation collaboratively with our CryptSlide application. Slides are written use Markdown syntax and you can choose the background and text colors when presenting it. -

-

- -

-
-
-
-
-
-

Polls

-
-

- Plan your meeting or your event, or determine what is the best solution for your problem using our poll application. Don't worry about sensible data, everything here is also Zero Knowledge and only people with the poll link can access the data. -

-

- -

-
-
- Poll application +
+
+
+
+

Rich Text editor

+ Rich Text application +
+

+ Edit rich text documents collaboratively with our realtime Zero Knowledge CkEditor application. +

+

+ +

+
+
+

Code editor

+ Code application +
+

+ Edit code from your software collaboratively with our realtime Zero Knowledge CodeMirror application. +

+

+ +

+
+
+

Slide editor

+ Slide applcation +
+

+ Create your presentations using the Markdown syntax with our CryptSlide application, and display them in your browser. +

+

+ +

+
+
+

Polls

+ Poll application +
+

+ Plan your meeting or your event, or vote for the best solution regarding your problem using our poll application. +

+

+ +

+
+
diff --git a/customize.dist/src/less/cryptpad.less b/customize.dist/src/less/cryptpad.less index a6fd93b69..4efb0e5bf 100644 --- a/customize.dist/src/less/cryptpad.less +++ b/customize.dist/src/less/cryptpad.less @@ -134,54 +134,96 @@ body.html { width: 100%; margin-left: auto; margin-right: auto; - background: @base; - padding: 10px @main-border-width; + background: #fff; //@base; + padding: 10px 0;//@main-border-width; position: relative; + .info-container { + width: 900px; + max-width: 100%; + margin: 0 auto; + &>div{ + padding: 10px; + width: 400px; + max-width: 100%; + position: relative; + display: inline-block; + vertical-align: middle; + &:not(.image) { + @media screen and (max-width: @media-not-big) { + width: 100%; + left: 0; + } + } + &.image { + text-align: center; + @media screen and (max-width: @media-not-big) { + display: none; + } + } + } + } + &.first { - margin-top: ~"calc(100vh - 50px)"; + //margin-top: ~"min(calc(100vh - 150px), 650px)"; @media screen and (max-width: @media-not-big) { - margin-top: 0;; + //margin-top: 0; } } &.even { - background: darken(@base, 10%); + //background: darken(@base, 1%); } &.category { - background: darken(@base, 20%); + background: darken(@base, 3%); } - .left { - left: 0; //@main-border-width; - } - .right { - left: 10%; //@main-border-width; + .app { + display: inline-block; + width: 300px; + vertical-align: middle; + margin: 0px 25px; + white-space: normal; + max-width: ~"calc(50% - 50px)"; + @media screen and (max-width: 500px) { + display: block; + max-width: 100%; + margin: 0 auto; + } } - - @media screen and (max-width: @media-not-big) { - padding: 10px 5vh; + .app-container { + width: 1400px; + max-width: 100%; + margin: 0 auto; } - - - &>div{ - padding: 10px; - width: 45%; - position: relative; + .app-row { display: inline-block; - vertical-align: middle; - &:not(.image) { + white-space: nowrap; + width: 700px; + max-width: 100%; + margin: 0 auto; + @media screen and (max-width: 1399px) { + display: block; + } + img { @media screen and (max-width: @media-not-big) { - width: 100%; - left: 0; + display: none; } } } - .image { - text-align: center; - @media screen and (max-width: @media-not-big) { - display: none; - } + .left { + //left: 10%; //@main-border-width; + } + .right { + left: 100px; //@main-border-width; + } + + h1, h2, h3, h4, h5, h6 { + padding: 0; + } + + @media screen and (max-width: @media-not-big) { + padding: 10px 5vh; } p { @@ -213,11 +255,12 @@ body.html { background-color: #000; opacity: 0.3; } - position: absolute; + position: relative; left: 0; right: 0; //padding: 0; - height: ~"calc(100vh - 50px)"; + height: ~"calc(100vh - 150px)"; + min-height: 450px; margin: auto; //margin-top: 100px; @@ -295,7 +338,11 @@ body.html { width: 100%; } - .remember { + label { + margin-bottom: 0; + //margin-top: 0.5em; + } + /*.remember { vertical-align: middle; line-height: 28px; height: 28px; @@ -310,10 +357,9 @@ body.html { //margin-top: 10px; margin-right: 5px; } - - label { - margin-bottom: 0; - //margin-top: 0.5em; + */ + [type="checkbox"] { + margin-right: 5px; } button { @@ -357,7 +403,7 @@ body.html { @media screen and (max-width: @media-not-big) { position: relative; height: auto; - background: #aaa; + //background: #aaa; top: -10px; } diff --git a/customize.dist/src/less/variables.less b/customize.dist/src/less/variables.less index 346042ed7..de2539fd8 100644 --- a/customize.dist/src/less/variables.less +++ b/customize.dist/src/less/variables.less @@ -1,9 +1,9 @@ -@base: #f5f5f5; +@base: #fff; //#f5f5f5; @dark-base: darken(@base, 20%); @less-dark-base: darken(@base, 10%); @light-base: lighten(@base, 20%); @less-light-base: lighten(@base, 10%); -@fore: #111; +@fore: #555; @old-base: #302B28; @old-fore: #fafafa; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 679bdb1d8..69c1f87bd 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -296,7 +296,7 @@ define(function () { out.button_newpad = 'Nouveau document texte'; out.button_newcode = 'Nouvelle page de code'; - out.button_newpoll = 'Nouveay sondage'; + out.button_newpoll = 'Nouveau sondage'; out.button_newslide = 'Nouvelle présentation'; out.form_title = "Tous vos pads, partout où vous allez !"; From d1bed5ae4b6a981bbe33ef8e23a696da5101f25d Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 23 Jan 2017 10:51:44 +0100 Subject: [PATCH 56/88] Fix polls table not updated with local events --- www/poll/main.js | 48 ++++++++++++++++++++++++++-------------------- www/poll/render.js | 1 - 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/www/poll/main.js b/www/poll/main.js index ce838a57f..6d774b8f1 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -26,6 +26,13 @@ define([ secret.keys = secret.key; } + var DEBUG = false; + var debug = console.log; + if (!DEBUG) { + debug = function() {}; + } + var error = console.error; + Cryptpad.addLoadingScreen(); var onConnectError = function (info) { Cryptpad.errorLoadingScreen(Messages.websocketError); @@ -187,11 +194,11 @@ define([ /* Any time the realtime object changes, call this function */ var change = function (o, n, path, throttle) { - if (!Cryptpad.isArray(path)) { + if (path && !Cryptpad.isArray(path)) { return; } if (path && path.join) { - console.log("Change from [%s] to [%s] at [%s]", + debug("Change from [%s] to [%s] at [%s]", o, n, path.join(', ')); } @@ -242,7 +249,7 @@ define([ var type = input.type.toLowerCase(); var id = getRealtimeId(input); - console.log(input); + debug(input); var object = APP.proxy; @@ -253,22 +260,22 @@ define([ switch (type) { case 'text': - console.log("text[rt-id='%s'] [%s]", id, input.value); - if (!input.value) { return void console.log("Hit enter?"); } + debug("text[rt-id='%s'] [%s]", id, input.value); + if (!input.value) { return void debug("Hit enter?"); } Render.setValue(object, id, input.value); change(null, null, null, 50); break; case 'checkbox': - console.log("checkbox[tr-id='%s'] %s", id, input.checked); + debug("checkbox[tr-id='%s'] %s", id, input.checked); if (APP.editable.col.indexOf(x) >= 0 || x === APP.userid) { Render.setValue(object, id, input.checked); change(); } else { - console.log('checkbox locked'); + debug('checkbox locked'); } break; default: - console.log("Input[type='%s']", type); + debug("Input[type='%s']", type); break; } }; @@ -308,7 +315,7 @@ define([ } else if (type === 'cell') { change(); } else { - console.log("UNHANDLED"); + debug("UNHANDLED"); } }; @@ -333,10 +340,10 @@ define([ var target = e && e.target; if (isKeyup) { - console.log("Keyup!"); + debug("Keyup!"); } - if (!target) { return void console.log("NO TARGET"); } + if (!target) { return void debug("NO TARGET"); } var nodeName = target && target.nodeName; @@ -356,7 +363,7 @@ define([ //console.error(new Error("C'est pas possible!")); break; default: - console.log(target, nodeName); + debug(target, nodeName); break; } }; @@ -366,7 +373,7 @@ define([ */ var prepareProxy = function (proxy, schema) { if (proxy && proxy.version === 1) { return; } - console.log("Configuring proxy schema..."); + debug("Configuring proxy schema..."); proxy.info = proxy.info || schema.info; Object.keys(schema.info).forEach(function (k) { @@ -466,8 +473,8 @@ define([ document.title = newTitle; Cryptpad.renamePad(newTitle, function (err, data) { if (err) { - console.log("Couldn't set pad title"); - console.error(err); + debug("Couldn't set pad title"); + error(err); document.title = oldTitle; return; } @@ -501,8 +508,8 @@ define([ var $description = $('#description').attr('placeholder', Messages.poll_descriptionHint || 'description'); var ready = function (info, userid, readOnly) { - console.log("READY"); - console.log('userid: %s', userid); + debug("READY"); + debug('userid: %s', userid); var proxy = APP.proxy; var uncommitted = APP.uncommitted = {}; @@ -613,7 +620,7 @@ define([ notify(); } - console.log("change: (%s, %s, [%s])", o, n, p.join(', ')); + debug("change: (%s, %s, [%s])", o, n, p.join(', ')); }) .on('change', ['table'], change) .on('remove', [], change); @@ -727,8 +734,8 @@ define([ Cryptpad.getPadTitle(function (err, title) { if (err) { - console.error(err); - console.log("Couldn't get pad title"); + error(err); + debug("Couldn't get pad title"); return; } updateTitle(title || defaultName); @@ -778,7 +785,6 @@ define([ .on('disconnect', disconnect); Cryptpad.getAttribute(HIDE_INTRODUCTION_TEXT, function (e, value) { - console.log(value); if (e) { console.error(e); } if (!value) { Cryptpad.setAttribute(HIDE_INTRODUCTION_TEXT, "1", function (e) { diff --git a/www/poll/render.js b/www/poll/render.js index ce2f67518..3f1e8b614 100644 --- a/www/poll/render.js +++ b/www/poll/render.js @@ -127,7 +127,6 @@ var Renderer = function (Cryptpad) { }; var createRow = Render.createRow = function (obj, cb, id, value) { - console.error('new row!'); var order = Cryptpad.find(obj, ['table', 'rowsOrder']); if (!order) { throw new Error("Uninitialized realtime object!"); } id = id || rowuid(); From 39ca2e6dd61c96015991d5019d17f004a931d93b Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 23 Jan 2017 10:52:37 +0100 Subject: [PATCH 57/88] Fix bootstrap conflict with context menus --- www/drive/file.css | 4 ++++ www/drive/inner.html | 32 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/www/drive/file.css b/www/drive/file.css index 2fad2fd94..2d88f50f6 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -52,6 +52,10 @@ li { display: none; position: absolute; } +.contextMenu li { + padding: 0; + font-size: 16px; +} .droppable { background-color: #FE9A2E; diff --git a/www/drive/inner.html b/www/drive/inner.html index 379a8fed0..368638704 100644 --- a/www/drive/inner.html +++ b/www/drive/inner.html @@ -18,38 +18,38 @@
From 5e36d9ea29c754b7378a045aba68dfde15a0ebaa Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 23 Jan 2017 10:51:44 +0100 Subject: [PATCH 58/88] Fix polls table not updated with local events --- www/poll/main.js | 47 ++++++++++++++++++++++++++-------------------- www/poll/render.js | 1 - 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/www/poll/main.js b/www/poll/main.js index e15adab41..ea12f3426 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -26,6 +26,13 @@ define([ secret.keys = secret.key; } + var DEBUG = false; + var debug = console.log; + if (!DEBUG) { + debug = function() {}; + } + var error = console.error; + Cryptpad.addLoadingScreen(); var onConnectError = function (info) { Cryptpad.errorLoadingScreen(Messages.websocketError); @@ -187,11 +194,11 @@ define([ /* Any time the realtime object changes, call this function */ var change = function (o, n, path, throttle) { - if (!Cryptpad.isArray(path)) { + if (path && !Cryptpad.isArray(path)) { return; } if (path && path.join) { - console.log("Change from [%s] to [%s] at [%s]", + debug("Change from [%s] to [%s] at [%s]", o, n, path.join(', ')); } @@ -242,7 +249,7 @@ define([ var type = input.type.toLowerCase(); var id = getRealtimeId(input); - console.log(input); + debug(input); var object = APP.proxy; @@ -253,22 +260,22 @@ define([ switch (type) { case 'text': - console.log("text[rt-id='%s'] [%s]", id, input.value); - if (!input.value) { return void console.log("Hit enter?"); } + debug("text[rt-id='%s'] [%s]", id, input.value); + if (!input.value) { return void debug("Hit enter?"); } Render.setValue(object, id, input.value); change(null, null, null, 50); break; case 'checkbox': - console.log("checkbox[tr-id='%s'] %s", id, input.checked); + debug("checkbox[tr-id='%s'] %s", id, input.checked); if (APP.editable.col.indexOf(x) >= 0 || x === APP.userid) { Render.setValue(object, id, input.checked); change(); } else { - console.log('checkbox locked'); + debug('checkbox locked'); } break; default: - console.log("Input[type='%s']", type); + debug("Input[type='%s']", type); break; } }; @@ -308,7 +315,7 @@ define([ } else if (type === 'cell') { change(); } else { - console.log("UNHANDLED"); + debug("UNHANDLED"); } }; @@ -333,10 +340,10 @@ define([ var target = e && e.target; if (isKeyup) { - console.log("Keyup!"); + debug("Keyup!"); } - if (!target) { return void console.log("NO TARGET"); } + if (!target) { return void debug("NO TARGET"); } var nodeName = target && target.nodeName; @@ -356,7 +363,7 @@ define([ //console.error(new Error("C'est pas possible!")); break; default: - console.log(target, nodeName); + debug(target, nodeName); break; } }; @@ -366,7 +373,7 @@ define([ */ var prepareProxy = function (proxy, schema) { if (proxy && proxy.version === 1) { return; } - console.log("Configuring proxy schema..."); + debug("Configuring proxy schema..."); proxy.info = proxy.info || schema.info; Object.keys(schema.info).forEach(function (k) { @@ -466,8 +473,8 @@ define([ document.title = newTitle; Cryptpad.renamePad(newTitle, function (err, data) { if (err) { - console.log("Couldn't set pad title"); - console.error(err); + debug("Couldn't set pad title"); + error(err); document.title = oldTitle; return; } @@ -501,8 +508,8 @@ define([ var $description = $('#description').attr('placeholder', Messages.poll_descriptionHint || 'description'); var ready = function (info, userid, readOnly) { - console.log("READY"); - console.log('userid: %s', userid); + debug("READY"); + debug('userid: %s', userid); var proxy = APP.proxy; var uncommitted = APP.uncommitted = {}; @@ -613,7 +620,7 @@ define([ notify(); } - console.log("change: (%s, %s, [%s])", o, n, p.join(', ')); + debug("change: (%s, %s, [%s])", o, n, p.join(', ')); }) .on('change', ['table'], change) .on('remove', [], change); @@ -727,8 +734,8 @@ define([ Cryptpad.getPadTitle(function (err, title) { if (err) { - console.error(err); - console.log("Couldn't get pad title"); + error(err); + debug("Couldn't get pad title"); return; } updateTitle(title || defaultName); diff --git a/www/poll/render.js b/www/poll/render.js index ce2f67518..3f1e8b614 100644 --- a/www/poll/render.js +++ b/www/poll/render.js @@ -127,7 +127,6 @@ var Renderer = function (Cryptpad) { }; var createRow = Render.createRow = function (obj, cb, id, value) { - console.error('new row!'); var order = Cryptpad.find(obj, ['table', 'rowsOrder']); if (!order) { throw new Error("Uninitialized realtime object!"); } id = id || rowuid(); From c77abfa7f4909ffe50242cf8d4b8f56eb79f902a Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 23 Jan 2017 11:05:03 +0100 Subject: [PATCH 59/88] Remove a second scrollbar in polls --- www/poll/index.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/www/poll/index.html b/www/poll/index.html index deac65f77..ab78be2f5 100644 --- a/www/poll/index.html +++ b/www/poll/index.html @@ -32,8 +32,6 @@ } .realtime { display: block; - overflow: auto; - max-height: 100%; max-width: 100%; } From 141f8f776a9da92e1b303b0dd40b025e21678cb1 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 23 Jan 2017 12:29:12 +0100 Subject: [PATCH 60/88] Fix the Noscript bug --- customize.dist/share/frame.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/customize.dist/share/frame.js b/customize.dist/share/frame.js index d3d4fb00d..9f604af23 100644 --- a/customize.dist/share/frame.js +++ b/customize.dist/share/frame.js @@ -24,7 +24,10 @@ onload(void 0, iframe, e); window.clearTimeout(to); }; - iframe.setAttribute('src', src); + // We must pass a unique parameter here to avoid cache problems in Firefox with + // the NoScript plugin: if the iframe's content is taken from the cache, the JS + // is not executed with NoScript.... + iframe.setAttribute('src', src + '?t=' + new Date().getTime()); parent.appendChild(iframe); }; From 82caa1aa8b647af08ff35ef882d61e19cd2538e7 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 23 Jan 2017 12:29:12 +0100 Subject: [PATCH 61/88] Fix the Noscript bug --- customize.dist/share/frame.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/customize.dist/share/frame.js b/customize.dist/share/frame.js index d3d4fb00d..9f604af23 100644 --- a/customize.dist/share/frame.js +++ b/customize.dist/share/frame.js @@ -24,7 +24,10 @@ onload(void 0, iframe, e); window.clearTimeout(to); }; - iframe.setAttribute('src', src); + // We must pass a unique parameter here to avoid cache problems in Firefox with + // the NoScript plugin: if the iframe's content is taken from the cache, the JS + // is not executed with NoScript.... + iframe.setAttribute('src', src + '?t=' + new Date().getTime()); parent.appendChild(iframe); }; From f8455875a9ab9b5fdc54ae5f85fe774522c46e51 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 23 Jan 2017 15:07:38 +0100 Subject: [PATCH 62/88] Fix the NoScript (iframe not loaded) bug with inner iframes --- www/code/index.html | 5 ++++- www/pad/index.html | 5 ++++- www/slide/index.html | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/www/code/index.html b/www/code/index.html index 847ac2ec6..b4b1e025f 100644 --- a/www/code/index.html +++ b/www/code/index.html @@ -47,7 +47,10 @@
- + +
diff --git a/www/pad/index.html b/www/pad/index.html index 8437073af..d26ce6b96 100644 --- a/www/pad/index.html +++ b/www/pad/index.html @@ -59,7 +59,10 @@ - + + diff --git a/www/slide/index.html b/www/slide/index.html index 1af49e2ab..c5f2f0fd6 100644 --- a/www/slide/index.html +++ b/www/slide/index.html @@ -51,7 +51,10 @@
- + +
From a5c03c1540edfb42d8cda67ed11aed64497f1f72 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 24 Jan 2017 12:38:06 +0100 Subject: [PATCH 63/88] Make sure data is migrated before leaving registration page --- www/user/main.js | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/www/user/main.js b/www/user/main.js index b658ef76a..e45d48655 100644 --- a/www/user/main.js +++ b/www/user/main.js @@ -227,13 +227,26 @@ define([ proxy[k] = map[k]; }); - delete localStorage.FS_hash; - - if (!proxy[USERNAME_KEY]) { - proxy[USERNAME_KEY] = opt.name; - } - - next(); + var whenSynced = function () { + delete localStorage.FS_hash; + + if (!proxy[USERNAME_KEY]) { + proxy[USERNAME_KEY] = opt.name; + } + next(); + }; + + // Make sure the migration is synced in chainpad before continuing otherwise + // we may leave that page too early or trigger a reload in another tab before + // the migration is complete + var check = function () { + if (APP.realtime.getUserDoc() === APP.realtime.getAuthDoc()) { + whenSynced(); + return; + } + window.setTimeout(check, 300); + }; + check(); }); }); }); From f5753cf594fef79cdc6e11b028713d6794b54027 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 24 Jan 2017 12:42:21 +0100 Subject: [PATCH 64/88] Fix typo --- customize.dist/translations/messages.fr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 69c1f87bd..9bb697ebf 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -63,7 +63,7 @@ define(function () { out.userButton = 'UTILISATEUR'; out.userButtonTitle = "Changer votre nom d'utilisateur"; out.changeNamePrompt = 'Changer votre nom (laisser vide pour rester anonyme) : '; - out.user_rename = "Changer le nmm affiché"; + out.user_rename = "Changer le nom affiché"; out.user_displayName = "Nom affiché"; out.user_accountName = "Nom d'utilisateur"; From 9d275daebbd6ac832b1c210673d22573d123ed83 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 24 Jan 2017 12:47:53 +0100 Subject: [PATCH 65/88] Backport changes for the login page from hpbs branch --- customize.dist/translations/messages.fr.js | 63 +++++++++++++++-- customize.dist/translations/messages.js | 35 +++++----- www/common/toolbar.js | 12 +++- www/user/index.html | 8 ++- www/user/main.js | 81 ++++++++++++++++++---- 5 files changed, 160 insertions(+), 39 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 22d778d14..4ac605f5a 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -1,6 +1,8 @@ define(function () { var out = {}; + // translations must set this key for their language to be available in + // the language dropdowns that are shown throughout Cryptpad's interface out._languageName = "Français"; out.main_title = "Cryptpad: Éditeur collaboratif en temps réel, zero knowledge"; @@ -61,8 +63,6 @@ define(function () { out.userButton = 'UTILISATEUR'; out.userButtonTitle = "Changer votre nom d'utilisateur"; out.changeNamePrompt = 'Changer votre nom (laisser vide pour rester anonyme) : '; - out.user_login = "Connexion"; - out.user_logout = "Déconnexion"; out.user_rename = "Changer le nom affiché"; out.user_displayName = "Nom affiché"; out.user_accountName = "Nom d'utilisateur"; @@ -121,10 +121,12 @@ define(function () { out.recentPadsIframe = 'Vos documents récents'; out.okButton = 'OK (Entrée)'; + + out.cancel = "Annuler"; out.cancelButton = 'Annuler (Echap)'; out.loginText = '

Votre nom d\'utilisateur et votre mot de passe sont utilisés pour générer une clé unique qui reste inconnue de notre serveur.

\n' + - '

Faites attention de ne pas oublier vos identifiants puisqu\'ils seront impossible à récupérer.

'; + '

Faites attention de ne pas oublier vos identifiants puisqu\'ils seront impossible à récupérer.

'; //TODO out.forget = "Oublier"; @@ -184,6 +186,7 @@ define(function () { out.fm_trashName = "Corbeille"; out.fm_unsortedName = "Fichiers non triés"; out.fm_filesDataName = "Tous les fichiers"; + out.fm_templateName = "Modèles"; out.fm_newButton = "Nouveau"; out.fm_newFolder = "Nouveau dossier"; out.fm_folder = "Dossier"; @@ -237,6 +240,43 @@ define(function () { 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."; + // login + out.login_login = "Connexion"; + out.login_nologin = "Documents récents de ce navigateur"; + out.login_register = "Inscription"; + out.logoutButton = "Déconnexion"; + + out.login_migrate = "Souhaitez-vous importer les données existantes de votre session anonyme ?"; + + out.username_label = "Nom d'utilisateur : "; + out.displayname_label = "Nom affiché : "; + + out.login_username = "votre nom d'utilisateur"; + out.login_password = "votre mot de passe"; + out.login_confirm = "confirmer votre mot de passe"; + out.login_remember = "Se souvenir de moi"; + + out.login_cancel_prompt = "...ou si vous avez entré le mauvais nom d'utilisateur ou mot de passe, annulez pour essayer à nouveau."; + + out.login_registerSuccess = "Inscription réalisée avec succès. Prenez soin de ne pas oublier votre mot de passe !"; + out.login_passwordMismatch = "Les deux mots de passe entrés sont différents. Essayez à nouveau."; + + out.login_warning = [ + '

ATTENTION

', + '

Cryptpad sauve vos données personnelles dans un document temps-réel chiffré, comme pour tous les autres types de documents temps-réel.

', + '

Votre nom d\'utilisateur et votre mot de passe ne sont jamais envoyés au serveur de manière non-chiffré.

', + '

Ainsi, si vous oubliez votre nom d\'utilisateur ou votre mot de passe, il n\'y a absolument rien que nous puissions faire pour retrouver vos informations perdues.

', + '

Prenez soin de ne surtout pas oublier votre nom d\'utilisateur OU votre mot de passe !

', + ].join('\n'); + + out.login_hashing = "Traitement de vos identifiants, cela peut nécessiter quelques instants."; + + out.login_no_user = "Il n'y a aucun utilisateur associé au nom et au mot de passe que vous avez entré."; + out.login_confirm_password = "Veuillez taper de nouveau votre mot de passe pour vous inscrire..."; + + out.loginText = '

Votre nom d\'utilisateur et votre mot d epasse sont utilisés pour générer une clé unique qui reste inconnue de notre serveur.

\n' + + '

Faîtes attention de ne pas perdre vos identifiants, puisqu\'il est impossible de les récupérer

'; + // index.html out.main_p1 = 'CryptPad est l\'éditeur collaboratif en temps réel zero knowledge. Le chiffrement est effectué depuis votre navigateur, ce qui protège les données contre le serveur, le cloud, et la NSA. La clé de chiffrement est stockée dans l\'identifieur de fragment de l\'URL qui n\'est jamais envoyée au serveur mais est accessible depuis javascript, de sorte qu\'en partageant l\'URL, vous donnez l\'accès au pad à ceux qui souhaitent participer.'; @@ -253,10 +293,19 @@ define(function () { out.table_created = 'Créé le'; out.table_last = 'Dernier accès'; - out.button_newpad = 'NOUVEAU DOCUMENT TEXTE'; - out.button_newcode = 'NOUVELLE PAGE DE CODE'; - out.button_newpoll = 'NOUVEAU SONDAGE'; - out.button_newslide = 'NOUVELLE PRÉSENTATION'; + out.button_newpad = 'Nouveau document texte'; + out.button_newcode = 'Nouvelle page de code'; + out.button_newpoll = 'Nouveau sondage'; + out.button_newslide = 'Nouvelle présentation'; + + out.form_title = "Tous vos pads, partout où vous allez !"; + out.form_username = "Nom d'utilisateur"; + out.form_password = "Mot de passe"; + + out.about = "À propos"; + out.privacy = "Vie privée"; + out.contact = "Contact"; + out.terms = "Conditions"; // privacy.html diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 9aa315ec1..133f41d6b 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -63,8 +63,6 @@ define(function () { out.userButton = 'USER'; out.userButtonTitle = 'Change your username'; out.changeNamePrompt = 'Change your name (leave empty to be anonymous): '; - out.user_login = "Log in"; - out.user_logout = "Log out"; out.user_rename = "Change display name"; out.user_displayName = "Display name"; out.user_accountName = "Account name"; @@ -124,7 +122,7 @@ define(function () { out.okButton = 'OK (enter)'; - out.cancel = "cancel"; + out.cancel = "Cancel"; out.cancelButton = 'Cancel (esc)'; out.forget = "Forget"; @@ -240,9 +238,10 @@ define(function () { 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"; - out.login_register = "register"; - out.logoutButton = "log out"; + out.login_login = "Log in"; + out.login_nologin = "Your browser's recent pads"; + out.login_register = "Sign up"; + out.logoutButton = "Log out"; out.login_migrate = "Would you like to migrate existing data from your anonymous session?"; @@ -252,7 +251,7 @@ define(function () { out.login_username = "your username"; out.login_password = "your password"; out.login_confirm = "confirm your password"; - out.login_remember = "remember me"; + out.login_remember = "Remember me"; out.login_cancel_prompt = "...or if you may have entered the wrong username or password, cancel to try again."; @@ -267,11 +266,6 @@ define(function () { '

Make sure you do not forget your username and password!

', ].join('\n'); - out.login_logout = [ - //'

It seems you are already logged in

', - //'

Would you like to log out and authenticate as another user?

', - ].join('\n'); - out.login_hashing = "Hashing your password, this might take some time."; out.login_no_user = "There is no user associated with the username and password that you entered."; @@ -296,10 +290,19 @@ define(function () { out.table_created = 'Created'; out.table_last = 'Last Accessed'; - out.button_newpad = 'NEW RICH TEXT PAD'; - out.button_newcode = 'NEW CODE PAD'; - out.button_newpoll = 'NEW POLL'; - out.button_newslide = 'NEW PRESENTATION'; + out.button_newpad = 'New Rich Text pad'; + out.button_newcode = 'New Code pad'; + out.button_newpoll = 'New Poll'; + out.button_newslide = 'New Presentation'; + + out.form_title = "All your pads, everywhere!"; + out.form_username = "Username"; + out.form_password = "Password"; + + out.about = "About"; + out.privacy = "Privacy"; + out.contact = "Contact"; + out.terms = "ToS"; // privacy.html diff --git a/www/common/toolbar.js b/www/common/toolbar.js index a4c63a902..c2a74e44c 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -410,13 +410,18 @@ define([ options.push({ tag: 'a', attributes: {'class': 'logout'}, - content: Messages.user_logout + content: Messages.logoutButton }); } else { options.push({ tag: 'a', attributes: {'class': 'login'}, - content: Messages.user_login + content: Messages.login_login + }); + options.push({ + tag: 'a', + attributes: {'class': 'register'}, + content: Messages.login_register }); } var $icon = $('', {'class': 'fa fa-user'}); @@ -439,6 +444,9 @@ define([ $userAdmin.find('a.login').click(function (e) { window.open('/user'); }); + $userAdmin.find('a.register').click(function (e) { + window.open('/user#register'); + }); if (config.userName && config.userName.setName && config.userName.lastName) { $userAdmin.find('a.' + USERBUTTON_CLS).click(function (e) { diff --git a/www/user/index.html b/www/user/index.html index 5f27377ba..b4e7eb2ac 100644 --- a/www/user/index.html +++ b/www/user/index.html @@ -25,6 +25,11 @@ display: none; border-radius: 5px; } + + .register { + display: none; + } + @media (max-width: 1000px) { div.panel { width: 90%; } } @@ -49,6 +54,7 @@


+
@@ -83,6 +89,6 @@

-

View your file manager.

+

View your CryptDrive.

diff --git a/www/user/main.js b/www/user/main.js index fc159e314..e45d48655 100644 --- a/www/user/main.js +++ b/www/user/main.js @@ -23,8 +23,10 @@ define([ // login elements var $loginBox = $('#login-panel'); var $login = $('#login'); + var $login_register = $('#login_register'); var $username = $('#username'); var $password = $('#password'); + var $password_register = $('#confirm_register'); var $remember = $('#remember'); // hashing elements @@ -61,7 +63,13 @@ define([ var revealConfirm = APP.revealConfirm = revealer($confirmBox); var revealLogout = APP.revealLogout= revealer($logoutBox); - var revealUser = APP.revealUser = revealer($userBox); + var revealUser_false = APP.revealUser_false = revealer($userBox); + var revealUser = APP.revealUser = function (state) { + if (!state) { + revealUser_false(state); + } + document.location.href = '/drive'; + }; var getDisplayName = APP.getDisplayName = function (proxy) { return proxy['cryptpad.username']; @@ -186,9 +194,9 @@ define([ }; }; - var handleNewUser = function (proxy, opt) { + var handleNewUser = function (proxy, opt, force) { // could not find a profile for that username/password - confirmPassword(proxy, opt.password, function () { + var todo = function () { APP.confirming = false; APP.setAccountName((proxy.login_name = opt.name)); APP.setDisplayName(APP.getDisplayName(proxy)); @@ -219,17 +227,35 @@ define([ proxy[k] = map[k]; }); - delete localStorage.FS_hash; - - if (!proxy[USERNAME_KEY]) { - proxy[USERNAME_KEY] = opt.name; - } - - next(); + var whenSynced = function () { + delete localStorage.FS_hash; + + if (!proxy[USERNAME_KEY]) { + proxy[USERNAME_KEY] = opt.name; + } + next(); + }; + + // Make sure the migration is synced in chainpad before continuing otherwise + // we may leave that page too early or trigger a reload in another tab before + // the migration is complete + var check = function () { + if (APP.realtime.getUserDoc() === APP.realtime.getAuthDoc()) { + whenSynced(); + return; + } + window.setTimeout(check, 300); + }; + check(); }); }); }); - }); + }; + if (force) { + todo(); + return; + } + confirmPassword(proxy, opt.password, todo); }; var handleUser = function (proxy, opt) { @@ -237,6 +263,9 @@ define([ var now = opt.now = +(new Date()); if (!proxyKeys.length) { + if (opt.register) { + return handleNewUser(proxy, opt, true); + } return handleNewUser(proxy, opt); } handleRegisteredUser(proxy, opt); @@ -287,7 +316,6 @@ define([ }; var rt = APP.rt = Listmap.create(config); - rt.proxy.on('create', function (info) { APP.realtime = info.realtime; }) @@ -310,6 +338,11 @@ define([ revealUser(true); } else { + if (sessionStorage.register || document.location.hash.slice(1) === 'register') { + document.location.hash = 'register'; + $login.text(Cryptpad.Messages.login_register); + $('#login-panel .register').show(); + } revealLogin(true); } @@ -318,9 +351,15 @@ define([ $login.click(function () { var uname = $username.val().trim(); var passwd = $password.val(); + var passwd_confirm = $password_register.val(); var confirm = $confirm.val(); var remember = $remember[0].checked; + var register = document.location.hash.slice(1) === 'register'; + + if (passwd !== passwd_confirm && register) { + return void Cryptpad.alert("Passwords are not the same"); + } if (!Cred.isValidUsername(uname)) { return void Cryptpad.alert('invalid username'); } @@ -341,7 +380,7 @@ define([ window.setTimeout(function () { useBytes(bytes, { remember: remember, - //register: register, + register: register, name: uname, password: passwd, }); @@ -350,5 +389,21 @@ define([ }, 75); }); }); + + if (sessionStorage.login) { + $username.val(sessionStorage.login_user); + $password.val(sessionStorage.login_pass); + $remember.attr('checked', sessionStorage.login_rmb === "true"); + $login.click(); + } + if (sessionStorage.register) { + $username.val(sessionStorage.login_user); + $password.val(sessionStorage.login_pass); + $remember.attr('checked', sessionStorage.login_rmb === "true"); + } + ['login', 'register', 'login_user', 'login_pass', 'login_rmb'].forEach(function (k) { + delete sessionStorage[k]; + }); + }); }); From 88021f226473db1dcacdee32e4eb13f0ad290f7c Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 24 Jan 2017 18:14:29 +0100 Subject: [PATCH 66/88] Anonymous pads fo anonymous users --- customize.dist/fsStore.js | 18 +++++-- www/common/cryptpad-common.js | 19 +++++-- www/common/fileObject.js | 65 +++++++++++++++++------- www/drive/file.css | 2 +- www/drive/main.js | 96 +++++++++++++++++++++++++---------- 5 files changed, 145 insertions(+), 55 deletions(-) diff --git a/customize.dist/fsStore.js b/customize.dist/fsStore.js index 1ab788dc4..dcf36927b 100644 --- a/customize.dist/fsStore.js +++ b/customize.dist/fsStore.js @@ -39,6 +39,11 @@ define([ cb(void 0, map); }; + Store.setDrive = function (key, val, cb) { + storeObj.drive[key] = val; + cb(); + }; + var safeGet = window.safeGet = function (key) { return storeObj[key]; }; @@ -56,6 +61,10 @@ define([ cb(void 0, res); }; + Store.getDrive = function (key, cb) { + cb(void 0, storeObj.drive[key]); + }; + var safeRemove = function (key) { delete storeObj[key]; }; @@ -127,7 +136,7 @@ define([ }; var onReady = function (f, proxy, storageKey) { - filesOp = FO.init(proxy, { + filesOp = FO.init(proxy.drive, { storageKey: storageKey }); storeObj = proxy; @@ -179,10 +188,13 @@ define([ } }).on('ready', function () { if (ready) { return; } - if (!rt.proxy[Cryptpad.storageKey] || !Cryptpad.isArray(rt.proxy[Cryptpad.storageKey])) { + if (!rt.proxy.drive || typeof(rt.proxy.drive) !== 'object') { rt.proxy.drive = {}; } + var drive = rt.proxy.drive; + // Creating a new anon drive: import anon pads from localStorage + if (!drive[Cryptpad.storageKey] || !Cryptpad.isArray(drive[Cryptpad.storageKey])) { var oldStore = Cryptpad.getStore(true); oldStore.get(Cryptpad.storageKey, function (err, s) { - rt.proxy[Cryptpad.storageKey] = s; + drive[Cryptpad.storageKey] = s; onReady(f, rt.proxy, Cryptpad.storageKey); }); return; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 9ae31a238..1daf1fe73 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -80,7 +80,7 @@ define([ var logout = common.logout = function (cb) { [ - fileHashKey, +// fileHashKey, userHashKey, ].forEach(function (k) { sessionStorage.removeItem(k); @@ -88,6 +88,9 @@ define([ delete localStorage[k]; delete sessionStorage[k]; }); + if (!localStorage[fileHashKey]) { + localStorage[fileHashKey] = common.createRandomHash(); + } if (cb) { cb(); } }; @@ -101,6 +104,11 @@ define([ return hash; }; + var isLoggedIn = common.isLoggedIn = function () { + //return typeof getStore().getLoginName() === "string"; + return typeof getUserHash() === "string"; + }; + // var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; }; var isArray = common.isArray = $.isArray; @@ -444,7 +452,7 @@ define([ // STORAGE /* fetch and migrate your pad history from localStorage */ var getRecentPads = common.getRecentPads = function (cb, legacy) { - getStore(legacy).get(storageKey, function (err, recentPads) { + getStore(legacy).getDrive(storageKey, function (err, recentPads) { if (isArray(recentPads)) { cb(void 0, migrateRecentPads(recentPads)); return; @@ -456,7 +464,7 @@ define([ // STORAGE /* commit a list of pads to localStorage */ var setRecentPads = common.setRecentPads = function (pads, cb, legacy) { - getStore(legacy).set(storageKey, pads, function (err, data) { + getStore(legacy).setDrive(storageKey, pads, function (err, data) { cb(err, data); }); }; @@ -566,8 +574,11 @@ define([ if (!contains) { var data = makePad(href, name); + if (common.initialPath) { + data.owner = 1; // TODO use owner id here? + } renamed.push(data); - if (USE_FS_STORE && typeof(getStore().addPad) === "function") { + if (USE_FS_STORE && common.initialPath && typeof(getStore().addPad) === "function") { getStore().addPad(href, common.initialPath, name); } } diff --git a/www/common/fileObject.js b/www/common/fileObject.js index 7398ffc7d..4137a0f84 100644 --- a/www/common/fileObject.js +++ b/www/common/fileObject.js @@ -8,6 +8,7 @@ define([ var ROOT = "root"; var UNSORTED = "unsorted"; var FILES_DATA = "filesData"; + var ANON = "anon"; // virtual path var TRASH = "trash"; var TEMPLATE = "template"; var NEW_FOLDER_NAME = Messages.fm_newFolder; @@ -57,6 +58,9 @@ define([ var isPathInTrash = exp.isPathInTrash = function (path) { return path[0] && path[0] === TRASH; }; + var isPathInAnon = exp.isPathInAnon = function (path) { + return path[0] && path[0] === ANON; + }; var isPathInFilesData = exp.isPathInFilesData = function (path) { return path[0] && path[0] === FILES_DATA; @@ -227,6 +231,13 @@ define([ return ret; }; + /*var getAnonFiles = exp.getAnonFiles = function () { + if (!files[ANON]) { + files[ANON] = []; + } + return files[ANON].slice(); + };*///TODO + var removeFileFromRoot = function (root, href) { if (isFile(root)) { return; } for (var e in root) { @@ -688,6 +699,11 @@ define([ }); }; + var isAnonFile = exp.isAnonFile = function (file) { + var data = getFileData(file); + return !data.owner; + }; + var fixFiles = exp.fixFiles = function () { // Explore the tree and check that everything is correct: // * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects @@ -709,6 +725,11 @@ define([ debug("An element in ROOT was not a folder nor a file. ", element[el]); element[el] = undefined; delete element[el]; + } else if (isFile(element[el])) { + if (isAnonFile(element[el])) { + debug("An element in ROOT was an anonymous file. ", element[el]); + delete element[el]; + } } else if (isFolder(element[el])) { fixRoot(element[el]); } @@ -721,6 +742,7 @@ define([ var addToClean = function (obj, idx) { if (typeof(obj) !== "object") { toClean.push(idx); return; } if (!isFile(obj.element) && !isFolder(obj.element)) { toClean.push(idx); return; } + if (isFile(obj.element) && isAnonFile(obj.element)) { toClean.push(idx); return; } if (!$.isArray(obj.path)) { toClean.push(idx); return; } }; for (var el in tr) { @@ -745,15 +767,12 @@ define([ var templateFiles = getTemplateFiles(); var toClean = []; us.forEach(function (el, idx) { - if (!isFile(el) || rootFiles.indexOf(el) !== -1 || templateFiles.indexOf(el) !== -1) { + if (!isFile(el) || rootFiles.indexOf(el) !== -1 || templateFiles.indexOf(el) !== -1 || isAnonFile(el)) { toClean.push(idx); } }); - toClean.forEach(function (el) { - var idx = us.indexOf(el); - if (idx !== -1) { - us.splice(idx, 1); - } + toClean.forEach(function (idx) { + us.splice(idx, 1); }); }; var fixTemplate = function () { @@ -764,36 +783,44 @@ define([ var unsortedFiles = getUnsortedFiles(); var toClean = []; us.forEach(function (el, idx) { - if (!isFile(el) || rootFiles.indexOf(el) !== -1 || unsortedFiles.indexOf(el) !== -1) { + if (!isFile(el) || rootFiles.indexOf(el) !== -1 || unsortedFiles.indexOf(el) !== -1 || isAnonFile(el)) { toClean.push(idx); } }); - toClean.forEach(function (el) { - var idx = us.indexOf(el); - if (idx !== -1) { - us.splice(idx, 1); - } + toClean.forEach(function (idx) { + us.splice(idx, 1); }); }; + /*var fixAnon = function () { + if (!$.isArray(files[ANON])) { debug("ANON was not an array"); files[FILES_DATA] = []; } + };*/// TODO var fixFilesData = function () { if (!$.isArray(files[FILES_DATA])) { debug("FILES_DATA was not an array"); files[FILES_DATA] = []; } var fd = files[FILES_DATA]; var rootFiles = getRootFiles(); var unsortedFiles = getUnsortedFiles(); + var templateFiles = getTemplateFiles(); var trashFiles = getTrashFiles(); + //var anonFiles = getAnonFiles(); var toClean = []; fd.forEach(function (el, idx) { if (typeof(el) !== "object") { debug("An element in filesData was not an object.", el); toClean.push(el); - } else { - if (rootFiles.indexOf(el.href) === -1 - && unsortedFiles.indexOf(el.href) === -1 - && trashFiles.indexOf(el.href) === -1) { - debug("An element in filesData was not in ROOT, UNSORTED or TRASH.", el); - files[UNSORTED].push(el.href); - } + return; + } + if (el.owner + && rootFiles.indexOf(el.href) === -1 + && unsortedFiles.indexOf(el.href) === -1 + && templateFiles.indexOf(el.href) === -1 + && trashFiles.indexOf(el.href) === -1) { + debug("An element in filesData was not in ROOT, UNSORTED or TRASH.", el); + files[UNSORTED].push(el.href); + return; } + /*if (!el.owner && anonFiles.indexOf(el.href) === -1) { + files[ANON].push(el.href); + }*/// TODO }); toClean.forEach(function (el) { var idx = fd.indexOf(el); diff --git a/www/drive/file.css b/www/drive/file.css index 2fad2fd94..d6c1f2274 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -97,7 +97,7 @@ li { text-decoration: underline; } -#tree #trashTree, #tree #unsortedTree, #tree #templateTree, #tree #allfilesTree { +#tree .category2 { margin-top: 2em; } diff --git a/www/drive/main.js b/www/drive/main.js index 308beed83..d1d89ee35 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -26,7 +26,8 @@ define([ var APP = window.APP = { $bar: $iframe.find('#toolbar'), editable: false, - Cryptpad: Cryptpad + Cryptpad: Cryptpad, + loggedIn: Cryptpad.isLoggedIn() }; var stringify = APP.stringify = function (obj) { @@ -43,6 +44,11 @@ define([ var TEMPLATE_NAME = Messages.fm_templateName; var TRASH = "trash"; var TRASH_NAME = Messages.fm_trashName; + + // anon: Virtual path, not stored in the object but extracted from FILES_DATA + var ANON = "anon"; + var ANON_NAME = Messages.fm_anonName || 'Anon pads......'; + var LOCALSTORAGE_LAST = "cryptpad-file-lastOpened"; var LOCALSTORAGE_OPENED = "cryptpad-file-openedFolders"; var LOCALSTORAGE_VIEWMODE = "cryptpad-file-viewMode"; @@ -130,7 +136,8 @@ define([ else { $iframe.find('[draggable="false"]').attr('draggable', true); } }; - var init = function (files) { + var init = function (proxy) { + var files = proxy.drive; var isOwnDrive = function () { return Cryptpad.getUserHash() === APP.hash || localStorage.FS_hash === APP.hash; }; @@ -166,7 +173,7 @@ define([ // FILE MANAGER // _WORKGROUP_ and other people drive : display Documents as main page - var currentPath = module.currentPath = isOwnDrive() ? getLastOpenedFolder() : [ROOT]; + var currentPath = module.currentPath = APP.loggedIn ? isOwnDrive() ? getLastOpenedFolder() : [ROOT] : [ANON]; var lastSelectTime; var selectedElement; @@ -725,6 +732,7 @@ define([ 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 === ANON && path.length === 1) { name = ANON_NAME; } else if (name === FILES_DATA && path.length === 1) { name = FILES_DATA_NAME; } else if (filesOp.isPathInTrash(path)) { name = getTrashTitle(path); } var $title = $('

').text(name); @@ -749,19 +757,19 @@ define([ var $box = $('
', {'class': 'info-box'}); var msg; switch (path[0]) { - case 'root': + case ROOT: msg = Messages.fm_info_root; break; - case 'unsorted': + case UNSORTED: msg = Messages.fm_info_unsorted; break; - case 'template': + case TEMPLATE: msg = Messages.fm_info_template; break; - case 'trash': + case TRASH: msg = Messages.fm_info_trash; break; - case Cryptpad.storageKey: + case FILES_DATA: msg = Messages.fm_info_allFiles; break; default: @@ -836,12 +844,13 @@ define([ options.push({tag: 'hr'}); } AppConfig.availablePadTypes.forEach(function (type) { + var path = filesOp.comparePath(currentPath, [ANON]) ? '' : '/#?path=' + encodeURIComponent(currentPath); options.push({ tag: 'a', attributes: { 'class': 'newdoc', 'data-type': type, - 'href': '/' + type + '/#?path=' + encodeURIComponent(currentPath), + 'href': '/' + type + path, 'target': '_blank' }, content: Messages.type[type] @@ -1060,7 +1069,7 @@ 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 displayHrefArray = function ($container, rootName) { + var displayHrefArray = function ($container, rootName, draggable) { var unsorted = files[rootName]; if (rootName === UNSORTED && allFilesSorted()) { return; } var $fileHeader = getFileListHeader(false); @@ -1081,7 +1090,7 @@ define([ var $name = $('', { 'class': 'file-element element' }); addFileData(href, file.title, $name, false); var $element = $('
  • ', { - draggable: true + draggable: draggable }).append($icon).append($name).dblclick(function () { openFile(href); }); @@ -1092,17 +1101,22 @@ define([ onElementClick(e, $element, path); }); $element.contextmenu(openDefaultContextMenu); - addDragAndDropHandlers($element, path, false, false); + if (draggable) { + addDragAndDropHandlers($element, path, false, false); + } $container.append($element); }); }; - var displayAllFiles = function ($container) { + var displayAllFiles = function ($container, anon) { var allfiles = files[FILES_DATA]; if (allfiles.length === 0) { return; } var $fileHeader = getFileListHeader(false); $container.append($fileHeader); - var keys = allfiles; + var keys = allfiles.filter(function (el) { + return anon && !el.owner || !anon && el.owner; + }); + var sortedFiles = sortElements(false, [FILES_DATA], keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !getSortFileDesc(), false, true); sortedFiles.forEach(function (file) { var $icon = $fileIcon.clone(); @@ -1183,9 +1197,10 @@ define([ var isUnsorted = filesOp.comparePath(path, [UNSORTED]); var isTemplate = filesOp.comparePath(path, [TEMPLATE]); var isAllFiles = filesOp.comparePath(path, [FILES_DATA]); + var isAnon = filesOp.comparePath(path, [ANON]); var root = filesOp.findElement(files, path); - if (typeof(root) === "undefined") { + if (typeof(root) === "undefined" && !isAnon) { log(Messages.fm_unknownFolderError); debug("Unable to locate the selected directory: ", path); var parentPath = path.slice(); @@ -1221,9 +1236,12 @@ define([ var $fileHeader = getFileListHeader(true); if (isUnsorted || isTemplate) { - displayHrefArray($list, path[0]); + // 3rd parameter is "draggable": anon pads shouldn't be draggable + displayHrefArray($list, path[0], !isAnon); } else if (isAllFiles) { - displayAllFiles($list); + displayAllFiles($list, false); + } else if (isAnon) { + displayAllFiles($list, true); } else if (isTrashRoot) { displayTrashRoot($list, $folderHeader, $fileHeader); } else { @@ -1352,7 +1370,7 @@ define([ var isOpened = filesOp.comparePath(path, currentPath); var $unsortedElement = createTreeElement(UNSORTED_NAME, $icon, [UNSORTED], false, true, false, isOpened); $unsortedElement.addClass('root'); - var $unsortedList = $('
      ', { id: 'unsortedTree' }).append($unsortedElement); + var $unsortedList = $('
        ', { id: 'unsortedTree', 'class': 'category2' }).append($unsortedElement); $container.append($unsortedList); }; @@ -1361,7 +1379,7 @@ define([ var isOpened = filesOp.comparePath(path, currentPath); var $element = createTreeElement(TEMPLATE_NAME, $icon, [TEMPLATE], false, true, false, isOpened); $element.addClass('root'); - var $list = $('
          ', { id: 'templateTree' }).append($element); + var $list = $('
            ', { id: 'templateTree', 'class': 'category2' }).append($element); $container.append($list); }; @@ -1370,7 +1388,19 @@ define([ var isOpened = filesOp.comparePath(path, currentPath); var $allfilesElement = createTreeElement(FILES_DATA_NAME, $icon, [FILES_DATA], false, false, false, isOpened); $allfilesElement.addClass('root'); - var $allfilesList = $('
              ', { id: 'allfilesTree' }).append($allfilesElement); + var $allfilesList = $('
                ', { id: 'allfilesTree', 'class': 'category2' }).append($allfilesElement); + $container.append($allfilesList); + }; + + var createAnonFiles = function ($container, path, anonUser) { + var $icon = $unsortedIcon.clone(); + var isOpened = filesOp.comparePath(path, currentPath); + var $allfilesElement = createTreeElement(ANON_NAME, $icon, [ANON], false, false, false, isOpened); + $allfilesElement.addClass('root'); + var $allfilesList = $('
                  ', { id: 'anonTree', 'class': 'category2' }).append($allfilesElement); + if (anonUser) { + $allfilesList.removeClass('category2'); + } $container.append($allfilesList); }; @@ -1390,16 +1420,21 @@ define([ $trashElement.contextmenu(openTrashTreeContextMenu); if (isOpened) { $trash.addClass('active'); } - var $trashList = $('
                    ', { id: 'trashTree' }).append($trashElement); + var $trashList = $('
                      ', { id: 'trashTree', 'class': 'category2' }).append($trashElement); $container.append($trashList); }; var resetTree = module.resetTree = function () { $tree.html(''); + if (!APP.loggedIn) { + createAnonFiles($tree, [ANON], true); + return; + } createTree($tree, [ROOT]); if (!isWorkgroup()) { createUnsorted($tree, [UNSORTED]); createTemplate($tree, [TEMPLATE]); + createAnonFiles($tree, [ANON]); createAllFiles($tree, [FILES_DATA]); } createTrash($tree, [TRASH]); @@ -1646,16 +1681,19 @@ define([ onRefresh.to = window.setTimeout(refresh, 500); } }; - files.on('change', [], function (o, n, p) { + proxy.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))) { + if (path[0] !== 'drive') { return false; } + path = path.slice(1); + var cPath = filesOp.isPathInAnon(currentPath) ? [FILES_DATA] : currentPath.slice(); + if ((filesOp.isPathInUnsorted(cPath) && filesOp.isPathInUnsorted(path)) || + (filesOp.isPathInTemplate(cPath) && filesOp.isPathInTemplate(path)) || + (path.length >= cPath.length && filesOp.isSubpath(path, cPath)) || + (filesOp.isPathInTrash(cPath) && filesOp.isPathInTrash(path))) { // Reload after a few ms to make sure all the change events have been received onRefresh.refresh(); } else if (path.length && path[0] === FILES_DATA) { - if (filesOp.isPathInHrefArray(currentPath)) { + if (filesOp.isPathInHrefArray(cPath) || filesOp.isPathInAnon(path)) { onRefresh.refresh(); } else { refreshFilesData(); @@ -1791,8 +1829,9 @@ define([ module.files = proxy; if (JSON.stringify(proxy) === '{}') { var store = Cryptpad.getStore(true); + var drive = proxy.drive = {}; store.get(Cryptpad.storageKey, function (err, s) { - proxy[FILES_DATA] = s; + drive[FILES_DATA] = s; initLocalStorage(); init(proxy); APP.userList.onChange(); @@ -1800,6 +1839,7 @@ define([ }); return; } + if (!proxy.drive || typeof(proxy.drive) !== 'object') { proxy.drive = {}; } initLocalStorage(); init(proxy); APP.userList.onChange(); From 015e6fc26258c54d9e26d4b1052b11515493e903 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 24 Jan 2017 18:17:23 +0100 Subject: [PATCH 67/88] Make sure we have the same hash in all the tabs when disconnecting --- www/common/cryptpad-common.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 9ae31a238..0de076e17 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -80,7 +80,7 @@ define([ var logout = common.logout = function (cb) { [ - fileHashKey, +// fileHashKey, userHashKey, ].forEach(function (k) { sessionStorage.removeItem(k); @@ -88,6 +88,11 @@ define([ delete localStorage[k]; delete sessionStorage[k]; }); + // Make sure we have an FS_hash in localStorage before reloading all the tabs + // so that we don't end up with tabs using different anon hashes + if (!localStorage[fileHashKey]) { + localStorage[fileHashKey] = common.createRandomHash(); + } if (cb) { cb(); } }; From 373b07ed28913470fa84fe29c556e1e072982a2f Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 25 Jan 2017 10:21:31 +0100 Subject: [PATCH 68/88] Fix lint errors --- www/common/toolbar.js | 14 +++++++------- www/pad/main.js | 5 +++-- www/poll/main.js | 28 ++++++++++++++-------------- www/slide/main.js | 2 +- www/slide/slide.js | 18 +++++++++--------- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/www/common/toolbar.js b/www/common/toolbar.js index c2a74e44c..a118dcf62 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -374,7 +374,7 @@ define([ if (config.displayed.indexOf('useradmin') !== -1) { if (!config.userName || !config.userName.setName || !config.userName.lastName) { throw new Error("You must provide a `userName` object containing `setName` (function) " + - "and `lastName` (object) if you want to display the user admin menu.") + "and `lastName` (object) if you want to display the user admin menu."); } var $displayedName = $('', {'class': USERNAME_CLS}); var accountName = Cryptpad.getStore().getLoginName ? Cryptpad.getStore().getLoginName() : null; @@ -388,7 +388,7 @@ define([ var $userName = $('', {'class': 'userDisplayName'}); if (readOnly !== 1) { // Hide "Display name:" in read only mode - $userName.append(Messages.user_displayName + ': ') + $userName.append(Messages.user_displayName + ': '); } $userName.append($displayedName.clone()); $userAdminContent.append($userName); @@ -429,12 +429,12 @@ define([ if (account) { $button.append($('', {'class': 'account-name'}).text('(' + accountName + ')')); } - var dropdownConfig = { + var dropdownConfigUser = { text: $button.html(), // Button initial text options: options, // Entries displayed in the menu left: true, // Open to the left of the button }; - var $userAdmin = Cryptpad.createDropdown(dropdownConfig); + var $userAdmin = Cryptpad.createDropdown(dropdownConfigUser); $userContainer.append($userAdmin); $userAdmin.find('a.logout').click(function (e) { @@ -569,9 +569,9 @@ define([ return; } - var e = jQuery.Event("keyup"); - e.which = 13; - $titleElement.find('input').trigger(e); + var ev = $.Event("keyup"); + ev.which = 13; + $titleElement.find('input').trigger(ev); /* $titleElement.find('input').hide(); diff --git a/www/pad/main.js b/www/pad/main.js index df80cef19..3998ad915 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -495,8 +495,9 @@ define([ updateMetadata(shjson); var newInner = JSON.parse(shjson); + var newSInner; if (newInner.length > 2) { - var newSInner = stringify(newInner[2]); + newSInner = stringify(newInner[2]); } // build a dom from HJSON, diff, and patch the editor @@ -535,7 +536,7 @@ define([ // Notify only when the content has changed, not when someone has joined/left var oldSInner = stringify(JSON.parse(oldShjson)[2]); - if (newSInner !== oldSInner) { + if (newSInner && newSInner !== oldSInner) { notify(); } }; diff --git a/www/poll/main.js b/www/poll/main.js index 10a25e01d..49835a13a 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -192,6 +192,20 @@ define([ } }; + var unnotify = function () { + if (APP.tabNotification && + typeof(APP.tabNotification.cancel) === 'function') { + APP.tabNotification.cancel(); + } + }; + + var notify = function () { + if (Visible.isSupported() && !Visible.currently()) { + unnotify(); + APP.tabNotification = Notify.tab(1000, 10); + } + }; + /* Any time the realtime object changes, call this function */ var change = function (o, n, path, throttle) { if (path && !Cryptpad.isArray(path)) { @@ -402,20 +416,6 @@ define([ }); }; - var unnotify = function () { - if (APP.tabNotification && - typeof(APP.tabNotification.cancel) === 'function') { - APP.tabNotification.cancel(); - } - }; - - var notify = function () { - if (Visible.isSupported() && !Visible.currently()) { - unnotify(); - APP.tabNotification = Notify.tab(1000, 10); - } - }; - var userData = APP.userData = {}; // List of pretty names for all users (mapped with their ID) var userList; // List of users still connected to the channel (server IDs) var addToUserData = function(data) { diff --git a/www/slide/main.js b/www/slide/main.js index 4de77868e..e8ef4651b 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -766,7 +766,7 @@ define([ } Slide.update(remoteDoc); - if (oldDoc !== newDoc) { + if (oldDoc !== remoteDoc) { notify(); } }; diff --git a/www/slide/slide.js b/www/slide/slide.js index 501415cad..5fc279d59 100644 --- a/www/slide/slide.js +++ b/www/slide/slide.js @@ -212,19 +212,19 @@ define([ }, 1000); }); $modal.find('#button_exit').click(function (e) { - var e = jQuery.Event("keyup"); - e.which = 27; - $modal.trigger(e); + var ev = $.Event("keyup"); + ev.which = 27; + $modal.trigger(ev); }); $modal.find('#button_left').click(function (e) { - var e = jQuery.Event("keyup"); - e.which = 37; - $modal.trigger(e); + var ev = $.Event("keyup"); + ev.which = 37; + $modal.trigger(ev); }); $modal.find('#button_right').click(function (e) { - var e = jQuery.Event("keyup"); - e.which = 39; - $modal.trigger(e); + var ev = $.Event("keyup"); + ev.which = 39; + $modal.trigger(ev); }); $(ifrw).on('keyup', function (e) { From f42665ba49187ab7da014ee3d4c634b1c1dff605 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 25 Jan 2017 14:26:28 +0100 Subject: [PATCH 69/88] Remove the unowned pads category --- customize.dist/translations/messages.fr.js | 2 +- customize.dist/translations/messages.js | 2 +- www/common/cryptpad-common.js | 6 +- www/common/fileObject.js | 67 ++++++++------- www/drive/file.css | 4 + www/drive/main.js | 95 ++++++++++------------ 6 files changed, 89 insertions(+), 87 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 4ac605f5a..8f761c5bb 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -202,7 +202,7 @@ define(function () { out.fm_noname = "Document sans titre"; out.fm_emptyTrashDialog = "Êtes-vous sûr de vouloir vider la corbeille ?"; out.fm_removeSeveralPermanentlyDialog = "Êtes-vous sûr de vouloir supprimer ces {0} éléments de manière permanente ?"; - out.fm_removePermanentlyDialog = "Êtes-vous sûr de vouloir supprimer {0} de manière permanente ?"; + out.fm_removePermanentlyDialog = "Êtes-vous sûr de vouloir supprimer cet élément de manière permanente ?"; out.fm_restoreDialog = "Êtes-vous sûr de vouloir restaurer {0} à son emplacement précédent ?"; out.fm_removeSeveralDialog = "Êtes-vous sûr de vouloir déplacer ces {0} éléments vers la corbeille ?"; out.fm_removeDialog = "Êtes-vous sûr de vouloir déplacer {0} vers la corbeille ?"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 133f41d6b..dff57764f 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -199,7 +199,7 @@ define(function () { out.fm_noname = "Untitled Document"; out.fm_emptyTrashDialog = "Are you sure you want to empty the trash?"; out.fm_removeSeveralPermanentlyDialog = "Are you sure you want to remove these {0} elements from the trash permanently?"; - out.fm_removePermanentlyDialog = "Are you sure you want to remove {0} permanently?"; + out.fm_removePermanentlyDialog = "Are you sure you want to remove that element permanently?"; out.fm_removeSeveralDialog = "Are you sure you want to move these {0} elements to the trash?"; out.fm_removeDialog = "Are you sure you want to move {0} to the trash?"; out.fm_restoreDialog = "Are you sure you want to restore {0} to its previous location?"; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 410b12136..b49210517 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -407,7 +407,7 @@ define([ // STORAGE var setPadAttribute = common.setPadAttribute = function (attr, value, cb, legacy) { - getStore(legacy).set([getHash(), attr].join('.'), value, function (err, data) { + getStore(legacy).setDrive([getHash(), attr].join('.'), value, function (err, data) { cb(err, data); }); }; @@ -422,7 +422,7 @@ define([ // STORAGE var getPadAttribute = common.getPadAttribute = function (attr, cb, legacy) { - getStore(legacy).get([getHash(), attr].join('.'), function (err, data) { + getStore(legacy).getDrive([getHash(), attr].join('.'), function (err, data) { cb(err, data); }); }; @@ -577,7 +577,7 @@ define([ if (!contains) { var data = makePad(href, name); if (common.initialPath) { - data.owner = 1; // TODO use owner id here? + data.owner = getStore().getLoginName(); // TODO use owner id here? } renamed.push(data); if (USE_FS_STORE && common.initialPath && typeof(getStore().addPad) === "function") { diff --git a/www/common/fileObject.js b/www/common/fileObject.js index 4137a0f84..1d16cef93 100644 --- a/www/common/fileObject.js +++ b/www/common/fileObject.js @@ -8,7 +8,6 @@ define([ var ROOT = "root"; var UNSORTED = "unsorted"; var FILES_DATA = "filesData"; - var ANON = "anon"; // virtual path var TRASH = "trash"; var TEMPLATE = "template"; var NEW_FOLDER_NAME = Messages.fm_newFolder; @@ -58,9 +57,6 @@ define([ var isPathInTrash = exp.isPathInTrash = function (path) { return path[0] && path[0] === TRASH; }; - var isPathInAnon = exp.isPathInAnon = function (path) { - return path[0] && path[0] === ANON; - }; var isPathInFilesData = exp.isPathInFilesData = function (path) { return path[0] && path[0] === FILES_DATA; @@ -231,13 +227,6 @@ define([ return ret; }; - /*var getAnonFiles = exp.getAnonFiles = function () { - if (!files[ANON]) { - files[ANON] = []; - } - return files[ANON].slice(); - };*///TODO - var removeFileFromRoot = function (root, href) { if (isFile(root)) { return; } for (var e in root) { @@ -256,6 +245,17 @@ define([ return path[0] === TRASH && path.length === 4; }; + var removePadAttribute = function (f) { + Object.keys(files).forEach(function (key) { + var hash = f.indexOf('#') !== -1 ? f.slice(f.indexOf('#') + 1) : null; + if (hash && key.indexOf(hash) === 0) { + debug("Deleting pad attribute in the realtime object"); + files[key] = undefined; + delete files[key]; + } + }); + }; + var checkDeletedFiles = function () { // Nothing in FILES_DATA for workgroups if (workgroup) { return; } @@ -279,14 +279,7 @@ define([ if (idx !== -1) { debug("Removing", f, "from filesData"); files[FILES_DATA].splice(idx, 1); - Object.keys(files).forEach(function (key) { - var hash = f.href.indexOf('#') !== -1 ? f.href.slice(f.href.indexOf('#') + 1) : null; - if (hash && key.indexOf(hash) === 0) { - debug("Deleting pad attribute in the realtime object"); - files[key] = undefined; - delete files[key]; - } - }); + removePadAttribute(f.href); } }); }; @@ -297,7 +290,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) { //TODO || === TEMPLATE + } else if (path[0] === UNSORTED || path[0] === TEMPLATE) { parentEl.splice(key, 1); } else { parentEl[key] = undefined; @@ -375,7 +368,6 @@ 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); @@ -409,7 +401,7 @@ define([ if (isPathInHrefArray(newParentPath)) { if (isFolder(element)) { - log(Messages.fo_moveUnsortedError); //TODO or template + log(Messages.fo_moveUnsortedError); return; } else { if (elementPath[0] === newParentPath[0]) { return; } @@ -595,6 +587,28 @@ define([ if(cb) { cb(); } }; + var deleteFileData = exp.deleteFileData = function (href, cb) { + if (workgroup) { return; } + + var toRemove = []; + files[FILES_DATA].forEach(function (arr) { + var f = arr.href; + if (f === href) { + toRemove.push(arr); + } + }); + toRemove.forEach(function (f) { + var idx = files[FILES_DATA].indexOf(f); + if (idx !== -1) { + debug("Removing", f, "from filesData"); + files[FILES_DATA].splice(idx, 1); + // Remove the "padAttributes" stored in the realtime object for that pad + removePadAttribute(f.href); + } + }); + + if(cb) { cb(); } + }; var renameElement = exp.renameElement = function (path, newName, cb) { if (path.length <= 1) { @@ -791,9 +805,6 @@ define([ us.splice(idx, 1); }); }; - /*var fixAnon = function () { - if (!$.isArray(files[ANON])) { debug("ANON was not an array"); files[FILES_DATA] = []; } - };*/// TODO var fixFilesData = function () { if (!$.isArray(files[FILES_DATA])) { debug("FILES_DATA was not an array"); files[FILES_DATA] = []; } var fd = files[FILES_DATA]; @@ -809,8 +820,7 @@ define([ toClean.push(el); return; } - if (el.owner - && rootFiles.indexOf(el.href) === -1 + if (rootFiles.indexOf(el.href) === -1 && unsortedFiles.indexOf(el.href) === -1 && templateFiles.indexOf(el.href) === -1 && trashFiles.indexOf(el.href) === -1) { @@ -818,9 +828,6 @@ define([ files[UNSORTED].push(el.href); return; } - /*if (!el.owner && anonFiles.indexOf(el.href) === -1) { - files[ANON].push(el.href); - }*/// TODO }); toClean.forEach(function (el) { var idx = fd.indexOf(el); diff --git a/www/drive/file.css b/www/drive/file.css index d6c1f2274..c6ee63658 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -247,6 +247,10 @@ li { text-align: center; } +#content .grid li .fa.listonly { + display: none; +} + #content .list li { display: flex; flex-flow: row; diff --git a/www/drive/main.js b/www/drive/main.js index d1d89ee35..42d8a3fbc 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -45,10 +45,6 @@ define([ var TRASH = "trash"; var TRASH_NAME = Messages.fm_trashName; - // anon: Virtual path, not stored in the object but extracted from FILES_DATA - var ANON = "anon"; - var ANON_NAME = Messages.fm_anonName || 'Anon pads......'; - var LOCALSTORAGE_LAST = "cryptpad-file-lastOpened"; var LOCALSTORAGE_OPENED = "cryptpad-file-openedFolders"; var LOCALSTORAGE_VIEWMODE = "cryptpad-file-viewMode"; @@ -173,7 +169,7 @@ define([ // FILE MANAGER // _WORKGROUP_ and other people drive : display Documents as main page - var currentPath = module.currentPath = APP.loggedIn ? isOwnDrive() ? getLastOpenedFolder() : [ROOT] : [ANON]; + var currentPath = module.currentPath = isOwnDrive() ? getLastOpenedFolder() : [ROOT]; var lastSelectTime; var selectedElement; @@ -192,6 +188,11 @@ define([ var $folderOpenedIcon = $('', {"class": "fa fa-folder-open folder", style:"color:#FEDE8B;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;"}); var $folderOpenedEmptyIcon = $folderOpenedIcon.clone(); var $fileIcon = $('', {"class": "fa fa-file-text-o file"}); + var $padIcon = $('', {"class": "fa fa-file-word-o file"}); + var $codeIcon = $('', {"class": "fa fa-file-code-o file"}); + var $slideIcon = $('', {"class": "fa fa-file-powerpoint-o file"}); + var $pollIcon = $('', {"class": "fa fa-calendar file"}); + var $anonIcon = $('', {"class": "fa fa-user-secret file listonly"}); var $upIcon = $('', {"class": "fa fa-arrow-circle-up"}); var $unsortedIcon = $('', {"class": "fa fa-files-o"}); var $templateIcon = $('', {"class": "fa fa-cubes"}); @@ -645,6 +646,22 @@ define([ $span.append($name).append($subfolders).append($files); }; + var getFileIcon = function (href) { + var $icon = $fileIcon.clone(); + var data = filesOp.getFileData(href); + if (!data) { return $icon; } + + if (href.indexOf('/pad/') !== -1) { $icon = $padIcon.clone() } + else if (href.indexOf('/code/') !== -1) { $icon = $codeIcon.clone() } + else if (href.indexOf('/slide/') !== -1) { $icon = $slideIcon.clone() } + else if (href.indexOf('/poll/') !== -1) { $icon = $pollIcon.clone() } + + if (!data.owner) { + $icon = $('').append($anonIcon.clone()).append($icon); + } + return $icon; + }; + // Create the "li" element corresponding to the file/folder located in "path" var createElement = function (path, elPath, root, isFolder) { // Forbid drag&drop inside the trash @@ -660,7 +677,7 @@ define([ } var element = filesOp.findElement(files, newPath); - var $icon = $fileIcon.clone(); + var $icon = !isFolder ? getFileIcon(element) : undefined; var spanClass = 'file-element element'; var liClass = 'file-item'; if (isFolder) { @@ -732,7 +749,6 @@ define([ 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 === ANON && path.length === 1) { name = ANON_NAME; } else if (name === FILES_DATA && path.length === 1) { name = FILES_DATA_NAME; } else if (filesOp.isPathInTrash(path)) { name = getTrashTitle(path); } var $title = $('

                      ').text(name); @@ -844,7 +860,7 @@ define([ options.push({tag: 'hr'}); } AppConfig.availablePadTypes.forEach(function (type) { - var path = filesOp.comparePath(currentPath, [ANON]) ? '' : '/#?path=' + encodeURIComponent(currentPath); + var path = '/#?path=' + encodeURIComponent(currentPath); options.push({ tag: 'a', attributes: { @@ -1086,7 +1102,7 @@ define([ //return; } var idx = files[rootName].indexOf(href); - var $icon = $fileIcon.clone(); + var $icon = getFileIcon(href); var $name = $('', { 'class': 'file-element element' }); addFileData(href, file.title, $name, false); var $element = $('
                    • ', { @@ -1108,18 +1124,16 @@ define([ }); }; - var displayAllFiles = function ($container, anon) { + var displayAllFiles = function ($container) { var allfiles = files[FILES_DATA]; if (allfiles.length === 0) { return; } var $fileHeader = getFileListHeader(false); $container.append($fileHeader); - var keys = allfiles.filter(function (el) { - return anon && !el.owner || !anon && el.owner; - }); + var keys = allfiles; var sortedFiles = sortElements(false, [FILES_DATA], keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !getSortFileDesc(), false, true); sortedFiles.forEach(function (file) { - var $icon = $fileIcon.clone(); + var $icon = getFileIcon(file.href); var $name = $('', { 'class': 'file-element element' }); addFileData(file.href, file.title, $name, false); var $element = $('
                    • ').append($icon).append($name).dblclick(function () { @@ -1181,7 +1195,7 @@ define([ if (!appStatus.isReady && !force) { return; } // Only Trash and Root are available in not-owned files manager if (isWorkgroup() && !filesOp.isPathInTrash(path) && !filesOp.isPathInRoot(path)) { - log("TRANSLATE or REMOVE: Unable to open the selected category, displaying root"); //TODO translate + log("Unable to open the selected category, displaying root"); //TODO translate currentPath = [ROOT]; displayDirectory(currentPath); return; @@ -1197,10 +1211,9 @@ define([ var isUnsorted = filesOp.comparePath(path, [UNSORTED]); var isTemplate = filesOp.comparePath(path, [TEMPLATE]); var isAllFiles = filesOp.comparePath(path, [FILES_DATA]); - var isAnon = filesOp.comparePath(path, [ANON]); var root = filesOp.findElement(files, path); - if (typeof(root) === "undefined" && !isAnon) { + if (typeof(root) === "undefined") { log(Messages.fm_unknownFolderError); debug("Unable to locate the selected directory: ", path); var parentPath = path.slice(); @@ -1236,12 +1249,9 @@ define([ var $fileHeader = getFileListHeader(true); if (isUnsorted || isTemplate) { - // 3rd parameter is "draggable": anon pads shouldn't be draggable - displayHrefArray($list, path[0], !isAnon); + displayHrefArray($list, path[0]); } else if (isAllFiles) { - displayAllFiles($list, false); - } else if (isAnon) { - displayAllFiles($list, true); + displayAllFiles($list); } else if (isTrashRoot) { displayTrashRoot($list, $folderHeader, $fileHeader); } else { @@ -1392,18 +1402,6 @@ define([ $container.append($allfilesList); }; - var createAnonFiles = function ($container, path, anonUser) { - var $icon = $unsortedIcon.clone(); - var isOpened = filesOp.comparePath(path, currentPath); - var $allfilesElement = createTreeElement(ANON_NAME, $icon, [ANON], false, false, false, isOpened); - $allfilesElement.addClass('root'); - var $allfilesList = $('
                        ', { id: 'anonTree', 'class': 'category2' }).append($allfilesElement); - if (anonUser) { - $allfilesList.removeClass('category2'); - } - $container.append($allfilesList); - }; - var createTrash = function ($container, path) { var $icon = filesOp.isFolderEmpty(files[TRASH]) ? $trashEmptyIcon.clone() : $trashIcon.clone(); var isOpened = filesOp.comparePath(path, currentPath); @@ -1426,15 +1424,10 @@ define([ var resetTree = module.resetTree = function () { $tree.html(''); - if (!APP.loggedIn) { - createAnonFiles($tree, [ANON], true); - return; - } createTree($tree, [ROOT]); if (!isWorkgroup()) { createUnsorted($tree, [UNSORTED]); createTemplate($tree, [TEMPLATE]); - createAnonFiles($tree, [ANON]); createAllFiles($tree, [FILES_DATA]); } createTrash($tree, [TRASH]); @@ -1636,26 +1629,23 @@ define([ var $selected = $iframe.find('.selected'); if (!$selected.length) { return; } var paths = []; + var isTrash = filesOp.isPathInTrash(currentPath); $selected.each(function (idx, elmt) { if (!$(elmt).data('path')) { return; } paths.push($(elmt).data('path')); }); - // If we are in the trash or if we are holding the "shift" key, delete permanently, - // else move to trash - if (filesOp.isPathInTrash(currentPath) || e.shiftKey) { - var cb = filesOp.removeFromTrash; - if (!filesOp.isPathInTrash(currentPath)) { - // If we are not in the trash, we just have to remove the key from root/unsorted - cb = filesOp.deletePathPermanently; + // If we are in the trash or anon pad or if we are holding the "shift" key, delete permanently, + if (isTrash || e.shiftKey) { + var cb = filesOp.removeFromTrash; // We're in the trash + if (!isTrash) { + cb = filesOp.deletePathPermanently; // We're in root/unsorted/template } - // If we are already in the trash, delete the elements permanently + var msg = Messages._getKey("fm_removeSeveralPermanentlyDialog", [paths.length]); - if (paths.length === 1) { // If we delete only one element, display its name in the popup - var path = paths[0]; - var element = filesOp.findElement(files, path); - var name = filesOp.isInTrashRoot(path) ? path[1] : (filesOp.isPathInHrefArray(path) ? filesOp.getTitle(element) : path[path.length - 1]); - msg = Messages._getKey("fm_removePermanentlyDialog", [name]); + if (paths.length === 1) { + msg = Messages.fm_removePermanentlyDialog; } + Cryptpad.confirm(msg, function(res) { if (!res) { return; } paths.forEach(function(p) { @@ -1665,6 +1655,7 @@ define([ }); return; } + // else move to trash moveElements(paths, [TRASH], false, refresh); } }); From 11f0a9ae5fa9e21e4beb998a9d129c8a92a1a64e Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 25 Jan 2017 15:33:22 +0100 Subject: [PATCH 70/88] Revert the changes adding anonymous pads --- npm-debug.log | 49 ----------------------------------- www/common/cryptpad-common.js | 3 --- www/common/fileObject.js | 16 ++---------- www/drive/main.js | 11 +++----- 4 files changed, 5 insertions(+), 74 deletions(-) delete mode 100644 npm-debug.log diff --git a/npm-debug.log b/npm-debug.log deleted file mode 100644 index 69610cda2..000000000 --- a/npm-debug.log +++ /dev/null @@ -1,49 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ '/home/yflory/.nvm/versions/node/v7.0.0/bin/node', -1 verbose cli '/home/yflory/.nvm/versions/node/v7.0.0/bin/npm', -1 verbose cli 'run', -1 verbose cli 'lint' ] -2 info using npm@3.10.8 -3 info using node@v7.0.0 -4 verbose run-script [ 'prelint', 'lint', 'postlint' ] -5 info lifecycle cryptpad@0.1.0~prelint: cryptpad@0.1.0 -6 silly lifecycle cryptpad@0.1.0~prelint: no script for prelint, continuing -7 info lifecycle cryptpad@0.1.0~lint: cryptpad@0.1.0 -8 verbose lifecycle cryptpad@0.1.0~lint: unsafe-perm in lifecycle true -9 verbose lifecycle cryptpad@0.1.0~lint: PATH: /home/yflory/.nvm/versions/node/v7.0.0/lib/node_modules/npm/bin/node-gyp-bin:/home/yflory/XWiki/cryptpad/node_modules/.bin:/home/yflory/.nvm/versions/node/v7.0.0/bin:/usr/lib/jvm/java-8-openjdk-amd64/bin:/usr/local/apache-maven/apache-maven-3.3.9/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/yflory/android-sdk-linux/tools -10 verbose lifecycle cryptpad@0.1.0~lint: CWD: /home/yflory/XWiki/cryptpad -11 silly lifecycle cryptpad@0.1.0~lint: Args: [ '-c', -11 silly lifecycle 'jshint --config .jshintrc --exclude-path .jshintignore .' ] -12 silly lifecycle cryptpad@0.1.0~lint: Returned: code: 2 signal: null -13 info lifecycle cryptpad@0.1.0~lint: Failed to exec lint script -14 verbose stack Error: cryptpad@0.1.0 lint: `jshint --config .jshintrc --exclude-path .jshintignore .` -14 verbose stack Exit status 2 -14 verbose stack at EventEmitter. (/home/yflory/.nvm/versions/node/v7.0.0/lib/node_modules/npm/lib/utils/lifecycle.js:255:16) -14 verbose stack at emitTwo (events.js:106:13) -14 verbose stack at EventEmitter.emit (events.js:191:7) -14 verbose stack at ChildProcess. (/home/yflory/.nvm/versions/node/v7.0.0/lib/node_modules/npm/lib/utils/spawn.js:40:14) -14 verbose stack at emitTwo (events.js:106:13) -14 verbose stack at ChildProcess.emit (events.js:191:7) -14 verbose stack at maybeClose (internal/child_process.js:877:16) -14 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:226:5) -15 verbose pkgid cryptpad@0.1.0 -16 verbose cwd /home/yflory/XWiki/cryptpad -17 error Linux 4.4.0-59-generic -18 error argv "/home/yflory/.nvm/versions/node/v7.0.0/bin/node" "/home/yflory/.nvm/versions/node/v7.0.0/bin/npm" "run" "lint" -19 error node v7.0.0 -20 error npm v3.10.8 -21 error code ELIFECYCLE -22 error cryptpad@0.1.0 lint: `jshint --config .jshintrc --exclude-path .jshintignore .` -22 error Exit status 2 -23 error Failed at the cryptpad@0.1.0 lint script 'jshint --config .jshintrc --exclude-path .jshintignore .'. -23 error Make sure you have the latest version of node.js and npm installed. -23 error If you do, this is most likely a problem with the cryptpad package, -23 error not with npm itself. -23 error Tell the author that this fails on your system: -23 error jshint --config .jshintrc --exclude-path .jshintignore . -23 error You can get information on how to open an issue for this project with: -23 error npm bugs cryptpad -23 error Or if that isn't available, you can get their info via: -23 error npm owner ls cryptpad -23 error There is likely additional logging output above. -24 verbose exit [ 1, true ] diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index b49210517..4c68dcd03 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -576,9 +576,6 @@ define([ if (!contains) { var data = makePad(href, name); - if (common.initialPath) { - data.owner = getStore().getLoginName(); // TODO use owner id here? - } renamed.push(data); if (USE_FS_STORE && common.initialPath && typeof(getStore().addPad) === "function") { getStore().addPad(href, common.initialPath, name); diff --git a/www/common/fileObject.js b/www/common/fileObject.js index 1d16cef93..f19bdc2d4 100644 --- a/www/common/fileObject.js +++ b/www/common/fileObject.js @@ -713,11 +713,6 @@ define([ }); }; - var isAnonFile = exp.isAnonFile = function (file) { - var data = getFileData(file); - return !data.owner; - }; - var fixFiles = exp.fixFiles = function () { // Explore the tree and check that everything is correct: // * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects @@ -739,11 +734,6 @@ define([ debug("An element in ROOT was not a folder nor a file. ", element[el]); element[el] = undefined; delete element[el]; - } else if (isFile(element[el])) { - if (isAnonFile(element[el])) { - debug("An element in ROOT was an anonymous file. ", element[el]); - delete element[el]; - } } else if (isFolder(element[el])) { fixRoot(element[el]); } @@ -756,7 +746,6 @@ define([ var addToClean = function (obj, idx) { if (typeof(obj) !== "object") { toClean.push(idx); return; } if (!isFile(obj.element) && !isFolder(obj.element)) { toClean.push(idx); return; } - if (isFile(obj.element) && isAnonFile(obj.element)) { toClean.push(idx); return; } if (!$.isArray(obj.path)) { toClean.push(idx); return; } }; for (var el in tr) { @@ -781,7 +770,7 @@ define([ var templateFiles = getTemplateFiles(); var toClean = []; us.forEach(function (el, idx) { - if (!isFile(el) || rootFiles.indexOf(el) !== -1 || templateFiles.indexOf(el) !== -1 || isAnonFile(el)) { + if (!isFile(el) || rootFiles.indexOf(el) !== -1 || templateFiles.indexOf(el) !== -1) { toClean.push(idx); } }); @@ -797,7 +786,7 @@ define([ var unsortedFiles = getUnsortedFiles(); var toClean = []; us.forEach(function (el, idx) { - if (!isFile(el) || rootFiles.indexOf(el) !== -1 || unsortedFiles.indexOf(el) !== -1 || isAnonFile(el)) { + if (!isFile(el) || rootFiles.indexOf(el) !== -1 || unsortedFiles.indexOf(el) !== -1) { toClean.push(idx); } }); @@ -812,7 +801,6 @@ define([ var unsortedFiles = getUnsortedFiles(); var templateFiles = getTemplateFiles(); var trashFiles = getTrashFiles(); - //var anonFiles = getAnonFiles(); var toClean = []; fd.forEach(function (el, idx) { if (typeof(el) !== "object") { diff --git a/www/drive/main.js b/www/drive/main.js index 42d8a3fbc..6b7fe7849 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -648,17 +648,12 @@ define([ var getFileIcon = function (href) { var $icon = $fileIcon.clone(); - var data = filesOp.getFileData(href); - if (!data) { return $icon; } if (href.indexOf('/pad/') !== -1) { $icon = $padIcon.clone() } else if (href.indexOf('/code/') !== -1) { $icon = $codeIcon.clone() } else if (href.indexOf('/slide/') !== -1) { $icon = $slideIcon.clone() } else if (href.indexOf('/poll/') !== -1) { $icon = $pollIcon.clone() } - if (!data.owner) { - $icon = $('').append($anonIcon.clone()).append($icon); - } return $icon; }; @@ -1249,7 +1244,7 @@ define([ var $fileHeader = getFileListHeader(true); if (isUnsorted || isTemplate) { - displayHrefArray($list, path[0]); + displayHrefArray($list, path[0], true); } else if (isAllFiles) { displayAllFiles($list); } else if (isTrashRoot) { @@ -1676,7 +1671,7 @@ define([ var path = arguments[2]; if (path[0] !== 'drive') { return false; } path = path.slice(1); - var cPath = filesOp.isPathInAnon(currentPath) ? [FILES_DATA] : currentPath.slice(); + var cPath = currentPath.slice(); if ((filesOp.isPathInUnsorted(cPath) && filesOp.isPathInUnsorted(path)) || (filesOp.isPathInTemplate(cPath) && filesOp.isPathInTemplate(path)) || (path.length >= cPath.length && filesOp.isSubpath(path, cPath)) || @@ -1684,7 +1679,7 @@ define([ // Reload after a few ms to make sure all the change events have been received onRefresh.refresh(); } else if (path.length && path[0] === FILES_DATA) { - if (filesOp.isPathInHrefArray(cPath) || filesOp.isPathInAnon(path)) { + if (filesOp.isPathInHrefArray(cPath)) { onRefresh.refresh(); } else { refreshFilesData(); From 8c7305bf1baf10973ad104fec491a3e1da207b1d Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 25 Jan 2017 16:21:46 +0100 Subject: [PATCH 71/88] Use less to write the drive stylesheet --- www/drive/file.css | 505 +++++++++++++++++++----------------------- www/drive/file.less | 363 ++++++++++++++++++++++++++++++ www/drive/oldfile.css | 378 +++++++++++++++++++++++++++++++ 3 files changed, 964 insertions(+), 282 deletions(-) create mode 100644 www/drive/file.less create mode 100644 www/drive/oldfile.css diff --git a/www/drive/file.css b/www/drive/file.css index c6ee63658..3fc4967fe 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -1,378 +1,319 @@ /* PAGE */ - -html, body { - width: 100%; - height: 100%; - box-sizing: border-box; - padding: 0; - margin: 0; - position: relative; - font-size: 20px; - overflow: auto; -} - +html, body { - display: flex; - flex-flow: column; + width: 100%; + height: 100%; + box-sizing: border-box; + padding: 0; + margin: 0; + position: relative; + font-size: 20px; + overflow: auto; +} +body { + display: flex; + flex-flow: column; } - .app-container { - flex: 1; - overflow: auto; - width: 100%; - display: flex; - flex-flow: row; + flex: 1; + overflow: auto; + width: 100%; + display: flex; + flex-flow: row; } - .fa { - /*min-width: 17px;*/ - margin-right: 3px; - font-family: FontAwesome; + /*min-width: 17px;*/ + margin-right: 3px; + font-family: FontAwesome; } - ul { - list-style: none; - padding-left: 10px; + list-style: none; + padding-left: 10px; } - li { - padding: 0px 5px; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.folder, .file { - margin-right: 5px; -} - + padding: 0px 5px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.folder, +.file { + margin-right: 5px; +} .contextMenu { - display: none; - position: absolute; + display: none; + position: absolute; } - .droppable { - background-color: #FE9A2E; - color: #222; + background-color: #FE9A2E; + color: #222; } - .selected { - border: 1px dotted #bbb; - background: #666; - color: #eee; - margin: -1px; + border: 1px dotted #bbb; + background: #666; + color: #eee; + margin: -1px; } - /* TREE */ - - #tree { - border-right: 1px solid #ccc; - box-sizing: border-box; - background: white; - overflow: auto; - resize: horizontal; - width: 350px; - white-space: nowrap; - max-width: 500px; - min-width: 200px; - padding: 10px 0px; -} - -#tree li { - cursor: auto; + border-right: 1px solid #ccc; + box-sizing: border-box; + background: #eee; + overflow: auto; + resize: horizontal; + width: 250px; + white-space: nowrap; + max-width: 500px; + min-width: 200px; + padding: 10px 0px; } - -#tree span.element { - cursor: pointer; +#tree li { + cursor: auto; } - #tree li > span.element:hover { - text-decoration: underline; + text-decoration: underline; +} +#tree li.collapsed ul { + display: none; +} +#tree li input { + width: calc(70%); +} +#tree span.element { + cursor: pointer; } - #tree .active { - text-decoration: underline; + text-decoration: underline; } - #tree .category2 { - margin-top: 2em; + margin-top: 2em; } - #tree .fa.expcol { - margin-left: -10px; - font-size: 14px; - position: absolute; - left: -20px; - top: 9px; - width: auto; - height: 11px; - padding: 0; - margin: 0; - background: white; - z-index: 10; - cursor: default; + margin-left: -10px; + font-size: 14px; + position: absolute; + left: -20px; + top: 9px; + width: auto; + height: 11px; + padding: 0; + margin: 0; + background: white; + z-index: 10; + cursor: default; } #tree .fa.expcol:before { - position:relative; - top: -1px; -} - -#tree li.collapsed ul { - display: none; -} - -#tree li input { - width: calc(100% - 30px); + position: relative; + top: -1px; } - -/* Tree lines */ - #tree ul { - margin: 0px 0px 0px 10px; - list-style: none; + margin: 0px 0px 0px 10px; + list-style: none; } #tree ul li { - position: relative; + position: relative; } #tree ul li:before { - position: absolute; - left: -15px; - top: -0.25em; - content: ''; - display: block; - border-left: 1px solid #888; - height: 1em; - border-bottom: 1px solid #888; - width: 17.5px; + position: absolute; + left: -15px; + top: -0.25em; + content: ''; + display: block; + border-left: 1px solid #888; + height: 1em; + border-bottom: 1px solid #888; + width: 17.5px; } #tree ul li:after { - position: absolute; - left: -15px; - bottom: -7px; - content: ''; - display: block; - border-left: 1px solid #888; - height: 100%; + position: absolute; + left: -15px; + bottom: -7px; + content: ''; + display: block; + border-left: 1px solid #888; + height: 100%; } #tree ul li.root { - margin: 0px 0px 0px -10px; + margin: 0px 0px 0px -10px; } #tree ul li.root:before { - display: none; + display: none; } #tree ul li.root:after { - display: none; + display: none; } #tree ul li:last-child:after { - display: none; + display: none; } - - /* CONTENT */ - #content { - box-sizing: border-box; - background: #eee; - overflow: auto; - flex: 1; - display: flex; - flex-flow: column; -} - + box-sizing: border-box; + background: #eee; + overflow: auto; + flex: 1; + display: flex; + flex-flow: column; +} #content h1 { - padding-left: 10px; - margin-top: 10px; + padding-left: 10px; + margin-top: 10px; } - #content .info-box { - margin: 0px auto; - padding: 5px; - background: #ddddff; - border: 1px solid #bbb; - border-radius: 5px; - margin-bottom: 10px; + 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; + cursor: pointer; + margin-left: 10px; + float: right; } - -.parentFolder { - cursor: pointer; - margin-left: 10px; +#content li:not(.header) * { + pointer-events: none; } - -.parentFolder:hover { - text-decoration: underline; +#content li:not(.header):hover .name { + text-decoration: underline; } - -#folderContent { - padding-right: 10px; - flex: 1; +#content div.grid li { + display: inline-block; + margin: 10px 10px; + width: 140px; + text-align: center; + vertical-align: top; } - -#content li:not(.header) * { - pointer-events: none; -} - -#content li:hover:not(.header) .name { - text-decoration: underline; -} - -#content .grid li { - display: inline-block; - margin: 10px 10px; - width: 140px; - text-align: center; - vertical-align: top; -} - -#content .grid li .name { - width: 100%; -} - -#content .grid li input { - width: 100%; -} - -#content .grid li .fa { - display: block; - margin: auto; - font-size: 40px; - width: auto; - text-align: center; -} - -#content .grid li .fa.listonly { - display: none; +#content div.grid li .name { + width: 100%; +} +#content div.grid li input { + width: 100%; +} +#content div.grid li .fa { + display: block; + margin: auto; + font-size: 40px; + text-align: center; +} +#content div.grid li .fa.listonly { + display: none; +} +#content div.grid .listElement { + display: none; } - #content .list li { - display: flex; - flex-flow: row; - align-items: center; - padding-right: 0px; + display: flex; + flex-flow: row; + align-items: center; + padding-right: 0px; } #content .list li .element { - display: inline-flex; - flex: 1; + display: inline-flex; + flex: 1; } - #content .list li.header { - cursor: default; - color: #008; - margin-top: 10px; + cursor: default; + color: #008; + margin-top: 10px; } #content .list li.header .element span:not(.fa) { - border-right: 1px solid #CCC; - text-align: left; + border-right: 1px solid #CCC; + text-align: left; } #content .list li.header .element span.fa { - float: right; + float: right; } #content .list li.header span.name { - padding-left: 0; + padding-left: 0; } - #content .list .element span { - padding: 0px 10px; - display: inline-block; - overflow: hidden; - white-space: nowrap; - box-sizing: border-box; - padding-right: 0px; - border-right: 10px solid rgba(0, 0, 0, 0); + padding: 0px 10px; + display: inline-block; + overflow: hidden; + white-space: nowrap; + box-sizing: border-box; + padding-right: 0px; + border-right: 10px solid rgba(0, 0, 0, 0); } #content .list .element span.name { - width: 478px; -} -.iframe #content .list .element span.name { - width: 278px; -} -#content .list .header span.name { - width: 500px; -} -.iframe #content .list .header span.name { - width: 300px; + width: 478px; } -#content .list .element span.type, #content .list .element span.atime, #content .list .element span.ctime { - width: 175px; +#content .list .element span.type, +#content .list .element span.atime, +#content .list .element span.ctime { + width: 175px; } #content .list .element span.title { - width: 250px; + width: 250px; + display: inline; } -#content .list .element span.folders { - width: 150px; +@media screen and (max-width: 1200px) { + #content .list .element span.title { + display: none; + } } +#content .list .element span.folders, #content .list .element span.files { - width: 150px; + width: 150px; } -#content div.grid .listElement { - display: none; +#content .list .header span.name { + width: 500px; } -@media screen and (max-width: 1200px) { - #content .list .element span.title { - display: none; - } +.parentFolder { + cursor: pointer; + margin-left: 10px; +} +.parentFolder:hover { + text-decoration: underline; } -@media screen and (min-width: 1201px) { - #content .list .element span.title { - display: inline; - } +#folderContent { + padding-right: 10px; + flex: 1; } - /* Toolbar */ - #driveToolbar { - background: #ccc; - height: 40px; -} - -.newPadContainer { - display: inline-block; - height: 100%; -} - -button.newElement { - border-radius: 0px; - height: 30px; - background: #888; - color: #eee; - font-size: 15px; - border: none; - font-weight: bold; -} - -button.newElement:hover { - box-shadow: 0px 0px 2px #000; -} - - -/* The container
                        - needed to position the dropdown content */ + background: #ddd; + height: 40px; + /* The container
                        - needed to position the dropdown content */ +} +#driveToolbar .newPadContainer { + display: inline-block; + height: 100%; +} +#driveToolbar button.newElement { + border-radius: 2px; + height: 30px; + background: #888; + color: #eee; + font-size: 16px; + border: none; + font-weight: bold; +} +#driveToolbar button.newElement:hover { + box-shadow: 0px 0px 2px #000; +} #driveToolbar .dropdown-bar { - margin: 4px 5px; - position: relative; - display: inline-block; + margin: 4px 5px; + position: relative; + display: inline-block; } #driveToolbar .dropdown-bar.right { - float: right; + float: right; + /* Right-side buttons */ } - -/* Right-side buttons */ #driveToolbar .dropdown-bar.right button { - display: inline-block; + display: inline-block; } #driveToolbar .dropdown-bar.right button.active { - display: none; + display: none; } #driveToolbar .dropdown-bar.right button .fa { - margin-right: 0px; + margin-right: 0px; } -.dropdown-bar-content { - margin-top: -3px; - margin-right: 2px; +#driveToolbar .dropdown-bar-content { + margin-top: -3px; + margin-right: 2px; } diff --git a/www/drive/file.less b/www/drive/file.less new file mode 100644 index 000000000..b1c2ca558 --- /dev/null +++ b/www/drive/file.less @@ -0,0 +1,363 @@ +/* PAGE */ + +html, body { + width: 100%; + height: 100%; + box-sizing: border-box; + padding: 0; + margin: 0; + position: relative; + font-size: 20px; + overflow: auto; +} + +body { + display: flex; + flex-flow: column; +} + +.app-container { + flex: 1; + overflow: auto; + width: 100%; + display: flex; + flex-flow: row; +} + +.fa { + /*min-width: 17px;*/ + margin-right: 3px; + font-family: FontAwesome; +} + +ul { + list-style: none; + padding-left: 10px; +} + +li { + padding: 0px 5px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.folder, .file { + margin-right: 5px; +} + +.contextMenu { + display: none; + position: absolute; +} + +.droppable { + background-color: #FE9A2E; + color: #222; +} + +.selected { + border: 1px dotted #bbb; + background: #666; + color: #eee; + margin: -1px; +} + +/* TREE */ + + +#tree { + border-right: 1px solid #ccc; + box-sizing: border-box; + background: #eee; + overflow: auto; + resize: horizontal; + width: 250px; + white-space: nowrap; + max-width: 500px; + min-width: 200px; + padding: 10px 0px; + li { + cursor: auto; + &> span.element:hover { + text-decoration: underline; + } + &.collapsed ul { + display: none; + } + input { + width: calc(100% - 30px); + } + } + span.element { + cursor: pointer; + } + .active { + text-decoration: underline; + } + .category2 { + margin-top: 2em; + } + .fa.expcol { + margin-left: -10px; + font-size: 14px; + position: absolute; + left: -20px; + top: 9px; + width: auto; + height: 11px; + padding: 0; + margin: 0; + background: white; + z-index: 10; + cursor: default; + &:before { + position:relative; + top: -1px; + } + } + + // Expand/collapse lines + ul { + margin: 0px 0px 0px 10px; + list-style: none; + li { + position: relative; + &:before { + position: absolute; + left: -15px; + top: -0.25em; + content: ''; + display: block; + border-left: 1px solid #888; + height: 1em; + border-bottom: 1px solid #888; + width: 17.5px; + } + &:after { + position: absolute; + left: -15px; + bottom: -7px; + content: ''; + display: block; + border-left: 1px solid #888; + height: 100%; + } + &.root { + margin: 0px 0px 0px -10px; + &:before { + display: none; + } + &:after { + display: none; + } + } + &:last-child:after { + display: none; + } + } + } + +} + +/* CONTENT */ + +#content { + box-sizing: border-box; + background: #eee; + overflow: auto; + flex: 1; + display: flex; + flex-flow: column; + h1 { + padding-left: 10px; + margin-top: 10px; + } + .info-box { + margin: 0px auto; + padding: 5px; + background: #ddddff; + border: 1px solid #bbb; + border-radius: 5px; + margin-bottom: 10px; + span { + cursor: pointer; + margin-left: 10px; + float: right; + } + } + li { + &:not(.header) { + * { + pointer-events: none; + } + &:hover { + .name { + text-decoration: underline; + } + } + } + } + div.grid { + li { + display: inline-block; + margin: 10px 10px; + width: 140px; + text-align: center; + vertical-align: top; + + .name { + width: 100%; + } + input { + width: 100%; + } + .fa { + display: block; + margin: auto; + font-size: 40px; + text-align: center; + &.listonly { + display: none; + } + } + } + .listElement { + display: none; + } + } + + .list { + li { + display: flex; + flex-flow: row; + align-items: center; + padding-right: 0px; + .element { + display: inline-flex; + flex: 1; + } + &.header { + cursor: default; + color: #008; + margin-top: 10px; + .element { + span { + &:not(.fa) { + border-right: 1px solid #CCC; + text-align: left; + } + &.fa { + float: right; + } + } + } + span { + &.name { + padding-left: 0; + } + } + } + } + .element { + span { + padding: 0px 10px; + display: inline-block; + overflow: hidden; + white-space: nowrap; + box-sizing: border-box; + padding-right: 0px; + border-right: 10px solid rgba(0, 0, 0, 0); + &.name { + width: 478px; + } + &.type, &.atime, &.ctime { + width: 175px; + } + &.title { + width: 250px; + display: inline; + @media screen and (max-width: 1200px) { + display: none; + } + } + &.folders, &.files { + width: 150px; + } + } + } + .header { + span { + &.name { + width: 500px; + } + } + } + } +} + +.parentFolder { + cursor: pointer; + margin-left: 10px; + &:hover { + text-decoration: underline; + } +} + +#folderContent { + padding-right: 10px; + flex: 1; +} + + +/* Toolbar */ + +#driveToolbar { + background: #ddd; + height: 40px; + .newPadContainer { + display: inline-block; + height: 100%; + } + + button.newElement { + border-radius: 2px; + height: 30px; + background: #888; + color: #eee; + font-size: 16px; + border: none; + font-weight: bold; + &:hover { + box-shadow: 0px 0px 2px #000; + } + } + /* The container
                        - needed to position the dropdown content */ + .dropdown-bar { + margin: 4px 5px; + position: relative; + display: inline-block; + &.right { + float: right; + /* Right-side buttons */ + button { + display: inline-block; + &.active { + display: none; + } + .fa { + margin-right: 0px; + } + } + } + } + .dropdown-bar-content { + margin-top: -3px; + margin-right: 2px; + } +} + + + diff --git a/www/drive/oldfile.css b/www/drive/oldfile.css new file mode 100644 index 000000000..8364886b8 --- /dev/null +++ b/www/drive/oldfile.css @@ -0,0 +1,378 @@ +/* PAGE */ + +html, body { + width: 100%; + height: 100%; + box-sizing: border-box; + padding: 0; + margin: 0; + position: relative; + font-size: 20px; + overflow: auto; +} + +body { + display: flex; + flex-flow: column; +} + +.app-container { + flex: 1; + overflow: auto; + width: 100%; + display: flex; + flex-flow: row; +} + +.fa { + /*min-width: 17px;*/ + margin-right: 3px; + font-family: FontAwesome; +} + +ul { + list-style: none; + padding-left: 10px; +} + +li { + padding: 0px 5px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.folder, .file { + margin-right: 5px; +} + +.contextMenu { + display: none; + position: absolute; +} + +.droppable { + background-color: #FE9A2E; + color: #222; +} + +.selected { + border: 1px dotted #bbb; + background: #666; + color: #eee; + margin: -1px; +} + +/* TREE */ + + +#tree { + border-right: 1px solid #ccc; + box-sizing: border-box; + background: #eee; + overflow: auto; + resize: horizontal; + width: 350px; + white-space: nowrap; + max-width: 500px; + min-width: 200px; + padding: 10px 0px; +} + +#tree li { + cursor: auto; +} + +#tree span.element { + cursor: pointer; +} + +#tree li > span.element:hover { + text-decoration: underline; +} + +#tree .active { + text-decoration: underline; +} + +#tree .category2 { + margin-top: 2em; +} + +#tree .fa.expcol { + margin-left: -10px; + font-size: 14px; + position: absolute; + left: -20px; + top: 9px; + width: auto; + height: 11px; + padding: 0; + margin: 0; + background: white; + z-index: 10; + cursor: default; +} +#tree .fa.expcol:before { + position:relative; + top: -1px; +} + +#tree li.collapsed ul { + display: none; +} + +#tree li input { + width: calc(100% - 30px); +} + +/* Tree lines */ + +#tree ul { + margin: 0px 0px 0px 10px; + list-style: none; +} +#tree ul li { + position: relative; +} +#tree ul li:before { + position: absolute; + left: -15px; + top: -0.25em; + content: ''; + display: block; + border-left: 1px solid #888; + height: 1em; + border-bottom: 1px solid #888; + width: 17.5px; +} +#tree ul li:after { + position: absolute; + left: -15px; + bottom: -7px; + content: ''; + display: block; + border-left: 1px solid #888; + height: 100%; +} +#tree ul li.root { + margin: 0px 0px 0px -10px; +} +#tree ul li.root:before { + display: none; +} +#tree ul li.root:after { + display: none; +} +#tree ul li:last-child:after { + display: none; +} + + +/* CONTENT */ + +#content { + box-sizing: border-box; + background: #eee; + overflow: auto; + flex: 1; + display: flex; + flex-flow: column; +} + +#content h1 { + padding-left: 10px; + margin-top: 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; +} + +.parentFolder { + cursor: pointer; + margin-left: 10px; +} + +.parentFolder:hover { + text-decoration: underline; +} + +#folderContent { + padding-right: 10px; + flex: 1; +} + +#content li:not(.header) * { + pointer-events: none; +} + +#content li:hover:not(.header) .name { + text-decoration: underline; +} + +#content .grid li { + display: inline-block; + margin: 10px 10px; + width: 140px; + text-align: center; + vertical-align: top; +} + +#content .grid li .name { + width: 100%; +} + +#content .grid li input { + width: 100%; +} + +#content .grid li .fa { + display: block; + margin: auto; + font-size: 40px; + text-align: center; +} + +#content .grid li .fa.listonly { + display: none; +} + +#content .list li { + display: flex; + flex-flow: row; + align-items: center; + padding-right: 0px; +} + +#content .list li .element { + display: inline-flex; + flex: 1; +} + +#content .list li.header { + cursor: default; + color: #008; + margin-top: 10px; +} +#content .list li.header .element span:not(.fa) { + border-right: 1px solid #CCC; + text-align: left; +} +#content .list li.header .element span.fa { + float: right; +} +#content .list li.header span.name { + padding-left: 0; +} + +#content .list .element span { + padding: 0px 10px; + display: inline-block; + overflow: hidden; + white-space: nowrap; + box-sizing: border-box; + padding-right: 0px; + border-right: 10px solid rgba(0, 0, 0, 0); +} +#content .list .element span.name { + width: 478px; +} +.iframe #content .list .element span.name { + width: 278px; +} +#content .list .header span.name { + width: 500px; +} +.iframe #content .list .header span.name { + width: 300px; +} +#content .list .element span.type, #content .list .element span.atime, #content .list .element span.ctime { + width: 175px; +} +#content .list .element span.title { + width: 250px; +} +#content .list .element span.folders { + width: 150px; +} +#content .list .element span.files { + width: 150px; +} +#content div.grid .listElement { + display: none; +} +@media screen and (max-width: 1200px) { + #content .list .element span.title { + display: none; + } +} +@media screen and (min-width: 1201px) { + #content .list .element span.title { + display: inline; + } +} + +/* Toolbar */ + +#driveToolbar { + background: #ddd; + height: 40px; +} + +.newPadContainer { + display: inline-block; + height: 100%; +} + +button.newElement { + border-radius: 2px; + height: 30px; + background: #888; + color: #eee; + font-size: 16px; + border: none; + font-weight: bold; +} + +button.newElement:hover { + box-shadow: 0px 0px 2px #000; +} + + +/* The container
                        - needed to position the dropdown content */ +#driveToolbar .dropdown-bar { + margin: 4px 5px; + position: relative; + display: inline-block; +} +#driveToolbar .dropdown-bar.right { + float: right; +} + +/* Right-side buttons */ +#driveToolbar .dropdown-bar.right button { + display: inline-block; +} +#driveToolbar .dropdown-bar.right button.active { + display: none; +} +#driveToolbar .dropdown-bar.right button .fa { + margin-right: 0px; +} +.dropdown-bar-content { + margin-top: -3px; + margin-right: 2px; +} From 7ad080b8a240ff4a18c68c8998bea6529f6bc6c3 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 25 Jan 2017 17:16:41 +0100 Subject: [PATCH 72/88] Move the folder icon style to the less file --- www/drive/file.css | 7 +++++++ www/drive/file.less | 10 ++++++++++ www/drive/main.js | 4 ++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/www/drive/file.css b/www/drive/file.css index 3fc4967fe..370d220c0 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -56,6 +56,13 @@ li { color: #eee; margin: -1px; } +span.fa-folder { + color: #FEDE8B; + text-shadow: -1px 0 #000000, 0 1px #000000, 1px 0 #000000, 0 -1px #000000; +} +span.fa { + min-width: 20px; +} /* TREE */ #tree { border-right: 1px solid #ccc; diff --git a/www/drive/file.less b/www/drive/file.less index b1c2ca558..8f246eb05 100644 --- a/www/drive/file.less +++ b/www/drive/file.less @@ -65,6 +65,16 @@ li { margin: -1px; } +span { + &.fa-folder { + color: #FEDE8B; + text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; + } + &.fa { + min-width: 20px; + } +} + /* TREE */ diff --git a/www/drive/main.js b/www/drive/main.js index 6b7fe7849..50c851e44 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -183,9 +183,9 @@ define([ // Icons - var $folderIcon = $('', {"class": "fa fa-folder folder", style:"color:#FEDE8B;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;"}); + var $folderIcon = $('', {"class": "fa fa-folder folder"}); var $folderEmptyIcon = $folderIcon.clone(); - var $folderOpenedIcon = $('', {"class": "fa fa-folder-open folder", style:"color:#FEDE8B;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;"}); + var $folderOpenedIcon = $('', {"class": "fa fa-folder-open folder"); var $folderOpenedEmptyIcon = $folderOpenedIcon.clone(); var $fileIcon = $('', {"class": "fa fa-file-text-o file"}); var $padIcon = $('', {"class": "fa fa-file-word-o file"}); From 95056315cf3040f790dc5214ca2310d46e6fe4ed Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 25 Jan 2017 17:16:41 +0100 Subject: [PATCH 73/88] Move the folder icon style to the less file --- www/drive/file.css | 8 ++++++++ www/drive/file.less | 10 ++++++++++ www/drive/main.js | 4 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/www/drive/file.css b/www/drive/file.css index 3fc4967fe..87d951ccb 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -56,6 +56,14 @@ li { color: #eee; margin: -1px; } +span.fa-folder, +span.fa-folder-open { + color: #FEDE8B; + text-shadow: -1px 0 #000000, 0 1px #000000, 1px 0 #000000, 0 -1px #000000; +} +span.fa { + min-width: 20px; +} /* TREE */ #tree { border-right: 1px solid #ccc; diff --git a/www/drive/file.less b/www/drive/file.less index b1c2ca558..f450be3da 100644 --- a/www/drive/file.less +++ b/www/drive/file.less @@ -65,6 +65,16 @@ li { margin: -1px; } +span { + &.fa-folder, &.fa-folder-open { + color: #FEDE8B; + text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; + } + &.fa { + min-width: 20px; + } +} + /* TREE */ diff --git a/www/drive/main.js b/www/drive/main.js index 6b7fe7849..50c851e44 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -183,9 +183,9 @@ define([ // Icons - var $folderIcon = $('', {"class": "fa fa-folder folder", style:"color:#FEDE8B;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;"}); + var $folderIcon = $('', {"class": "fa fa-folder folder"}); var $folderEmptyIcon = $folderIcon.clone(); - var $folderOpenedIcon = $('', {"class": "fa fa-folder-open folder", style:"color:#FEDE8B;text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;"}); + var $folderOpenedIcon = $('', {"class": "fa fa-folder-open folder"); var $folderOpenedEmptyIcon = $folderOpenedIcon.clone(); var $fileIcon = $('', {"class": "fa fa-file-text-o file"}); var $padIcon = $('', {"class": "fa fa-file-word-o file"}); From 6f5ff07c2b456dc6640aaf0ae6bba4f0e2e5c330 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 25 Jan 2017 18:33:59 +0100 Subject: [PATCH 74/88] Display the elements as a table instead of a list --- www/drive/file.css | 49 +++++++++++------------- www/drive/file.less | 67 +++++++++++++++------------------ www/drive/main.js | 91 +++++++++++++++++++++++---------------------- 3 files changed, 97 insertions(+), 110 deletions(-) diff --git a/www/drive/file.css b/www/drive/file.css index 87d951ccb..489d95050 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -61,9 +61,6 @@ span.fa-folder-open { color: #FEDE8B; text-shadow: -1px 0 #000000, 0 1px #000000, 1px 0 #000000, 0 -1px #000000; } -span.fa { - min-width: 20px; -} /* TREE */ #tree { border-right: 1px solid #ccc; @@ -212,42 +209,44 @@ span.fa { #content div.grid .listElement { display: none; } +#content .list ul { + display: table; + width: 100%; +} #content .list li { - display: flex; - flex-flow: row; - align-items: center; - padding-right: 0px; + display: table-row; } -#content .list li .element { - display: inline-flex; - flex: 1; +#content .list li > span { + padding: 0 5px; + display: table-cell; } #content .list li.header { cursor: default; - color: #008; - margin-top: 10px; + color: #888; } -#content .list li.header .element span:not(.fa) { - border-right: 1px solid #CCC; +#content .list li.header span:not(.fa) { text-align: left; } -#content .list li.header .element span.fa { +#content .list li.header span.sortasc, +#content .list li.header span.sortdesc { float: right; } -#content .list li.header span.name { - padding-left: 0; +#content .list li.header > span.active { + font-weight: bold; +} +#content .list li.header > span.clickable { + cursor: pointer; +} +#content .list li.header > span.clickable:hover { + background: #d8d8d8; } #content .list .element span { - padding: 0px 10px; - display: inline-block; overflow: hidden; white-space: nowrap; box-sizing: border-box; - padding-right: 0px; - border-right: 10px solid rgba(0, 0, 0, 0); } -#content .list .element span.name { - width: 478px; +#content .list .element span.icon { + width: 30px; } #content .list .element span.type, #content .list .element span.atime, @@ -256,7 +255,6 @@ span.fa { } #content .list .element span.title { width: 250px; - display: inline; } @media screen and (max-width: 1200px) { #content .list .element span.title { @@ -267,9 +265,6 @@ span.fa { #content .list .element span.files { width: 150px; } -#content .list .header span.name { - width: 500px; -} .parentFolder { cursor: pointer; margin-left: 10px; diff --git a/www/drive/file.less b/www/drive/file.less index f450be3da..dd8de9279 100644 --- a/www/drive/file.less +++ b/www/drive/file.less @@ -70,9 +70,6 @@ span { color: #FEDE8B; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; } - &.fa { - min-width: 20px; - } } /* TREE */ @@ -240,55 +237,56 @@ span { } .list { + // Make it act as a table! + ul { + display: table; + width: 100%; + } li { - display: flex; - flex-flow: row; - align-items: center; - padding-right: 0px; - .element { - display: inline-flex; - flex: 1; + display: table-row; + &> span { + padding: 0 5px; + display: table-cell; } + } + li { &.header { cursor: default; - color: #008; - margin-top: 10px; - .element { - span { - &:not(.fa) { - border-right: 1px solid #CCC; - text-align: left; - } - &.fa { - float: right; - } + color: #888; + span { + &:not(.fa) { + text-align: left; + } + &.sortasc, &.sortdesc { + float: right; } } - span { - &.name { - padding-left: 0; + &> span { + &.active { + font-weight: bold; + } + &.clickable { + cursor: pointer; + &:hover { + background: #d8d8d8; + } } } } } .element { span { - padding: 0px 10px; - display: inline-block; overflow: hidden; white-space: nowrap; box-sizing: border-box; - padding-right: 0px; - border-right: 10px solid rgba(0, 0, 0, 0); - &.name { - width: 478px; + &.icon { + width: 30px; } &.type, &.atime, &.ctime { width: 175px; } &.title { width: 250px; - display: inline; @media screen and (max-width: 1200px) { display: none; } @@ -298,13 +296,6 @@ span { } } } - .header { - span { - &.name { - width: 500px; - } - } - } } } diff --git a/www/drive/main.js b/www/drive/main.js index 50c851e44..9f207fb4d 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -183,16 +183,15 @@ define([ // Icons - var $folderIcon = $('', {"class": "fa fa-folder folder"}); + var $folderIcon = $('', {"class": "fa fa-folder folder icon"}); var $folderEmptyIcon = $folderIcon.clone(); - var $folderOpenedIcon = $('', {"class": "fa fa-folder-open folder"); + var $folderOpenedIcon = $('', {"class": "fa fa-folder-open folder"}); var $folderOpenedEmptyIcon = $folderOpenedIcon.clone(); - var $fileIcon = $('', {"class": "fa fa-file-text-o file"}); - var $padIcon = $('', {"class": "fa fa-file-word-o file"}); - var $codeIcon = $('', {"class": "fa fa-file-code-o file"}); - var $slideIcon = $('', {"class": "fa fa-file-powerpoint-o file"}); - var $pollIcon = $('', {"class": "fa fa-calendar file"}); - var $anonIcon = $('', {"class": "fa fa-user-secret file listonly"}); + var $fileIcon = $('', {"class": "fa fa-file-text-o file icon"}); + var $padIcon = $('', {"class": "fa fa-file-word-o file icon"}); + var $codeIcon = $('', {"class": "fa fa-file-code-o file icon"}); + var $slideIcon = $('', {"class": "fa fa-file-powerpoint-o file icon"}); + var $pollIcon = $('', {"class": "fa fa-calendar file icon"}); var $upIcon = $('', {"class": "fa fa-arrow-circle-up"}); var $unsortedIcon = $('', {"class": "fa fa-files-o"}); var $templateIcon = $('', {"class": "fa fa-cubes"}); @@ -202,8 +201,8 @@ define([ var $expandIcon = $('', {"class": "fa fa-plus-square-o expcol"}); var $listIcon = $('', {"class": "fa fa-list"}); var $gridIcon = $('', {"class": "fa fa-th"}); - var $sortAscIcon = $('', {"class": "fa fa-angle-up"}); - var $sortDescIcon = $('', {"class": "fa fa-angle-down"}); + var $sortAscIcon = $('', {"class": "fa fa-angle-up sortasc"}); + var $sortDescIcon = $('', {"class": "fa fa-angle-down sortdesc"}); var $closeIcon = $('', {"class": "fa fa-window-close"}); if (!APP.readOnly) { @@ -235,7 +234,7 @@ define([ $iframe.find('.selected').removeClass("selected"); }; var removeInput = function () { - $iframe.find('li > span:hidden').show(); + $iframe.find('li > span:hidden').attr('style', undefined); $iframe.find('li > input').remove(); }; @@ -367,8 +366,8 @@ define([ return true; } - // $element should be the , find it if it's not the case - var $element = $(e.target).closest('li').children('span.element'); + // $element should be the
                      • + var $element = $(e.target).closest('li'); onElementClick(undefined, $element); if (!$element.length) { logError("Unable to locate the .element tag", e.target); @@ -673,22 +672,20 @@ define([ var element = filesOp.findElement(files, newPath); var $icon = !isFolder ? getFileIcon(element) : undefined; - var spanClass = 'file-element element'; - var liClass = 'file-item'; + var liClass = 'file-item file-element element'; if (isFolder) { - spanClass = 'folder-element element'; - liClass = 'folder-item'; + liClass = 'folder-item folder-element element'; $icon = filesOp.isFolderEmpty(root[key]) ? $folderEmptyIcon.clone() : $folderIcon.clone(); } - var $name = $('', { 'class': spanClass }).text(key); + var $element = $('
                      • ', { + draggable: true + }); if (isFolder) { - addFolderData(element, key, $name); + addFolderData(element, key, $element); } else { - addFileData(element, key, $name, true); + addFileData(element, key, $element, true); } - var $element = $('
                      • ', { - draggable: true - }).append($icon).append($name).dblclick(function () { + $element.prepend($icon).dblclick(function () { if (isFolder) { module.displayDirectory(newPath); return; @@ -946,18 +943,19 @@ define([ $icon = $sortDescIcon.clone(); } if (typeof(Cryptpad.getLSAttribute(SORT_FOLDER_DESC)) !== "undefined") { - $list.find('.foldername').prepend($icon); + $list.find('.foldername').addClass('active').prepend($icon); } }; var getFolderListHeader = function () { - var $folderHeader = $('
                      • ', {'class': 'header listElement'}); - var $fohElement = $('', {'class': 'element'}).appendTo($folderHeader); - var $name = $('', {'class': 'name foldername'}).text(Messages.fm_folderName).click(onSortByClick); + var $fohElement = $('
                      • ', {'class': 'header listElement'}); + //var $fohElement = $('', {'class': 'element'}).appendTo($folderHeader); + var $fhIcon = $('', {'class': 'icon'}); + var $name = $('', {'class': 'name foldername clickable'}).text(Messages.fm_folderName).click(onSortByClick); var $subfolders = $('', {'class': 'folders listElement'}).text(Messages.fm_numberOfFolders); var $files = $('', {'class': 'files listElement'}).text(Messages.fm_numberOfFiles); - $fohElement.append($name).append($subfolders).append($files); + $fohElement.append($fhIcon).append($name).append($subfolders).append($files); addFolderSortIcon($fohElement); - return $folderHeader; + return $fohElement; }; var addFileSortIcon = function ($list) { var $icon = $sortAscIcon.clone(); @@ -968,19 +966,20 @@ define([ if (Cryptpad.getLSAttribute(SORT_FILE_BY) === '') { classSorted = 'filename'; } else if (Cryptpad.getLSAttribute(SORT_FILE_BY)) { classSorted = Cryptpad.getLSAttribute(SORT_FILE_BY); } if (classSorted) { - $list.find('.' + classSorted).prepend($icon); + $list.find('.' + classSorted).addClass('active').prepend($icon); } }; // _WORKGROUP_ : do not display title, atime and ctime in workgroups since we don't have files data var getFileListHeader = function (displayTitle) { - var $fileHeader = $('
                      • ', {'class': 'file-header header listElement'}); - var $fihElement = $('', {'class': 'element'}).appendTo($fileHeader); - var $fhName = $('', {'class': 'name filename'}).text(Messages.fm_fileName).click(onSortByClick); - var $fhTitle = $('', {'class': 'title '}).text(Messages.fm_title).click(onSortByClick); - var $fhType = $('', {'class': 'type'}).text(Messages.table_type).click(onSortByClick); - var $fhAdate = $('', {'class': 'atime'}).text(Messages.fm_lastAccess).click(onSortByClick); - var $fhCdate = $('', {'class': 'ctime'}).text(Messages.fm_creation).click(onSortByClick); - $fihElement.append($fhName); + var $fihElement = $('
                      • ', {'class': 'file-header header listElement element'}); + //var $fihElement = $('', {'class': 'element'}).appendTo($fileHeader); + var $fhIcon = $('', {'class': 'icon'}); + var $fhName = $('', {'class': 'name filename clickable'}).text(Messages.fm_fileName).click(onSortByClick); + var $fhTitle = $('', {'class': 'title clickable'}).text(Messages.fm_title).click(onSortByClick); + var $fhType = $('', {'class': 'type clickable'}).text(Messages.table_type).click(onSortByClick); + var $fhAdate = $('', {'class': 'atime clickable'}).text(Messages.fm_lastAccess).click(onSortByClick); + var $fhCdate = $('', {'class': 'ctime clickable'}).text(Messages.fm_creation).click(onSortByClick); + $fihElement.append($fhIcon).append($fhName); if (displayTitle && !isWorkgroup()) { $fihElement.append($fhTitle); } @@ -989,7 +988,8 @@ define([ $fihElement.append($fhAdate).append($fhCdate); } addFileSortIcon($fihElement); - return $fileHeader; + return $fihElement; + //return $fileHeader; }; var allFilesSorted = function () { @@ -1098,11 +1098,12 @@ define([ } var idx = files[rootName].indexOf(href); var $icon = getFileIcon(href); - var $name = $('', { 'class': 'file-element element' }); - addFileData(href, file.title, $name, false); var $element = $('
                      • ', { + 'class': 'file-element element', draggable: draggable - }).append($icon).append($name).dblclick(function () { + }); + addFileData(href, file.title, $element, false); + $element.prepend($icon).dblclick(function () { openFile(href); }); var path = [rootName, idx]; @@ -1129,9 +1130,9 @@ define([ var sortedFiles = sortElements(false, [FILES_DATA], keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !getSortFileDesc(), false, true); sortedFiles.forEach(function (file) { var $icon = getFileIcon(file.href); - var $name = $('', { 'class': 'file-element element' }); - addFileData(file.href, file.title, $name, false); - var $element = $('
                      • ').append($icon).append($name).dblclick(function () { + var $element = $('
                      • ', { 'class': 'file-element element' }) + addFileData(file.href, file.title, $element, false); + $element.prepend($icon).dblclick(function () { openFile(file.href); }); $element.click(function(e) { From 00efc9691937e83330e0a6f660a9a9ded25dc47b Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 26 Jan 2017 12:56:19 +0100 Subject: [PATCH 75/88] Move the toolbar and add a breadcrumb --- www/drive/file.css | 100 +++++++++++++++++++++++++------ www/drive/file.less | 138 +++++++++++++++++++++++++++++++++++-------- www/drive/inner.html | 1 + www/drive/main.js | 127 ++++++++++++++++++++++----------------- 4 files changed, 268 insertions(+), 98 deletions(-) diff --git a/www/drive/file.css b/www/drive/file.css index 489d95050..f28a9bfe2 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -14,6 +14,14 @@ body { display: flex; flex-flow: column; } +.unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} .app-container { flex: 1; overflow: auto; @@ -28,7 +36,7 @@ body { } ul { list-style: none; - padding-left: 10px; + padding-left: 0px; } li { padding: 0px 5px; @@ -65,7 +73,7 @@ span.fa-folder-open { #tree { border-right: 1px solid #ccc; box-sizing: border-box; - background: #eee; + background: #eeeeee; overflow: auto; resize: horizontal; width: 250px; @@ -73,11 +81,12 @@ span.fa-folder-open { max-width: 500px; min-width: 200px; padding: 10px 0px; + color: #000000; } #tree li { cursor: auto; } -#tree li > span.element:hover { +#tree li:hover > span.element { text-decoration: underline; } #tree li.collapsed ul { @@ -95,6 +104,10 @@ span.fa-folder-open { #tree .category2 { margin-top: 2em; } +#tree .category2 .root > .fa { + min-width: 30px; + cursor: pointer; +} #tree .fa.expcol { margin-left: -10px; font-size: 14px; @@ -116,6 +129,7 @@ span.fa-folder-open { #tree ul { margin: 0px 0px 0px 10px; list-style: none; + padding-left: 10px; } #tree ul li { position: relative; @@ -126,9 +140,9 @@ span.fa-folder-open { top: -0.25em; content: ''; display: block; - border-left: 1px solid #888; + border-left: 1px solid #888888; height: 1em; - border-bottom: 1px solid #888; + border-bottom: 1px solid #888888; width: 17.5px; } #tree ul li:after { @@ -137,7 +151,7 @@ span.fa-folder-open { bottom: -7px; content: ''; display: block; - border-left: 1px solid #888; + border-left: 1px solid #888888; height: 100%; } #tree ul li.root { @@ -155,7 +169,8 @@ span.fa-folder-open { /* CONTENT */ #content { box-sizing: border-box; - background: #eee; + background: #eeeeee; + color: #000000; overflow: auto; flex: 1; display: flex; @@ -166,12 +181,13 @@ span.fa-folder-open { margin-top: 10px; } #content .info-box { - margin: 0px auto; - padding: 5px; + height: 40px; + line-height: 40px; + padding-left: 10px; + margin: 10px auto; background: #ddddff; - border: 1px solid #bbb; + border: 1px solid #bbbbbb; border-radius: 5px; - margin-bottom: 10px; } #content .info-box span { cursor: pointer; @@ -184,6 +200,9 @@ span.fa-folder-open { #content li:not(.header):hover .name { text-decoration: underline; } +#content div.grid { + padding: 20px; +} #content div.grid li { display: inline-block; margin: 10px 10px; @@ -212,6 +231,7 @@ span.fa-folder-open { #content .list ul { display: table; width: 100%; + padding: 0px 10px; } #content .list li { display: table-row; @@ -222,7 +242,7 @@ span.fa-folder-open { } #content .list li.header { cursor: default; - color: #888; + color: #888888; } #content .list li.header span:not(.fa) { text-align: left; @@ -231,6 +251,9 @@ span.fa-folder-open { #content .list li.header span.sortdesc { float: right; } +#content .list li.header > span { + padding: 15px 5px; +} #content .list li.header > span.active { font-weight: bold; } @@ -278,28 +301,40 @@ span.fa-folder-open { } /* Toolbar */ #driveToolbar { - background: #ddd; + background: #dddddd; + color: #555555; height: 40px; + display: flex; + flex-flow: row; + border-top: 1px solid #cccccc; + border-bottom: ; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + z-index: 100; + box-sizing: content-box; /* The container
                        - needed to position the dropdown content */ } #driveToolbar .newPadContainer { display: inline-block; height: 100%; } -#driveToolbar button.newElement { +#driveToolbar button.element { border-radius: 2px; height: 30px; - background: #888; - color: #eee; + background: #888888; + color: #eeeeee; font-size: 16px; border: none; font-weight: bold; } -#driveToolbar button.newElement:hover { +#driveToolbar button.element:hover { box-shadow: 0px 0px 2px #000; } +#driveToolbar button.new { + padding: 0 20px; +} #driveToolbar .dropdown-bar { - margin: 4px 5px; + margin: 5px 5px; + line-height: 1em; position: relative; display: inline-block; } @@ -320,3 +355,32 @@ span.fa-folder-open { margin-top: -3px; margin-right: 2px; } +#driveToolbar .leftside { + width: 250px; + margin: 0; + padding: 0; +} +#driveToolbar .rightside { + margin: 0; + padding: 0; + flex: 1; +} +#driveToolbar .path { + display: inline-block; + height: 100%; + line-height: 40px; + cursor: default; +} +#driveToolbar .path .element { + padding: 5px; + border: 1px solid #dddddd; + border-radius: 2px; + box-sizing: border-box; +} +#driveToolbar .path .element.clickable { + cursor: pointer; +} +#driveToolbar .path .element.clickable:hover { + background: #ffffff; + border: 1px solid #888888; +} diff --git a/www/drive/file.less b/www/drive/file.less index dd8de9279..30a5b6a8f 100644 --- a/www/drive/file.less +++ b/www/drive/file.less @@ -1,3 +1,22 @@ +@tree-bg: #eee; +@tree-fg: #000; +@tree-lines-col: #888; + +@content-bg: @tree-bg; +@content-fg: @tree-fg; +@info-box-bg: #ddddff; +@info-box-border: #bbb; +@table-header-fg: #888; +@table-header-bg: #d8d8d8; + +@toolbar-bg: #ddd; +@toolbar-fg: #555; +@toolbar-border-col: #ccc; +@toolbar-button-bg: #888; +@toolbar-button-fg: #eee; +@toolbar-path-bg: #fff; +@toolbar-path-border: #888; + /* PAGE */ html, body { @@ -16,6 +35,15 @@ body { flex-flow: column; } +.unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + .app-container { flex: 1; overflow: auto; @@ -32,7 +60,7 @@ body { ul { list-style: none; - padding-left: 10px; + padding-left: 0px; // Remove the default padding } li { @@ -78,7 +106,7 @@ span { #tree { border-right: 1px solid #ccc; box-sizing: border-box; - background: #eee; + background: @tree-bg; overflow: auto; resize: horizontal; width: 250px; @@ -86,9 +114,10 @@ span { max-width: 500px; min-width: 200px; padding: 10px 0px; + color: @tree-fg; li { cursor: auto; - &> span.element:hover { + &:hover > span.element { text-decoration: underline; } &.collapsed ul { @@ -106,6 +135,12 @@ span { } .category2 { margin-top: 2em; + .root { + &> .fa { + min-width: 30px; + cursor: pointer; + } + } } .fa.expcol { margin-left: -10px; @@ -130,6 +165,7 @@ span { ul { margin: 0px 0px 0px 10px; list-style: none; + padding-left: 10px; li { position: relative; &:before { @@ -138,9 +174,9 @@ span { top: -0.25em; content: ''; display: block; - border-left: 1px solid #888; + border-left: 1px solid @tree-lines-col; height: 1em; - border-bottom: 1px solid #888; + border-bottom: 1px solid @tree-lines-col; width: 17.5px; } &:after { @@ -149,7 +185,7 @@ span { bottom: -7px; content: ''; display: block; - border-left: 1px solid #888; + border-left: 1px solid @tree-lines-col; height: 100%; } &.root { @@ -173,7 +209,8 @@ span { #content { box-sizing: border-box; - background: #eee; + background: @content-bg; + color: @content-fg; overflow: auto; flex: 1; display: flex; @@ -183,12 +220,13 @@ span { margin-top: 10px; } .info-box { - margin: 0px auto; - padding: 5px; - background: #ddddff; - border: 1px solid #bbb; + height: 40px; + line-height: 40px; + padding-left: 10px; + margin: 10px auto; + background: @info-box-bg; + border: 1px solid @info-box-border; border-radius: 5px; - margin-bottom: 10px; span { cursor: pointer; margin-left: 10px; @@ -208,6 +246,7 @@ span { } } div.grid { + padding: 20px; li { display: inline-block; margin: 10px 10px; @@ -241,6 +280,7 @@ span { ul { display: table; width: 100%; + padding: 0px 10px; } li { display: table-row; @@ -252,7 +292,7 @@ span { li { &.header { cursor: default; - color: #888; + color: @table-header-fg; span { &:not(.fa) { text-align: left; @@ -262,13 +302,14 @@ span { } } &> span { + padding: 15px 5px; &.active { font-weight: bold; } &.clickable { cursor: pointer; &:hover { - background: #d8d8d8; + background: @table-header-bg; } } } @@ -316,28 +357,43 @@ span { /* Toolbar */ #driveToolbar { - background: #ddd; + background: @toolbar-bg; + color: @toolbar-fg; height: 40px; + display: flex; + flex-flow: row; + border-top: 1px solid @toolbar-border-col; + border-bottom: ; + box-shadow: 0 2px 4px rgba(0,0,0,0.2); + z-index: 100; + box-sizing: content-box; + .newPadContainer { display: inline-block; height: 100%; } - button.newElement { - border-radius: 2px; - height: 30px; - background: #888; - color: #eee; - font-size: 16px; - border: none; - font-weight: bold; - &:hover { - box-shadow: 0px 0px 2px #000; + button { + &.element { + border-radius: 2px; + height: 30px; + background: @toolbar-button-bg; + color: @toolbar-button-fg; + font-size: 16px; + border: none; + font-weight: bold; + &:hover { + box-shadow: 0px 0px 2px #000; + } + } + &.new { + padding: 0 20px; } } /* The container
                        - needed to position the dropdown content */ .dropdown-bar { - margin: 4px 5px; + margin: 5px 5px; + line-height: 1em; position: relative; display: inline-block; &.right { @@ -358,6 +414,36 @@ span { margin-top: -3px; margin-right: 2px; } + + .leftside { + width: 250px; + margin: 0; + padding: 0; + } + .rightside { + margin: 0; + padding: 0; + flex: 1; + } + .path { + display: inline-block; + height: 100%; + line-height: 40px; + cursor: default; + .element { + padding: 5px; + border: 1px solid @toolbar-bg; + border-radius: 2px; + box-sizing: border-box; + &.clickable { + cursor: pointer; + &:hover { + background: @toolbar-path-bg; + border: 1px solid @toolbar-path-border; + } + } + } + } } diff --git a/www/drive/inner.html b/www/drive/inner.html index 379a8fed0..dc82c7ee2 100644 --- a/www/drive/inner.html +++ b/www/drive/inner.html @@ -11,6 +11,7 @@
                        +
                        diff --git a/www/drive/main.js b/www/drive/main.js index 9f207fb4d..7056c7bcf 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -175,6 +175,7 @@ define([ var $tree = $iframe.find("#tree"); var $content = $iframe.find("#content"); + var $driveToolbar = $iframe.find("#driveToolbar"); var $contextMenu = $iframe.find("#treeContextMenu"); var $contentContextMenu = $iframe.find("#contentContextMenu"); var $defaultContextMenu = $iframe.find("#defaultContextMenu"); @@ -578,6 +579,10 @@ define([ onDrag(e.originalEvent, path); }); + $element.on('mousedown', function (e) { + e.stopPropagation(); + }); + // Add drop handlers if we are not in the trash and if the element is a folder if (!droppable || !isFolder) { return; } @@ -648,10 +653,10 @@ define([ var getFileIcon = function (href) { var $icon = $fileIcon.clone(); - if (href.indexOf('/pad/') !== -1) { $icon = $padIcon.clone() } - else if (href.indexOf('/code/') !== -1) { $icon = $codeIcon.clone() } - else if (href.indexOf('/slide/') !== -1) { $icon = $slideIcon.clone() } - else if (href.indexOf('/poll/') !== -1) { $icon = $pollIcon.clone() } + if (href.indexOf('/pad/') !== -1) { $icon = $padIcon.clone(); } + else if (href.indexOf('/code/') !== -1) { $icon = $codeIcon.clone(); } + else if (href.indexOf('/slide/') !== -1) { $icon = $slideIcon.clone(); } + else if (href.indexOf('/poll/') !== -1) { $icon = $pollIcon.clone(); } return $icon; }; @@ -732,32 +737,41 @@ define([ return title; }; + var getPrettyName = function (name) { + var pName; + switch (name) { + case ROOT: pName = ROOT_NAME; break; + case TRASH: pName = TRASH_NAME; break; + case UNSORTED: pName = UNSORTED_NAME; break; + case TEMPLATE: pName = TEMPLATE_NAME; break; + case FILES_DATA: pName = FILES_DATA_NAME; break; + default: pName = name; + } + return pName; + }; + // Create the title block with the "parent folder" button var createTitle = function (path) { - var isTrash = path[0] === TRASH; - // Create title and "Up" icon - var name = path[path.length - 1]; - 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 = $('

                        ').text(name); - if (path.length > 1) { - var $parentFolder = $upIcon.clone().addClass("parentFolder") - .click(function() { - var newPath = path.slice(); - newPath.pop(); - if (isTrash && path.length === 4) { - // path = [TRASH, "{DirName}", 0, 'element'] - // --> parent is TRASH - newPath = [TRASH]; - } - module.displayDirectory(newPath); + if (!path || path.length === 0) { return; } + var isTrash = filesOp.isPathInTrash(path); + var $title = $('', {'class': 'path unselectable'}); + path.forEach(function (p, idx) { + if (isTrash && [1,2].indexOf(idx) !== -1) { return; } + + var $span = $('', {'class': 'element'}); + if (idx < path.length - 1) { + $span.addClass('clickable'); + $span.click(function (e) { + module.displayDirectory(path.slice(0, idx + 1)); }); - $title.append($parentFolder); - } + } + + var name = p; + if (idx === 0) { name = getPrettyName(p); } + else { $title.append(' > '); } + + $span.text(name).appendTo($title); + }); return $title; }; @@ -807,10 +821,10 @@ define([ }); var $listButton = $('