diff --git a/.gitignore b/.gitignore index abc6eb530..a75bb20e2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ messages.log .DS_Store www/scratch data +npm-debug.log diff --git a/.travis.yml b/.travis.yml index 1331ef3cb..24288c6f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ branches: - soon - staging node_js: - - "4.2.1" + - "6.6.0" before_script: - npm run-script lint - cp config.js.dist config.js diff --git a/bower.json b/bower.json index a6fc85b41..be5bdf00e 100644 --- a/bower.json +++ b/bower.json @@ -24,23 +24,19 @@ "ckeditor": "~4.5.6", "codemirror": "^5.19.0", "requirejs": "~2.1.15", - "reconnectingWebsocket": "", "marked": "~0.3.5", "rangy": "rangy-release#~1.3.0", "json.sortify": "~2.1.0", "fabric.js": "fabric#~1.6.0", "hyperjson": "~1.4.0", "textpatcher": "^1.3.0", - "proxy-polyfill": "^0.1.5", "chainpad": "^0.3.0", "chainpad-json-validator": "^0.2.0", "chainpad-crypto": "^0.1.3", "chainpad-listmap": "^0.3.0", - "lil-uri": "^0.2.1", "file-saver": "^1.3.1", "diff-dom": "^2.1.1", "alertifyjs": "^1.0.11", - "spin.js": "^2.3.2", "scrypt-async": "^1.2.0", "bootstrap": "#v4.0.0-alpha.6" } diff --git a/customize.dist/about.html b/customize.dist/about.html index 988efafc3..dfacd0634 100644 --- a/customize.dist/about.html +++ b/customize.dist/about.html @@ -115,6 +115,7 @@ + diff --git a/customize.dist/contact.html b/customize.dist/contact.html index 1985d8347..182b7c5d2 100644 --- a/customize.dist/contact.html +++ b/customize.dist/contact.html @@ -112,6 +112,7 @@ + diff --git a/customize.dist/index.html b/customize.dist/index.html index 12697787e..022dd6070 100644 --- a/customize.dist/index.html +++ b/customize.dist/index.html @@ -234,6 +234,7 @@ + diff --git a/customize.dist/main.css b/customize.dist/main.css index 791563ed3..b3a79aaaf 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -1,6 +1,11 @@ /* Logs are shown to inform the user that something has happened They are only displayed briefly */ +@media print { + .alertify-logs { + visibility: hidden; + } +} .alertify-logs > * { padding: 12px 48px; color: #fafafa; @@ -56,11 +61,25 @@ top: 50%; transform: translateY(-50%); } +.alertify .dialog .bright, +.alertify .alert .bright { + color: #ffffff; +} .alertify .dialog > div, .alertify .alert > div { background-color: #444; border-radius: 5px; } +.alertify .dialog > div.half, +.alertify .alert > div.half { + width: 50%; +} +@media (max-width: 600px) { + .alertify .dialog > div.half, + .alertify .alert > div.half { + width: 100%; + } +} .alertify .dialog > *, .alertify .alert > * { width: 30%; @@ -118,6 +137,34 @@ border: 1px solid #302B28; border-radius: 5px; } +.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe, +.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe, +.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger, +.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger { + color: #302B28; + white-space: normal; + font-weight: bold; +} +.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger, +.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger { + background-color: #FA5858; +} +.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger:hover, +.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger:hover, +.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger:active, +.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger:active { + background-color: #fb7171; +} +.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe, +.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe { + background-color: #46E981; +} +.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe:hover, +.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe:hover, +.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe:active, +.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe:active { + background-color: #74eea0; +} .alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover, .alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover, .alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active, @@ -319,6 +366,7 @@ .cp #loading .cryptofist { margin-left: auto; margin-right: auto; + height: 300px; } @media screen and (max-height: 450px) { .cp #loading .cryptofist { @@ -332,6 +380,25 @@ .cp #loading .spinnerContainer > div { height: 100px; } +.cp #loadingTip { + position: fixed; + z-index: 99999; + top: 80%; + left: 0; + right: 0; + text-align: center; +} +.cp #loadingTip span { + background-color: #302B28; + color: #fafafa; + text-align: center; + font-size: 1.5em; + opacity: 0.7; + font-family: lato, Helvetica, sans-serif; + padding: 15px; + max-width: 60%; + display: inline-block; +} /* The container
- needed to position the dropdown content */ .dropdown-bar { position: relative; @@ -376,6 +443,10 @@ background-color: #f1f1f1; color: black !important; } +.dropdown-bar .dropdown-bar-content a.active { + background-color: #e8e8e8; + color: black !important; +} .dropdown-bar .dropdown-bar-content hr { margin: 5px 0px; height: 1px; @@ -487,6 +558,14 @@ font-size: 1.2em; font-weight: bold; } +.cp footer div.version-footer { + background-color: #302B28; + color: #fafafa; + text-align: center; + width: 100%; + padding-top: 10px; + padding-bottom: 10px; +} html.cp, .cp body { font-size: .875em; @@ -977,11 +1056,6 @@ html.cp, .cp #main_other .buttons { margin-top: 15px; } -.cp #fileManagerIframe { - width: 100%; - height: 500px; - margin-top: 15px; -} .cp .create, .cp .action { display: inline-block; @@ -1271,196 +1345,6 @@ html.cp, .cp div.realtime #addoption { border-bottom-left-radius: 5px; } -.cp.slide #modal .button { - position: absolute; - cursor: pointer; - font-size: 30px; - opacity: 0.6; - display: none; -} -.cp.slide #modal .button:hover { - opacity: 1; - display: block !important; -} -.cp.slide #modal #button_exit { - left: 20px; - top: 20px; - z-index: 9001; -} -.cp.slide #modal #button_left { - left: 6vw; - bottom: 10vh; -} -.cp.slide #modal #button_right { - right: 6vw; - bottom: 10vh; -} -.cp.slide #modal #content p, -.cp.slide #modal #content ul, -.cp.slide #modal #content ol { - font-size: 26px; -} -.cp.slide #modal #content img { - position: relative; - min-width: 1%; - max-width: 90%; - max-height: 90%; - margin: auto; -} -.cp div.modal, -.cp div#modal { - box-sizing: border-box; - z-index: 9001; - position: fixed; - top: 0px; - left: 0px; - width: 100%; - height: 100vh; - display: none; - background-color: #000; -} -.cp div.modal #content, -.cp div#modal #content { - box-sizing: border-box; - border: 1px solid white; - vertical-align: middle; - padding: 2.5vw; - /* center things as much as possible - - margin-top: 50vh; - margin-bottom: 50vh; - transform: translateY(-50%); - - */ - width: 100vw; - height: 56.25vw; - max-height: 100vh; - max-width: 177.78vh; - margin: auto; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} -.cp div.modal #content p, -.cp div#modal #content p, -.cp div.modal #content li, -.cp div#modal #content li, -.cp div.modal #content pre, -.cp div#modal #content pre, -.cp div.modal #content code, -.cp div#modal #content code { - font-size: 2.75vw; - line-height: 3.025vw; -} -.cp div.modal #content h1, -.cp div#modal #content h1 { - font-size: 5vw; - line-height: 5.5vw; -} -.cp div.modal #content h2, -.cp div#modal #content h2 { - font-size: 4.2vw; - line-height: 4.62vw; -} -.cp div.modal #content h3, -.cp div#modal #content h3 { - font-size: 3.6vw; - line-height: 3.96vw; -} -.cp div.modal #content h4, -.cp div#modal #content h4 { - font-size: 3vw; - line-height: 3.3vw; -} -.cp div.modal #content h5, -.cp div#modal #content h5 { - font-size: 2.2vw; - line-height: 2.42vw; -} -.cp div.modal #content h6, -.cp div#modal #content h6 { - font-size: 1.6vw; - line-height: 1.76vw; -} -.cp div.modal #content h1, -.cp div#modal #content h1, -.cp div.modal #content h2, -.cp div#modal #content h2, -.cp div.modal #content h3, -.cp div#modal #content h3, -.cp div.modal #content h4, -.cp div#modal #content h4, -.cp div.modal #content h5, -.cp div#modal #content h5, -.cp div.modal #content h6, -.cp div#modal #content h6 { - color: inherit; -} -.cp div.modal #content pre > code, -.cp div#modal #content pre > code { - display: block; - position: relative; - border: 1px solid #333; - width: 90%; - margin: auto; - padding-left: .25vw; -} -.cp div.modal #content ul, -.cp div#modal #content ul, -.cp div.modal #content ol, -.cp div#modal #content ol { - min-width: 50%; - max-width: 100%; - display: table; - margin: 0 auto; -} -.cp div.modal .center, -.cp div#modal .center { - position: relative; - width: 80%; - height: 80%; - margin: auto; - border: 1px solid #ffffff; - text-align: center; -} -.cp div.modal.shown, -.cp div#modal.shown { - display: block; -} -.cp div.modal table, -.cp div#modal table { - margin: 30px; - border-collapse: collapse; -} -.cp div.modal table input, -.cp div#modal table input { - height: 100%; - width: 90%; - border: 3px solid #fff; -} -.cp div.modal table tfoot tr td, -.cp div#modal table tfoot tr td { - z-index: 4000; - cursor: pointer; -} -.cp div.modal #addtime, -.cp div#modal #addtime, -.cp div.modal #adddate, -.cp div#modal #adddate { - color: #46E981; - border: 1px solid #46E981; - padding: 15px; -} -.cp div.modal #adddate, -.cp div#modal #adddate { - border-top-left-radius: 5px; -} -.cp div.modal #addtime, -.cp div#modal #addtime { - border-bottom-left-radius: 5px; -} #cors-store { display: none; } diff --git a/customize.dist/main.js b/customize.dist/main.js index 4c6d37ae5..8452a2480 100644 --- a/customize.dist/main.js +++ b/customize.dist/main.js @@ -1,9 +1,8 @@ define([ '/customize/application_config.js', '/common/cryptpad-common.js', - '/bower_components/lil-uri/uri.min.js', '/bower_components/jquery/dist/jquery.min.js', -], function (Config, Cryptpad, LilUri) { +], function (Config, Cryptpad) { var $ = window.$; var APP = window.APP = { @@ -133,8 +132,10 @@ define([ if (result.proxy && !result.proxy.login_name) { result.proxy.login_name = result.userName; } - Cryptpad.login(result.userHash, result.userName, function () { - document.location.href = '/drive/'; + Cryptpad.whenRealtimeSyncs(result.realtime, function () { + Cryptpad.login(result.userHash, result.userName, function () { + document.location.href = '/drive/'; + }); }); return; } diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 924139570..ba35f1d96 100644 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -1,11 +1,6 @@ (function () { var LS_LANG = "CRYPTPAD_LANG"; -var getStoredLanguage = function () { return localStorage.getItem(LS_LANG); }; -var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage; }; -var getLanguage = function () { return getStoredLanguage() || getBrowserLanguage(); }; -var language = getLanguage(); - // add your module to this map so it gets used var map = { 'fr': 'Français', @@ -15,6 +10,19 @@ var map = { 'pt-br': 'Português do Brasil' }; +var getStoredLanguage = function () { return localStorage.getItem(LS_LANG); }; +var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage; }; +var getLanguage = function () { + if (getStoredLanguage()) { return getStoredLanguage(); } + var l = getBrowserLanguage() || ''; + if (Object.keys(map).indexOf(l) !== -1) { + return l; + } + // Edge returns 'fr-FR' --> transform it to 'fr' and check again + return Object.keys(map).indexOf(l.split('-')[0]) !== -1 ? l.split('-')[0] : 'en'; +}; +var language = getLanguage(); + var req = ['/customize/translations/messages.js']; if (language && map[language]) { req.push('/customize/translations/messages.' + language + '.js'); } req.push('/bower_components/jquery/dist/jquery.min.js'); @@ -109,12 +117,7 @@ define(req, function(Default, Language) { var $button = $(selector).find('button .buttonTitle'); // Select the current language in the list var option = $(selector).find('[data-value="' + language + '"]'); - if ($(option).length) { - $button.text($(option).text()); - } - else { - $button.text('English'); - } + selector.setValue(language || 'English'); // Listen for language change $(selector).find('a.languageValue').on('click', function () { diff --git a/customize.dist/privacy.html b/customize.dist/privacy.html index 403a0f1c4..6bc03746c 100644 --- a/customize.dist/privacy.html +++ b/customize.dist/privacy.html @@ -133,6 +133,7 @@
+ diff --git a/customize.dist/src/fragments/footer.html b/customize.dist/src/fragments/footer.html index de089102d..b1a69bb5e 100644 --- a/customize.dist/src/fragments/footer.html +++ b/customize.dist/src/fragments/footer.html @@ -39,4 +39,5 @@ + diff --git a/customize.dist/src/less/alertify.less b/customize.dist/src/less/alertify.less index c4bb60898..7f6622522 100644 --- a/customize.dist/src/less/alertify.less +++ b/customize.dist/src/less/alertify.less @@ -4,6 +4,9 @@ They are only displayed briefly */ .alertify-logs { + @media print { + visibility: hidden; + } > * { padding: @padding-base @padding-base * 4; color: @alertify-fore; @@ -58,10 +61,19 @@ } .dialog, .alert { + .bright { + color: @light-base; + } & > div { background-color: @alertify-dialog-bg; border-radius: 5px; + &.half { + width: 50%; + @media (max-width: @media-medium-screen) { + width: 100%; + } + } } width: 100%; @@ -133,6 +145,25 @@ border: 1px solid @alertify-base; border-radius: 5px; + &.safe, &.danger { + color: @old-base; + white-space: normal; + font-weight: bold; + } + &.danger { + background-color: @cp-red; + &:hover, &:active { + background-color: lighten(@cp-red, 5%); + } + } + + &.safe { + background-color: @cp-green; + &:hover, &:active { + background-color: lighten(@cp-green, 10%); + } + } + &:hover, &:active { background-color: @alertify-btn-bg-hover; } diff --git a/customize.dist/src/less/cryptpad.less b/customize.dist/src/less/cryptpad.less index 6e0f951fb..d7fcc98c4 100644 --- a/customize.dist/src/less/cryptpad.less +++ b/customize.dist/src/less/cryptpad.less @@ -494,12 +494,6 @@ noscript { } } -#fileManagerIframe { - width: 100%; - height: 500px; - margin-top: 15px; -} - /* buttons */ .create, .action { @@ -816,192 +810,6 @@ form.realtime, div.realtime { #adduser { .top-left; } #addoption { .bottom-left; } } - -// used for slides -.viewportRatio (@x, @y, @p: 100) { - width: @p * 100vw; - height: @y * (@p * 100vw) / @x; - max-width: @x / @y * (@p * 100vh); - max-height: (@p * 100vh); -} - -&.slide { - #modal { - .button { - position: absolute; - cursor: pointer; - font-size: 30px; - opacity: 0.6; - display: none; - } - .button:hover { - opacity: 1; - display: block !important; - } - #button_exit { - left: 20px; - top: 20px; - z-index: 9001; - } - #button_left { - left: 6vw; - bottom: 10vh; - } - #button_right { - right: 6vw; - bottom: 10vh; - } - } - #modal #content { - p, ul, ol { font-size: 26px; } - - img { - position: relative; - min-width: 1%; - max-width: 90%; - max-height: 90%; - margin: auto; - } - } -} - -div.modal, div#modal { - display: none; - - #content { - box-sizing: border-box; - border: 1px solid white; - - vertical-align: middle; - padding: 2.5vw; - - /* center things as much as possible - - margin-top: 50vh; - margin-bottom: 50vh; - transform: translateY(-50%); - - */ - - width: 100vw; - height: 56.25vw; // height:width ratio = 9/16 = .5625 - max-height: 100vh; - max-width: 177.78vh; // 16/9 = 1.778 - margin: auto; - position: absolute; - top:0;bottom:0; // vertical center - left:0;right:0; // horizontal center - - p, li, pre, code { - .size(2.75); - } - - h1 { .size(5); } - h2 { .size(4.2); } - h3 { .size(3.6); } - h4 { .size (3); } - h5 { .size(2.2); } - h6 { .size(1.6); } - - h1, h2, h3, h4, h5, h6 { - color: inherit; - } - - pre > code { - display: block; - position: relative; - border: 1px solid #333; - width: 90%; - margin: auto; - padding-left: .25vw; - } - - ul, ol { - min-width: 50%; - max-width: 100%; - display: table; - margin: 0 auto; - } - } - - box-sizing: border-box; - z-index: 9001; - position: fixed; - - top: 0px; - left: 0px; - - width: 100%; - height: 100vh; - display: none; - - background-color: @slide-default-bg; - - .center { - position: relative; - - width: 80%; - height: 80%; - margin: auto; - border: 1px solid @light-base; - - text-align: center; - } - - &.shown { - display: block; - } - - table { - margin: 30px; - - border-collapse: collapse; - tr { - td { - } - } - - input { - height: 100%; - width: 90%; - border: 3px solid @base; - } - - thead { - tr { - th { - span.remove { - } - } - } - } - tbody { - tr { - td { - - } - } - } - tfoot { - tr { - td { - z-index: 4000; - cursor: pointer; - } - } - } - } - - #addtime, - #adddate { - color: @cp-green; - border: 1px solid @cp-green; - padding: 15px; - } - - #adddate { .top-left; } - #addtime { .bottom-left; } -} } // hack for our cross-origin iframe diff --git a/customize.dist/src/less/dropdown.less b/customize.dist/src/less/dropdown.less index 0d915cf80..79a7edbec 100644 --- a/customize.dist/src/less/dropdown.less +++ b/customize.dist/src/less/dropdown.less @@ -57,6 +57,11 @@ background-color: #f1f1f1; color: black !important; } + + &.active { + background-color: #e8e8e8; + color: black !important; + } } hr { diff --git a/customize.dist/src/less/footer.less b/customize.dist/src/less/footer.less index a8711e132..8862bf951 100644 --- a/customize.dist/src/less/footer.less +++ b/customize.dist/src/less/footer.less @@ -18,4 +18,12 @@ font-size: 1.2em; font-weight: bold; } + div.version-footer { + background-color: @old-base; + color: @old-fore; + text-align: center; + width: 100%; + padding-top: 10px; + padding-bottom: 10px; + } } diff --git a/customize.dist/src/less/loading.less b/customize.dist/src/less/loading.less index fefc533fe..b48045622 100644 --- a/customize.dist/src/less/loading.less +++ b/customize.dist/src/less/loading.less @@ -16,6 +16,7 @@ .cryptofist { margin-left: auto; margin-right: auto; + height: 300px; @media screen and (max-height: @media-short-screen) { display: none; } @@ -28,4 +29,22 @@ } } } - +.cp #loadingTip { + position: fixed; + z-index: 99999; + top: 80%; + left: 0; + right: 0; + text-align: center; + span { + background-color: @bg-loading; + color: @color-loading; + text-align: center; + font-size: 1.5em; + opacity: 0.7; + font-family: lato, Helvetica, sans-serif; + padding: 15px; + max-width: 60%; + display: inline-block; + } +} diff --git a/customize.dist/src/less/toolbar.less b/customize.dist/src/less/toolbar.less index 8befac1ab..6f0177bc0 100644 --- a/customize.dist/src/less/toolbar.less +++ b/customize.dist/src/less/toolbar.less @@ -95,6 +95,7 @@ } button { + color: #000; background-color: inherit; background-image: linear-gradient(to bottom,#fff,#e4e4e4); border: 1px solid #A6A6A6; @@ -253,13 +254,12 @@ input { font-size: 1.5em; vertical-align: middle; - height: 100%; box-sizing: border-box; border: 1px solid black; background: #fff; cursor: auto; width: 300px; - padding: 0px 5px; + padding: 5px 5px; } } .cryptpad-link { @@ -312,6 +312,7 @@ //float: right; pre { white-space: pre; + margin: 0; } } button { diff --git a/customize.dist/terms.html b/customize.dist/terms.html index a92c99c93..35eae9467 100644 --- a/customize.dist/terms.html +++ b/customize.dist/terms.html @@ -116,6 +116,7 @@ + diff --git a/customize.dist/toolbar.css b/customize.dist/toolbar.css index e0e0bda64..fb297eae7 100644 --- a/customize.dist/toolbar.css +++ b/customize.dist/toolbar.css @@ -42,6 +42,10 @@ background-color: #f1f1f1; color: black !important; } +.dropdown-bar .dropdown-bar-content a.active { + background-color: #e8e8e8; + color: black !important; +} .dropdown-bar .dropdown-bar-content hr { margin: 5px 0px; height: 1px; @@ -164,6 +168,7 @@ margin-right: 2px; } .cryptpad-toolbar button { + color: #000; background-color: inherit; background-image: linear-gradient(to bottom, #fff, #e4e4e4); border: 1px solid #A6A6A6; @@ -324,13 +329,12 @@ .cryptpad-toolbar-top .cryptpad-title input { font-size: 1.5em; vertical-align: middle; - height: 100%; box-sizing: border-box; border: 1px solid black; background: #fff; cursor: auto; width: 300px; - padding: 0px 5px; + padding: 5px 5px; } .cryptpad-toolbar-top .cryptpad-link { position: absolute; @@ -374,6 +378,7 @@ } .cryptpad-toolbar-leftside .cryptpad-user-list pre { white-space: pre; + margin: 0; } .cryptpad-toolbar-leftside button { margin: 2px 4px 2px 0px; diff --git a/customize.dist/translations/messages.es.js b/customize.dist/translations/messages.es.js index 0c32903b7..7ca34e7c7 100644 --- a/customize.dist/translations/messages.es.js +++ b/customize.dist/translations/messages.es.js @@ -35,10 +35,8 @@ define(function () { out.orangeLight = "La conexión es lenta y podria impactar la experiencia"; out.redLight = "Has sido desconectado de la sesión"; - out.importButton = 'Importar'; out.importButtonTitle = 'Importar un documento de tus archivos locales'; - out.exportButton = 'Exportar'; out.exportButtonTitle = 'Exportar este documento a un archivo local'; out.exportPrompt = '¿Cómo te gustaría llamar a este archivo?'; @@ -46,22 +44,16 @@ define(function () { out.clickToEdit = "Haz clic para cambiar"; - out.forgetButton = 'Olvidar'; out.forgetButtonTitle = 'Eliminar este documento de la lista en la pagina de inicio'; out.forgetPrompt = 'Pulser OK eliminará este documento del almacenamiento local (localStorage), ¿estás seguro?'; out.shareButton = 'Compartir'; out.shareSuccess = 'URL copiada al portapapeles'; - out.presentButton = 'Presentar'; out.presentButtonTitle = "Entrar en el modo presentación"; out.presentSuccess = 'ESC para salir del modo presentación'; - out.sourceButton = 'Ver código fuente'; - out.sourceButtonTitle = "Abandonar modo presentación"; - out.backgroundButton = 'Color de fondo'; out.backgroundButtonTitle = 'Cambiar el color de fondo en el modo presentación'; - out.colorButton = 'Color de texto'; out.colorButtonTitle = 'Cambiar el color de texto en el modo presentación'; out.editShare = "URL de edición compartida"; @@ -88,7 +80,6 @@ define(function () { out.poll_p_save = "Tus configuraciones se actualizan instantaneamente, no es necesario guardar cambios."; out.poll_p_encryption = "Todos los datos entrados son cifrados, solo las personas que poseen el enlace tienen acceso. Incluso el servidor no puede ver el contenido."; - out.wizardButton = 'Asistente'; out.wizardLog = "Presiona el boton en la parte superior izquierda para volver a la encuesta"; out.wizardTitle = "Utiliza el asistente para crear tu encuesta"; out.wizardConfirm = "¿Estás realmente seguro de agregar estas opciones a tu encuesta?"; @@ -326,5 +317,35 @@ define(function () { out.readme_cat3_l2 = "Con los slides CryptPad, puedes hacer presentaciones rápidas con Markdown"; out.readme_cat3_l3 = "Con CryptPoll puedes tomar votos rápidos, especialmente utíl para programar un horario que conviene a todo el mundo"; - return out; + // 1.2.0 - Chupacabra + + out.settings_resetError = "Verificación no válida. Tu CryptDrive no fue cambiado."; + out.saved = "Guardado"; + out.printButton = "Imprimir"; + out.printButtonTitle = "Imprimir tu presentación o exportar a PDF"; + out.printOptions = "Opciones de impresión"; + out.printSlideNumber = "Mostrar el número de diapositiva"; + out.printDate = "Mostrar la fecha"; + out.printTitle = "Mostrar el título"; + out.printCSS = "CSS personalizado:"; + out.editOpen = "Abrir enlances de edición en pestaña nueva"; + out.editOpenTitle = "Abrir en modo edición en pestaña nueva"; + out.settings_importTitle = "Importar pads recientes locales en CryptDrive"; + out.settings_import = "Importar"; + out.settings_importConfirm = "¿Seguro qué quieres importar tus pads recientes a tu cuenta CryptDrive?"; + out.settings_importDone = "Importación terminada"; + + out.tips = {}; + out.tips.lag = "El icono verde en la parte superior derecha muestra la calidad de tu connexión a CryptPad."; + out.tips.shortcuts = "`ctrl+b`, `ctrl+i`, y `ctrl+u` son accesos rápidos para negrita, itálica y subrayado."; + out.tips.indent = "Cuando editas listas, puedes usar tab o shift+tab para icrementar o decrementar indentación."; + out.tips.title = "Puedes cambiar el título de tus pads en la parte superior de la pantalla."; + out.tips.store = "Cada vez que visitas un pad con una sesión iniciada se guardará a tu CryptDrive."; + out.tips.marker = "Puedes resaltar texto en un pad utilizando el \"marcador\" en el menú de estílo."; + + out.feedback_about = "Si estas leyendo esto, quizas estés curioso de saber porqué CryptPad solicita esta página cuando haces algunas acciones"; + out.feedback_privacy = "Nos importa tu privacidad, y al mismo tiempo queremos que CryptPad sea muy fácil de usar. Utilizamos esta página para conocer las funcionalidades que importan a nuestros usuarios, pidiendolo con un parametro que nos dice que accion fue realizada."; + out.feedback_optout = "Si quieres darte de baja, visita tus preferencias, donde podrás activar o desactivar feedback"; + +return out; }); diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 3bcd145de..9b40cfe35 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -25,6 +25,7 @@ define(function () { out.loading = "Chargement..."; out.error = "Erreur"; + out.saved = "Enregistré"; out.disconnected = 'Déconnecté'; out.synchronizing = 'Synchronisation'; @@ -48,10 +49,8 @@ define(function () { out.orangeLight = "Votre connexion est lente, ce qui réduit la qualité de l'éditeur"; out.redLight = "Vous êtes déconnectés de la session"; - out.importButton = 'Import'; out.importButtonTitle = 'Importer un pad depuis un fichier local'; - out.exportButton = 'Exporter'; out.exportButtonTitle = 'Exporter ce pad vers un fichier local'; out.exportPrompt = 'Comment souhaitez-vous nommer ce fichier ?'; @@ -62,7 +61,6 @@ define(function () { out.clickToEdit = 'Cliquer pour modifier'; - out.forgetButton = 'Supprimer'; out.forgetButtonTitle = 'Déplacer ce pad vers la corbeille'; out.forgetPrompt = 'Cliquer sur OK déplacera ce pad vers la corbeille de votre CryptDrive, êtes-vous sûr ?'; out.movedToTrash = 'Ce pad a été déplacé vers la corbeille.
Accéder à mon Drive'; @@ -73,20 +71,25 @@ define(function () { out.newButton = 'Nouveau'; out.newButtonTitle = 'Créer un nouveau pad'; - out.presentButton = 'Present'; out.presentButtonTitle = "Entrer en mode présentation"; out.presentSuccess = 'Appuyer sur Échap pour quitter le mode présentation'; - out.sourceButton = 'Voir la source'; - out.sourceButtonTitle = "Quitter le mode présentation"; - out.backgroundButton = 'Couleur de fond'; out.backgroundButtonTitle = 'Changer la couleur de fond de la présentation'; - out.colorButton = 'Couleur du texte'; out.colorButtonTitle = 'Changer la couleur du texte en mode présentation'; - out.editShare = "Partager le lien d'édition"; + out.printButton = "Imprimer"; + out.printButtonTitle = "Imprimer votre présentation ou l'enregistrer au format PDF"; + out.printOptions = "Options d'impression"; + out.printSlideNumber = "Afficher le numéro des slides"; + out.printDate = "Afficher la date"; + out.printTitle = "Afficher le titre du pad"; + out.printCSS = "Personnaliser l'apparence (CSS):"; + + out.editShare = "Lien d'édition"; out.editShareTitle = "Copier le lien d'édition dans le presse-papiers"; - out.viewShare = "Partager lien de lecture-seule"; + out.editOpen = "Éditer dans un nouvel onglet"; + out.editOpenTitle = "Ouvrir le lien d'édition dans un nouvel onglet"; + out.viewShare = "Lien de lecture-seule"; out.viewShareTitle = "Copier lien d'accès en lecture seule dans le presse-papiers"; out.viewOpen = "Voir dans un nouvel onglet"; out.viewOpenTitle = "Ouvrir le lien en lecture seule dans un nouvel onglet"; @@ -108,7 +111,6 @@ define(function () { out.poll_p_save = "Vos modifications sont mises à jour instantanément, donc vous n'avez jamais besoin de sauver le contenu."; out.poll_p_encryption = "Tout ce que vous entrez est chiffré donc seules les personnes possédant le lien du sondage y ont accès. Même le serveur ne peut pas voir le contenu."; - out.wizardButton = 'Assistant'; out.wizardLog = "Cliquez sur le bouton dans le coin supérieur gauche pour retourner au sondage"; out.wizardTitle = "Utiliser l'assistant pour créer votre sondage"; out.wizardConfirm = "Êtes-vous vraiment prêt à ajouter ces options au sondage ?"; @@ -223,10 +225,13 @@ define(function () { out.register_importRecent = "Importer l'historique (Recommendé)"; out.register_acceptTerms = "J'accepte les conditions d'utilisation"; - out.register_rememberPassword = "Je vais me souvenir de mes identifiants"; out.register_passwordsDontMatch = "Les mots de passe doivent être identiques!"; out.register_mustAcceptTerms = "Vous devez accepter les conditions d'utilisation."; out.register_mustRememberPass = "Nous ne pouvons pas réinitialiser votre mot de passe si vous l'oubliez. C'est important que vous vous en souveniez! Veuillez cocher la case pour confirmer."; + out.register_writtenPassword = "J'ai bien noté mon nom d'utilisateur et mon mot de passe, continuer"; + out.register_cancel = "Retour"; + out.register_warning = "Zero Knowledge signifie que nous ne pouvons pas récupérer vos données si vous perdez vos identifiants."; + out.register_alreadyRegistered = "Cet utilisateur existe déjà, souhaitez-vous vous connecter ?"; out.register_header = "Bienvenue dans CryptPad"; out.register_explanation = [ @@ -250,10 +255,16 @@ define(function () { "Êtes-vous sûr de vouloir continuer ?
" + "Tapez “I love CryptPad” pour confirmer."; out.settings_resetDone = "Votre drive est désormais vide!"; + out.settings_resetError = "Texte de vérification incorrect. Votre CryptDrive n'a pas été modifié."; out.settings_resetTips = "Astuces et informations dans CryptDrive"; out.settings_resetTipsButton = "Réinitialiser les astuces visibles dans CryptDrive"; out.settings_resetTipsDone = "Toutes les astuces sont de nouveau visibles."; + out.settings_importTitle = "Importer les pads récents de ce navigateur dans mon CryptDrive"; + out.settings_import = "Importer"; + out.settings_importConfirm = "Êtes-vous sûr de vouloir importer les pads récents de ce navigateur dans le CryptDrive de votre compte utilisateur ?"; + out.settings_importDone = "Importation terminée"; + out.settings_userFeedbackHint1 = "CryptPad peut envoyer des retours d'expérience très limités vers le serveur, de manière à nous permettre d'améliorer l'expérience des utilisateurs."; out.settings_userFeedbackHint2 = "Le contenu de vos pads et les clés de déchiffrement ne seront jamais partagés avec le serveur."; out.settings_userFeedback = "Activer l'envoi de retours d'expérience"; @@ -306,7 +317,6 @@ define(function () { out.policy_whatweknow = 'Ce que nous savons de vous'; out.policy_whatweknow_p1 = 'En tant qu\'application hébergée sur le web, CryptPad a accès aux meta-données exposées par le protocole HTTP. Ceci inclus votre adresse IP et d\'autres en-têtes HTTP qui peuvent être utilisées pour identifier votre propre navigateur. Vous pouvez voir quelles informations votre navigateur partage en visitant WhatIsMyBrowser.com.'; out.policy_whatweknow_p2 = 'Nous utilisons Piwik, une plateforme open source d\'analytique, afin d\'en apprendre plus sur nos utilisateurs. Piwik nous indique comment vous avez trouvé CryptPad, que ce soit par une entrée directe, par un moteur de recherche ou depuis un lien provenant d\'un autre site web tel que Reddit ou Twitter. Nous savons également quand vous visitez le site, sur quels liens vous cliquez dans les pages informatives et combien de temps vous restez sur une page donnée.'; - out.policy_whatweknow_p3 = 'Ces outils d\'analytique sont utilisés uniquement sur les pages informatives. Nous ne collectons aucune information concernant votre utilisation de nos applications "zero knowledge".'; out.policy_howweuse = 'Comment nous utilisons ce que nous apprenons'; out.policy_howweuse_p1 = 'Nous utilisons ces informations pour prendre de meilleures décisions concernant la communication autour de CryptPad, en évaluant le succès de ce qui a été realisé par le passé. Les informations concernant votre localisation nous permettent de savoir si nous devons considérer l\'ajout de traductions de CryptPad dans d\'autres langues que l\'anglais.'; out.policy_howweuse_p2 = "Les informations concernant votre navigateur (que ce soit un système d\'exploitation de bureau ou d\'appareil portable) nous aident à prendre des décisions lors de la priorisation des ajouts et améliorations de fonctionnalités. Notre équipe de développement est petite, et nous essayons de prendre des décisions qui amélioreront l\'expérience du plus grand nombre d\'utilisateurs possible."; @@ -357,13 +367,23 @@ define(function () { '', '

', ].join(''); + out.initialState = [ + '

', + 'Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge. Tout est sauvegardé dés que vous le tapez.', + '
', + 'Partagez le lien vers ce pad avec des amis ou utilisez le bouton  Partager  pour obtenir le lien de lecture-seule, qui permet la lecture mais non la modification.', + '

', + '

', + '', + 'Lancez-vous, commencez à taper...', + '

' + ].join(''); out.codeInitialState = [ '/*\n', - ' Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge.\n', + ' Voici l\'éditeur de code collaboratif et Zero Knowledge de CryptPad.\n', ' Ce que vous tapez ici est chiffré de manière que seules les personnes avec le lien peuvent y accéder.\n', - ' Même le serveur est incapable de voir ce que vous tapez.\n', - ' Ce que vous voyez ici, ce que vous entendez, quand vous partez, ça reste ici.\n', + ' Vous pouvez choisir le langage de programmation pour la coloration syntaxique, ainsi que le thème de couleurs, dans le coin supérieur droit.\n', '*/' ].join(''); @@ -405,5 +425,18 @@ define(function () { out.readme_cat3_l2 = "Avec l'éditeur de présentations de CryptPad, vous pouvez réaliser des présentations rapides en utilisant Markdown"; out.readme_cat3_l3 = "Avec CryptPoll vous pouvez créer rapidement des sondages, et en particulier plannifier des meetings qui rentrent dans l'agenda de tout ceux qui souhaitent participer."; + // Tips + out.tips = {}; + out.tips.lag = "L'icône verte dans le coin supérieur droit montre la qualité de votre connexion Internet vers le serveur CryptPad."; + out.tips.shortcuts = "`ctrl+b`, `ctrl+i` et `ctrl+u` sont des raccourcis rapides pour mettre en gras, en italique ou souligner."; + out.tips.indent = "Dans les listes à puces ou numérotées, vous pouvez utiliser `Tab` ou `Maj+Tab` pour augmenter ou réduire rapidement l'indentation."; + out.tips.title = "Vous pouvez changer le titre de votre pad en cliquant au centre en haut de la page."; + out.tips.store = "Dés que vous ouvrez un nouveau pad, il est automatiquement stocké dans votre CryptDrive si vous êtes connectés."; + out.tips.marker = "Vous pouvez surligner du texte dans un pad en utilisant l'option \"marker\" dans le menu déroulant des styles."; + + out.feedback_about = "Si vous lisez ceci, vous vous demandez probablement pourquoi CryptPad envoie des requêtes vers des pages web quand vous realisez certaines actions."; + out.feedback_privacy = "Nous prenons au sérieux le respect de votre vie privée, et en même temps nous souhaitons rendre CryptPad très simple à utiliser. Nous utilisons cette page pour comprendre quelles foncitonnalités dans l'interface comptent le plus pour les utilisateurs, en l'appelant avec un paramètre spécifiant quelle action a été réalisée."; + out.feedback_optout = "Si vous le souhaitez, vous pouvez désactiver ces requêtes en vous rendant dans votre page de préférences, où vous trouverez une case à cocher pour désactiver le retour d'expérience."; + return out; }); diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 172371032..7395cdb96 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -27,6 +27,7 @@ define(function () { out.loading = "Loading..."; out.error = "Error"; + out.saved = "Saved"; out.disconnected = 'Disconnected'; out.synchronizing = 'Synchronizing'; @@ -50,10 +51,8 @@ define(function () { out.orangeLight = "Your slow connection may impact your experience"; out.redLight = "You are disconnected from the session"; - out.importButton = 'IMPORT'; out.importButtonTitle = 'Import a pad from a local file'; - out.exportButton = 'EXPORT'; out.exportButtonTitle = 'Export this pad to a local file'; out.exportPrompt = 'What would you like to name your file?'; @@ -64,7 +63,6 @@ define(function () { out.clickToEdit = "Click to edit"; - out.forgetButton = 'FORGET'; out.forgetButtonTitle = 'Move this pad to the trash'; out.forgetPrompt = 'Clicking OK will move this pad to your trash. Are you sure?'; out.movedToTrash = 'That pad has been moved to the trash.
Access my Drive'; @@ -75,22 +73,27 @@ define(function () { out.newButton = 'New'; out.newButtonTitle = 'Create a new pad'; - out.presentButton = 'PRESENT'; out.presentButtonTitle = "Enter presentation mode"; out.presentSuccess = 'Hit ESC to exit presentation mode'; - out.sourceButton = 'VIEW SOURCE'; //TODO remove? hidden behind the present mode - out.sourceButtonTitle = "Leave presentation mode"; - out.backgroundButton = 'BACKGROUND COLOR'; out.backgroundButtonTitle = 'Change the background color in the presentation'; - out.colorButton = 'TEXT COLOR'; out.colorButtonTitle = 'Change the text color in presentation mode'; + out.printButton = "Print"; + out.printButtonTitle = "Print your slides or export them as a PDF file"; + out.printOptions = "Print options"; + out.printSlideNumber = "Display the slide number"; + out.printDate = "Display the date"; + out.printTitle = "Display the pad title"; + out.printCSS = "Custom style rules (CSS):"; + out.editShare = "Editing link"; - out.editShareTitle = "Copy the edit link to clipboard"; + out.editShareTitle = "Copy the editing link to clipboard"; + out.editOpen = "Open editing link in a new tab"; + out.editOpenTitle = "Open this pad in editing mode in a new tab"; out.viewShare = "Read-only link"; out.viewShareTitle = "Copy the read-only link to clipboard"; - out.viewOpen = "Open read-only link in new tab"; + out.viewOpen = "Open read-only link in a new tab"; out.viewOpenTitle = "Open this pad in read-only mode in a new tab"; out.notifyJoined = "{0} has joined the collaborative session"; @@ -99,7 +102,7 @@ define(function () { out.okButton = 'OK (enter)'; - out.cancel = "Cancel"; // Not used? + out.cancel = "Cancel"; out.cancelButton = 'Cancel (esc)'; // Polls @@ -110,7 +113,6 @@ define(function () { out.poll_p_save = "Your settings are updated instantly, so you never need to save."; out.poll_p_encryption = "All your input is encrypted so only people who have the link can access it. Even the server cannot see what you change."; - out.wizardButton = 'WIZARD'; out.wizardLog = "Click the button in the top left to return to your poll"; out.wizardTitle = "Use the wizard to create your poll"; out.wizardConfirm = "Are you really ready to add these options to your poll?"; @@ -225,7 +227,6 @@ define(function () { out.register_importRecent = "Import pad history (Recommended)"; out.register_acceptTerms = "I accept the terms of service"; - out.register_rememberPassword = "I will remember my login name and password"; out.register_passwordsDontMatch = "Passwords do not match!"; out.register_mustAcceptTerms = "You must accept the terms of service."; out.register_mustRememberPass = "We cannot reset your password if you forget it. It's very important that you remember it! Please check the checkbox to confirm."; @@ -240,6 +241,13 @@ define(function () { "" ].join(''); + out.register_writtenPassword = "I have written down my username and password, proceed"; + out.register_cancel = "Go back"; + + out.register_warning = "Zero Knowledge means that we can't recover your data if you lose your password."; + + out.register_alreadyRegistered = "This user already exists, do you want to log in?"; + // Settings out.settings_title = "Settings"; out.settings_save = "Save"; @@ -252,10 +260,16 @@ define(function () { "Are you sure you want to continue?
" + "Type “I love CryptPad” to confirm."; out.settings_resetDone = "Your drive is now empty!"; + out.settings_resetError = "Incorrect verification text. Your CryptDrive has not been changed."; out.settings_resetTips = "Tips in CryptDrive"; out.settings_resetTipsButton = "Reset the available tips in CryptDrive"; out.settings_resetTipsDone = "All the tips are now visible again."; + out.settings_importTitle = "Import this browser's recent pads in my CryptDrive"; + out.settings_import = "Import"; + out.settings_importConfirm = "Are you sure you want to import recent pads from this browser to your user account's CryptDrive?"; + out.settings_importDone = "Import completed"; + out.settings_userFeedbackHint1 = "CryptPad provides some very basic feedback to the server, to let us know how to improve your experience."; out.settings_userFeedbackHint2 = "Your pad's content will never be shared with the server."; out.settings_userFeedback = "Enable user feedback"; @@ -351,26 +365,22 @@ define(function () { // Initial states out.initialState = [ - '

', - 'This is CryptPad, the zero knowledge realtime collaborative editor.', + '

', + 'This is CryptPad, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.', '
', - 'What you type here is encrypted so only people who have the link can access it.', - '
', - 'Even the server cannot see what you type.', - '

', - '

', - '', - 'What you see here, what you hear here, when you leave here, let it stay here', - '', + 'Share the link to this pad to edit with friends or use the  Share  button to share a read-only link which allows viewing but not editing.', '

', + + '

', + 'Go ahead, just start typing...', + '

' ].join(''); out.codeInitialState = [ '/*\n', - ' This is CryptPad, the zero knowledge realtime collaborative editor.\n', + ' This is the CryptPad Zero Knowledge collaborative code editor.\n', ' What you type here is encrypted so only people who have the link can access it.\n', - ' Even the server cannot see what you type.\n', - ' What you see here, what you hear here, when you leave here, let it stay here.\n', + ' You can choose the programming language to highlight and the UI color scheme in the upper right.\n', '*/' ].join(''); @@ -391,6 +401,8 @@ define(function () { ' - Your slides are updated in realtime' ].join(''); + // Readme + out.driveReadmeTitle = "What is CryptDrive?"; out.readme_welcome = "Welcome to CryptPad !"; out.readme_p1 = "Welcome to CryptPad, this is where you can take note of things alone and with friends."; @@ -412,5 +424,18 @@ define(function () { out.readme_cat3_l2 = "With CryptPad slide editor, you can make quick presentations using Markdown"; out.readme_cat3_l3 = "With CryptPoll you can take quick votes, especially for scheduling meetings which fit with everybody's calendar"; + // Tips + out.tips = {}; + out.tips.lag = "The green icon in the upper right shows the quality of your internet connection to the CryptPad server."; + out.tips.shortcuts = "`ctrl+b`, `ctrl+i` and `ctrl+u` are quick shortcuts for bold, italic and underline."; + out.tips.indent = "In numbered and bulleted lists, you can use tab or shift+tab to quickly increase or decrease indentation."; + out.tips.title = "You can set the title of your pad by clicking the top center."; + out.tips.store = "Every time you visit a pad, if you're logged in it will be saved to your CryptDrive."; + out.tips.marker = "You can highlight text in a pad using the \"marker\" item in the styles dropdown menu."; + + out.feedback_about = "If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions"; + out.feedback_privacy = "We care about your privacy, and at the same time we want CryptPad to be very easy to use. We use this file to figure out which UI features matter to our users, by requesting it along with a parameter specifying which action was taken."; + out.feedback_optout = "If you would like to opt out, visit your user settings page, where you'll find a checkbox to enable or disable user feedback"; + return out; }); diff --git a/package.json b/package.json index ba331a899..4b71a0ba4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", - "version": "1.1.1", + "version": "1.2.0", "dependencies": { "express": "~4.10.1", "ws": "^1.0.1", @@ -16,7 +16,7 @@ "scripts": { "lint": "jshint --config .jshintrc --exclude-path .jshintignore .", "test": "node TestSelenium.js", - "style": "lessc ./customize.dist/src/less/cryptpad.less > ./customize.dist/main.css && lessc ./customize.dist/src/less/toolbar.less > ./customize.dist/toolbar.css && lessc ./www/drive/file.less > ./www/drive/file.css && lessc ./www/settings/main.less > ./www/settings/main.css", + "style": "lessc ./customize.dist/src/less/cryptpad.less > ./customize.dist/main.css && lessc ./customize.dist/src/less/toolbar.less > ./customize.dist/toolbar.css && lessc ./www/drive/file.less > ./www/drive/file.css && lessc ./www/settings/main.less > ./www/settings/main.css && lessc ./www/slide/slide.less > ./www/slide/slide.css", "template": "cd customize.dist/src && node build.js" } } diff --git a/readme.md b/readme.md index 083d44431..9988ff344 100644 --- a/readme.md +++ b/readme.md @@ -35,13 +35,18 @@ bower install ## copy config.js.dist to config.js cp config.js.dist config.js -## modify configuration to use your own mongodb instance -## for example aon the default mongodb port `mongodb://localhost:27017/demo_database` -$EDITOR config.js - node ./server.js ``` +## Configuration + +CryptPad _should_ work with an unmodified configuration file, though there are many things which you may want to customize. +Attributes in the config should have comments indicating how they are used. + +``` +$EDITOR config.js +``` + ## Maintenance To get access to the most recent codebase: @@ -63,18 +68,20 @@ npm update; To reset your instance of Cryptpad and remove all the data that is being stored: -If you are using the leveldb adaptor, this is as simple as deleting the folder which contains your leveldb datastore: + ``` -# change into your cryptpade directory +# change into your cryptpad directory cd /your/cryptpad/instance/location; # delete the datastore -rm -rf ./cryptpad.db +rm -rf ./datastore ``` If you are using the mongodb adaptor, [drop the relevant collection](https://docs.mongodb.org/manual/reference/method/db.collection.drop/#db.collection.drop). +If you are using the [leveldb adaptor](https://github.com/xwiki-labs/cryptpad-level-store), delete the datastore directory you have configured. + ## Testing To test CryptPad, go to http://your.server:3000/assert/ @@ -82,6 +89,16 @@ 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`. +## Developing CryptPad + +CryptPad is built with a lot of small javascript libraries. +To make js files load faster, we apply an aggressive caching policy. + +If you want to add new features to CryptPad, you'll want to turn off caching. +You can do so by launching your server in _dev mode_, like so: + +`DEV=1 node server.js` + # Setup using Docker See [Cryptpad-Docker](cryptpad-docker.md) @@ -108,14 +125,14 @@ Still there are other low-lives in the world so using CryptPad over HTTPS is pro ## Translations We'd like to make it easy for more people to use encryption in their routine activities. -As such, we've tried to make language-specific parts of Cryptpad translatable. If you're -able to translate Cryptpad's interface, and would like to help, please contact us! +As such, we've tried to make language-specific parts of CryptPad translatable. If you're +able to translate CryptPad's interface, and would like to help, please contact us! You can also see [our translation guide](/customize.dist/translations/README.md). ## Contacting Us -You can reach members of the Cryptpad development team on [twitter](https://twitter.com/cryptpad), +You can reach members of the CryptPad development team on [twitter](https://twitter.com/cryptpad), via our [github issue tracker](https://github.com/xwiki-labs/cryptpad/issues/), on the [freenode](http://webchat.freenode.net/?channels=%23cryptpad&uio=MT1mYWxzZSY5PXRydWUmMTE9Mjg3JjE1PXRydWUe7) irc network, or by [email](mailto:research@xwiki.com). @@ -137,11 +154,9 @@ published by the Free Software Foundation, either version 3 of the License, or ( any later version. If you wish to use this technology in a proprietary product, please contact sales@xwiki.com -* Icons thanks to http://www.famfamfam.com/ licensed [Creative Commons Attribution 2.5 License] - - [ChainPad]: https://github.com/xwiki-contrib/chainpad [CKEditor]: http://ckeditor.com/ [fragment identifier]: https://en.wikipedia.org/wiki/Fragment_identifier [active attack]: https://en.wikipedia.org/wiki/Attack_(computing)#Types_of_attacks [Creative Commons Attribution 2.5 License]: http://creativecommons.org/licenses/by/2.5/ + diff --git a/server.js b/server.js index 503558c1f..34f8cfedf 100644 --- a/server.js +++ b/server.js @@ -20,6 +20,11 @@ var app = Express(); var httpsOpts; +var DEV_MODE = !!process.env.DEV +if (DEV_MODE) { + console.log("DEV MODE ENABLED"); +} + const clone = (x) => (JSON.parse(JSON.stringify(x))); var setHeaders = (function () { @@ -96,7 +101,7 @@ app.get('/api/config', function(req, res){ res.send('define(' + JSON.stringify({ requireConf: { waitSeconds: 60, - urlArgs: 'ver=' + Package.version + urlArgs: 'ver=' + Package.version + (DEV_MODE? '-' + (+new Date()): ''), }, websocketPath: config.useExternalWebsocket ? undefined : config.websocketPath, websocketURL:'ws' + ((useSecureWebsockets) ? 's' : '') + '://' + host + ':' + diff --git a/www/code/index.html b/www/code/index.html index af6247a40..a3f943078 100644 --- a/www/code/index.html +++ b/www/code/index.html @@ -11,6 +11,7 @@ data-main-favicon="/customize/main-favicon.png" data-alt-favicon="/customize/alt-favicon.png" id="favicon" /> + -

If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions.

-

We care about your privacy, and at the same time we want CryptPad to be very easy to use. +

If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions.

+

We care about your privacy, and at the same time we want CryptPad to be very easy to use. We use this file to figure out which UI features matter to our users, by requesting it along with a parameter specifying which action was taken.

-

If you would like to opt out, visit your user settings page, where you'll find a checkbox to enable or disable user feedback

+

If you would like to opt out, visit your user settings page, where you'll find a checkbox to enable or disable user feedback

diff --git a/www/common/fileObject.js b/www/common/fileObject.js index d8f10ced4..43ba5c3e5 100644 --- a/www/common/fileObject.js +++ b/www/common/fileObject.js @@ -6,10 +6,10 @@ define([ var Messages = {}; - var ROOT = "root"; - var UNSORTED = "unsorted"; - var TRASH = "trash"; - var TEMPLATE = "template"; + var ROOT = module.ROOT = "root"; + var UNSORTED = module.UNSORTED = "unsorted"; + var TRASH = module.TRASH = "trash"; + var TEMPLATE = module.TEMPLATE = "template"; var init = module.init = function (files, config) { var Cryptpad = config.Cryptpad; @@ -232,15 +232,95 @@ define([ return ret; }; - var getFilesDataFiles = function () { + var getFilesDataFiles = exp.getFilesDataFiles = function () { var ret = []; - for (var el in files[FILES_DATA]) { + files[FILES_DATA].forEach(function (el) { if (el.href && ret.indexOf(el.href) === -1) { ret.push(el.href); } + }); + return ret; + }; + + var _findFileInRoot = function (path, href) { + if (path[0] !== ROOT && path[0] !== TRASH) { return []; } + var paths = []; + var root = exp.findElement(files, path); + var addPaths = function (p) { + if (paths.indexOf(p) === -1) { + paths.push(p); + } + }; + + if (isFile(root)) { + if (compareFiles(href, root)) { + if (paths.indexOf(path) === -1) { + paths.push(path); + } + } + return paths; + } + for (var e in root) { + var nPath = path.slice(); + nPath.push(e); + _findFileInRoot(nPath, href).forEach(addPaths); + } + + return paths; + }; + var _findFileInHrefArray = function (rootName, href) { + var unsorted = files[rootName].slice(); + var ret = []; + var i = -1; + while ((i = unsorted.indexOf(href, i+1)) !== -1){ + ret.push([rootName, i]); } return ret; }; + var _findFileInTrash = function (path, href) { + var root = exp.findElement(files, path); + var paths = []; + var addPaths = function (p) { + if (paths.indexOf(p) === -1) { + paths.push(p); + } + }; + if (path.length === 1) { + Object.keys(root).forEach(function (key) { + var arr = root[key]; + if (!Array.isArray(arr)) { return; } + var nPath = path.slice(); + nPath.push(key); + _findFileInTrash(nPath, href).forEach(addPaths); + }); + } + if (path.length === 2) { + if (!Array.isArray(root)) { return []; } + root.forEach(function (el, i) { + var nPath = path.slice(); + nPath.push(i); + nPath.push('element'); + if (isFile(el.element)) { + if (compareFiles(href, el.element)) { + addPaths(nPath); + } + return; + } + _findFileInTrash(nPath, href).forEach(addPaths); + }); + } + if (path.length >= 4) { + _findFileInRoot(path, href).forEach(addPaths); + } + return paths; + }; + var findFile = exp.findFile = function (href) { + var rootpaths = _findFileInRoot([ROOT], href); + var unsortedpaths = _findFileInHrefArray(UNSORTED, href); + var templatepaths = _findFileInHrefArray(TEMPLATE, href); + var trashpaths = _findFileInTrash([TRASH], href); + return rootpaths.concat(unsortedpaths, templatepaths, trashpaths); + }; // Remove the selected 'href' from the tree located at 'path', and push its locations to the 'paths' array var removeFileFromRoot = function (path, href) { @@ -374,7 +454,6 @@ define([ var parentEl = exp.findElement(files, parentPath); // Trash root: we have array here, we can't just splice with the path otherwise we might break the path // of another element in the loop - console.log(path); if (path.length === 4) { trashRoot.push({ name: path[1], @@ -573,7 +652,6 @@ define([ // Import elements in the file manager var importElements = exp.importElements = function (elements, path, cb) { if (!elements || elements.length === 0) { return; } - console.log(elements); var newParent = findElement(files, path); if (!newParent) { debug("Trying to import elements into a non-existing folder"); return; } elements.forEach(function (e) { @@ -670,7 +748,7 @@ define([ }; // Delete permanently (remove from the trash root and from filesData) - var removeFromTrash = exp.removeFromTrash = function (path, cb) { + var removeFromTrash = exp.removeFromTrash = function (path, cb, nocheck) { if (!path || path.length < 4 || path[0] !== TRASH) { return; } // Remove the last element from the path to get the parent path and the element name var parentPath = path.slice(); @@ -691,7 +769,9 @@ define([ parentEl[name] = undefined; delete parentEl[name]; } - checkDeletedFiles(); + if (!nocheck) { + checkDeletedFiles(); + } if(cb) { cb(); } }; @@ -773,7 +853,7 @@ define([ pushToTrash(key, href, path); }; - var addUnsortedPad = exp.addPad = function (href, path, name) { + var addPad = exp.addPad = function (href, path, name) { if (workgroup) { return; } if (!href) { return; } var unsortedFiles = getUnsortedFiles(); @@ -798,10 +878,54 @@ define([ } } if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1 && templateFiles.indexOf(href) === -1 && trashFiles.indexOf(href) === -1) { + console.log('push', href); files[UNSORTED].push(href); } }; + var replaceFile = function (path, o, n) { + var root = exp.findElement(files, path); + + if (isFile(root)) { return; } + for (var e in root) { + if (isFile(root[e])) { + if (compareFiles(o, root[e])) { + root[e] = n; + } + } else { + var nPath = path.slice(); + nPath.push(e); + replaceFile(nPath, o, n); + } + } + }; + + // Replace a href by a stronger one everywhere in the drive (except FILES_DATA) + var replaceHref = exp.replaceHref = function (o, n) { + if (!isFile(o) || !isFile(n)) { return; } + var paths = findFile(o); + + // Remove all the occurences in the trash + // Replace all the occurences not in the trash + // If all the occurences are in the trash or no occurence, add the pad to unsorted + var allInTrash = true; + paths.forEach(function (p) { + if (p[0] === TRASH) { + removeFromTrash(p, null, true); // 3rd parameter means skip "checkDeletedFiles" + return; + } else { + allInTrash = false; + var parentPath = p.slice(); + var key = parentPath.pop(); + var parentEl = findElement(files, parentPath); + parentEl[key] = n; + } + }); + if (allInTrash) { + addPad(n); + } + }; + // addTemplate is called when we want to add a new pad, never visited, to the templates list // first, we must add it to FILES_DATA, so the input has to be an fileDAta object var addTemplate = exp.addTemplate = function (fileData) { diff --git a/customize.dist/fsStore.js b/www/common/fsStore.js similarity index 97% rename from customize.dist/fsStore.js rename to www/common/fsStore.js index fbf7a5719..8f2405643 100644 --- a/customize.dist/fsStore.js +++ b/www/common/fsStore.js @@ -119,6 +119,10 @@ define([ return filesOp.getStructure(); }; + ret.replaceHref = function (o, n) { + return filesOp.replaceHref(o, n); + }; + var changeHandlers = ret.changeHandlers = []; ret.change = function (f) {}; @@ -127,9 +131,10 @@ define([ }; var onReady = function (f, proxy, Cryptpad, exp) { - var fo = FO.init(proxy.drive, { + var fo = exp.fo = FO.init(proxy.drive, { Cryptpad: Cryptpad }); + //storeObj = proxy; store = initStore(fo, proxy, exp); if (typeof(f) === 'function') { diff --git a/www/common/login.js b/www/common/login.js index 99678b1dd..7576ff4d4 100644 --- a/www/common/login.js +++ b/www/common/login.js @@ -94,17 +94,21 @@ define([ res.realtime = rt.realtime; res.network = rt.network; + // they're registering... + res.userHash = opt.userHash; + res.userName = uname; + // they tried to just log in but there's no such user if (!isRegister && isProxyEmpty(rt.proxy)) { rt.network.disconnect(); // clean up after yourself return void cb('NO_SUCH_USER', res); } - // they're registering... - - res.userHash = opt.userHash; - res.userName = uname; - //res.displayName // TODO + // they tried to register, but those exact credentials exist + if (isRegister && !isProxyEmpty(rt.proxy)) { + rt.network.disconnect(); + return void cb('ALREADY_REGISTERED', res); + } cb(void 0, res); }); diff --git a/www/common/mergeDrive.js b/www/common/mergeDrive.js new file mode 100644 index 000000000..f056fedee --- /dev/null +++ b/www/common/mergeDrive.js @@ -0,0 +1,198 @@ +require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } }); +define([ + '/common/cryptpad-common.js', + '/common/cryptget.js', + '/common/fileObject.js', + 'json.sortify' +], function (Cryptpad, Crypt, FO, Sortify) { + var exp = {}; + + var getType = function (el) { + if (el === null) { return "null"; } + return Array.isArray(el) ? "array" : typeof(el); + }; + + var findAvailableKey = function (obj, key) { + if (typeof (obj[key]) === "undefined") { return key; } + var i = 1; + var nkey = key; + while (typeof (obj[nkey]) !== "undefined") { + nkey = key + '_' + i; + i++; + } + return nkey; + }; + + var copy = function (el) { + if (typeof (el) !== "object") { return el; } + return JSON.parse(JSON.stringify(el)); + }; + + var deduplicate = function (array) { + var a = array.slice(); + for(var i=0; i', {'class': 'fa fa-share-alt'}); - var $span = $('', {'class': 'large'}).append(' ' +Messages.shareButton); - var dropdownConfigShare = { - text: $('
').append($shareIcon).append($span).html(), - options: [] - }; - var $shareBlock = Cryptpad.createDropdown(dropdownConfigShare); - $shareBlock.find('button').attr('id', 'shareButton'); - $shareBlock.find('.dropdown-bar-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS); - $userlistElement.append($shareBlock); + var secret = Cryptpad.find(config, ['share', 'secret']); + var channel = Cryptpad.find(config, ['share', 'channel']); + if (!secret || !channel) { + throw new Error("Unable to display the share button: share.secret and share.channel required"); + } + Cryptpad.getRecentPads(function (err, recent) { + var $shareIcon = $('', {'class': 'fa fa-share-alt'}); + var $span = $('', {'class': 'large'}).append(' ' +Messages.shareButton); + var hashes = Cryptpad.getHashes(channel, secret); + var options = []; + + // If we have a stronger version in drive, add it and add a redirect button + var stronger = recent && Cryptpad.findStronger(null, recent); + if (stronger) { + var parsed = Cryptpad.parsePadUrl(stronger); + hashes.editHash = parsed.hash; + } + + if (hashes.editHash) { + options.push({ + tag: 'a', + attributes: {title: Messages.editShareTitle, 'class': 'editShare'}, + content: ' ' + Messages.editShare + }); + if (stronger) { + // We're in view mode, display the "open editing link" button + options.push({ + tag: 'a', + attributes: { + title: Messages.editOpenTitle, + 'class': 'editOpen', + href: window.location.pathname + '#' + hashes.editHash, + target: '_blank' + }, + content: ' ' + Messages.editOpen + }); + } + options.push({tag: 'hr'}); + } + if (hashes.viewHash) { + options.push({ + tag: 'a', + attributes: {title: Messages.viewShareTitle, 'class': 'viewShare'}, + content: ' ' + Messages.viewShare + }); + if (hashes.editHash && !stronger) { + // We're in edit mode, display the "open readonly" button + options.push({ + tag: 'a', + attributes: { + title: Messages.viewOpenTitle, + 'class': 'viewOpen', + href: window.location.pathname + '#' + hashes.viewHash, + target: '_blank' + }, + content: ' ' + Messages.viewOpen + }); + } + } + var dropdownConfigShare = { + text: $('
').append($shareIcon).append($span).html(), + options: options + }; + var $shareBlock = Cryptpad.createDropdown(dropdownConfigShare); + $shareBlock.find('button').attr('id', 'shareButton'); + $shareBlock.find('.dropdown-bar-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS); + $userlistElement.append($shareBlock); + + if (hashes.editHash) { + $shareBlock.find('a.editShare').click(function () { + var url = window.location.origin + window.location.pathname + '#' + hashes.editHash; + var success = Cryptpad.Clipboard.copy(url); + if (success) { Cryptpad.log(Messages.shareSuccess); } + }); + } + if (hashes.viewHash) { + $shareBlock.find('a.viewShare').click(function () { + var url = window.location.origin + window.location.pathname + '#' + hashes.viewHash; + var success = Cryptpad.Clipboard.copy(url); + if (success) { Cryptpad.log(Messages.shareSuccess); } + }); + } + }); } }; @@ -223,7 +296,7 @@ define([ } if (anonymous > 0) { var text = anonymous === 1 ? Messages.anonymousUser : Messages.anonymousUsers; - $editUsers.push('' + anonymous + ' ' + text + ''); + $editUsers.append('' + anonymous + ' ' + text + ''); } if (numberOfViewUsers > 0) { var viewText = ''; diff --git a/www/drive/file.css b/www/drive/file.css index 0013e063c..c2fa83b65 100644 --- a/www/drive/file.css +++ b/www/drive/file.css @@ -66,6 +66,7 @@ li { .contextMenu { display: none; position: absolute; + z-index: 50; } .contextMenu li { padding: 0; @@ -81,6 +82,10 @@ li { color: #eee; margin: -1px; } +.selected .fa-minus-square-o, +.selected .fa-plus-square-o { + color: #000; +} span.fa-folder, span.fa-folder-open { color: #FEDE8B; @@ -101,17 +106,24 @@ span.fa-folder-open { color: #000; } #tree li { - /*cursor: pointer;*/ + padding: 0 0 0 5px; cursor: auto; } -#tree li:hover > span.element { - text-decoration: underline; -} #tree li.collapsed ul { display: none; } #tree li input { - width: calc(70%); + width: calc(100% - 30px); +} +#tree li > span.element-row { + width: calc(100% + 5px); + display: inline-block; + cursor: pointer; + margin-left: -5px; + padding-left: 5px; +} +#tree li > span.element-row:not(.selected):hover { + background-color: #eee; } #tree span.element { cursor: pointer; @@ -220,6 +232,9 @@ span.fa-folder-open { #content li:not(.header) *:not(input) { /*pointer-events: none;*/ } +#content li:not(.header):hover:not(.selected) { + background-color: #eee; +} #content li:not(.header):hover .name { /*text-decoration: underline;*/ } @@ -233,12 +248,20 @@ span.fa-folder-open { text-align: center; vertical-align: top; overflow: hidden; + text-overflow: ellipsis; + padding-top: 10px; + padding-bottom: 5px; + max-height: 145px; +} +#content div.grid li:not(.selected) { + border: transparent 1px; } #content div.grid li .name { width: 100%; } #content div.grid li input { width: 100%; + margin-top: 5px; } #content div.grid li .fa { display: block; diff --git a/www/drive/file.less b/www/drive/file.less index d3f49709a..251400ef0 100644 --- a/www/drive/file.less +++ b/www/drive/file.less @@ -2,6 +2,8 @@ @tree-fg: #000; @tree-lines-col: #888; +@drive-hover: #eee; + @content-bg: @tree-bg; @content-bg-ro: darken(@content-bg, 10%); @content-fg: @tree-fg; @@ -93,6 +95,7 @@ li { .contextMenu { display: none; position: absolute; + z-index: 50; li { padding: 0; font-size: 16px; @@ -109,6 +112,9 @@ li { background: #666; color: #eee; margin: -1px; + .fa-minus-square-o, .fa-plus-square-o { + color: @tree-fg; + } } span { @@ -134,16 +140,23 @@ span { padding: 10px 0px; color: @tree-fg; li { - /*cursor: pointer;*/ + padding: 0 0 0 5px; cursor: auto; - &:hover > span.element { - text-decoration: underline; - } &.collapsed ul { display: none; } input { - width: calc(100% - 30px); + width: ~"calc(100% - 30px)"; + } + & > span.element-row { + width: ~"calc(100% + 5px)"; + display: inline-block; + cursor: pointer; + margin-left: -5px; + padding-left: 5px; + } + & > span.element-row:not(.selected):hover { + background-color: @drive-hover; } } span.element { @@ -261,6 +274,9 @@ span { /*pointer-events: none;*/ } &:hover { + &:not(.selected) { + background-color: @drive-hover; + } .name { /*text-decoration: underline;*/ } @@ -276,12 +292,20 @@ span { text-align: center; vertical-align: top; overflow: hidden; + text-overflow: ellipsis; + padding-top: 10px; + padding-bottom: 5px; + max-height: 145px; + &:not(.selected) { + border: transparent 1px; + } .name { width: 100%; } input { width: 100%; + margin-top: 5px; } .fa { display: block; diff --git a/www/drive/index.html b/www/drive/index.html index 43fe2b44c..e5185dbff 100644 --- a/www/drive/index.html +++ b/www/drive/index.html @@ -9,6 +9,7 @@ data-main-favicon="/customize/main-favicon.png" data-alt-favicon="/customize/alt-favicon.png" id="favicon" /> +
- + +
+
+
+ +
+ +
+

+
diff --git a/www/slide/inner.html b/www/slide/inner.html index 6eacab9bb..8fde658df 100644 --- a/www/slide/inner.html +++ b/www/slide/inner.html @@ -5,6 +5,7 @@ + @@ -34,55 +35,6 @@ -
@@ -98,6 +50,7 @@
+
diff --git a/www/slide/main.js b/www/slide/main.js index c9087ed51..2e1cca8a8 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -128,12 +128,15 @@ define([ } editor.setOption('theme', theme); } - if ($select) { $select.find('.buttonTitle').text(theme || 'Theme'); } + if ($select) { + $select.setValue(theme || 'Theme'); + } }; }()); var $modal = $pad.contents().find('#modal'); var $content = $pad.contents().find('#content'); + var $print = $pad.contents().find('#print'); Slide.setModal($modal, $content, $pad, ifrw, initialState); @@ -409,6 +412,79 @@ define([ onLocal(); }; + var createPrintDialog = function () { + var printOptions = { + title: true, + slide: true, + date: true + }; + + var $container = $('
'); + var $container2 = $('
').appendTo($container); + var $div = $('
').appendTo($container2); + var $p = $('

', {'class': 'msg'}).appendTo($div); + $('').text(Messages.printOptions).appendTo($p); + $p.append($('
')); + // Slide number + $('', {type: 'checkbox', id: 'checkNumber', checked: 'checked'}).on('change', function () { + var c = this.checked; + console.log(c); + printOptions.slide = c; + }).appendTo($p).css('width', 'auto'); + $('