Compare commits

..

1 commit

Author SHA1 Message Date
yflory
03a21ed4fc Add support for priority value on websocket messages 2024-04-12 11:22:36 +02:00
124 changed files with 3221 additions and 7228 deletions

View file

@ -7,7 +7,6 @@ www/components/
www/bower_components/
www/common/onlyoffice/dist
www/common/onlyoffice/x2t
onlyoffice-dist/
www/scratch
www/accounts
@ -16,8 +15,6 @@ www/accounts
www/worker
www/todo
#lib/plugins/
www/common/hyperscript.js
www/pad/wysiwygarea-plugin.js

View file

@ -49,10 +49,13 @@ module.exports = {
// TODO remove these exceptions from the eslint defaults
'no-irregular-whitespace': ['off'],
'no-unused-vars': ['warn'],
'no-self-assign': ['off'],
'no-empty': ['off'],
'no-useless-escape': ['off'],
'no-redeclare': ['off'],
'no-extra-boolean-cast': ['off'],
'no-global-assign': ['off'],
'no-prototype-builtins': ['off'],
}
};

View file

@ -89,9 +89,6 @@ body:
label: Version
description: What version of CryptPad are you running?
options:
- 2024.6.1
- 2024.6.0
- 2024.3.1
- 2024.3.0
- 5.7.0
- 5.6.0
@ -103,6 +100,8 @@ body:
- 5.2.0
- 5.1.0
- 5.0.0
- 4.14.1
- 4.14.0
- Other
validations:
required: true

60
.lesshintrc Normal file
View file

@ -0,0 +1,60 @@
{
"fileExtensions": [".less"],
// These rules are almost certainly crap and will not catch bugs (Caleb)
"newlineAfterBlock": { "enabled": false }, // not just a newline but an entire empty line after each block
"spaceAroundOperator": { "enabled": false }, // disallow calc(10px+10px);
"hexLength": { "enabled": false }, // require long hex color codes or require short where possible
"hexNotation": { "enabled": false }, // require hex lowercase
"propertyOrdering": { "enabled": false }, // require attributes to be in alphabetical order D:
"stringQuotes": { "enabled": false }, // force quoting of strings with ' or " (silly)
"importPath": { "enabled": false }, // require imports to not have .less, ridiculous
"qualifyingElement": { "enabled": false }, // disallow div.xxx and require .xxx
"decimalZero": { "enabled": false }, // disallow .5em
"borderZero": { "enabled": false }, // disallow border: none;
"selectorNaming": { "enabled": false }, // this would be crap because classes are what they are.
"zeroUnit": { "enabled": false },
"singleLinePerProperty": { "enabled": false },
"_singleLinePerProperty": {
"enabled": true,
"allowSingleLineRules": true
},
"spaceAroundComma": { "enabled": false },
"importantRule": { "enabled": false },
"universalSelector": { "enabled": false },
"idSelector": { "enabled": false },
"singleLinePerSelector": { "enabled": false },
"spaceBetweenParens": { "enabled": false },
"maxCharPerLine": { "enabled": false }, // using lesshint flags can cause long lines
"comment": { "enabled": false }, // ban multi-line comments ?
// These rules should be discussed, if they're crap then they should be moved up.
"colorVariables": { "enabled": false }, // require all colors to be stored as variables first...
"variableValue": { "enabled": false }, // any attribute types which should always be variables ? color?
"spaceBeforeBrace": { "enabled": true },//{ "enabled": true, "style": "one_space" },
// Turn everything else on
"spaceAfterPropertyColon": { "enabled": true },
"finalNewline": { "enabled": true }, // require an empty line at the end of the file (enabled for now)
"attributeQuotes": { "enabled": true },
"depthLevel": {
"depth": 1 // TODO(cjd) This is obviously not triggering, even with 1
},
"duplicateProperty": { "enabled": false },
"emptyRule": { "enabled": true },
"hexValidation": { "enabled": true }, // disallow actual garbage color hex codes (e.g. #ab)
"propertyUnits": {
"valid": ["rem", "vw", "em", "px", "ch"], // These units are allowed for all properties
"invalid": ["pt"], // The 'pt' unit is not allowed under any circumstances
"properties": {
//"line-height": [] // No units are allowed for line-height
}
},
"spaceAfterPropertyName": { "enabled": true, "style": "no_space" },
"spaceAfterPropertyValue": { "enabled": true, "style": "no_space" },
"spaceAroundBang": { "enabled": true, "style": "before" },
"trailingSemicolon": { "enabled": true },
"trailingWhitespace": { "enabled": true },
"urlFormat": { "enabled": true, "style": "relative" },
"urlQuotes": { "enabled": true }
}

View file

@ -25,7 +25,7 @@ Files: .jshintrc
Copyright: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
License: AGPL-3.0-or-later
Files: .stylelintrc.js
Files: .lesshintrc
Copyright: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
License: AGPL-3.0-or-later
@ -156,4 +156,4 @@ License: AGPL-3.0-or-later
Files: www/common/onlyoffice/x2t/*
Copyright: Ascensio System Limited 2010-2022
License: AGPL-3.0-or-later
License: AGPL-3.0-or-later

View file

@ -1,43 +0,0 @@
module.exports = {
"extends": "stylelint-config-standard-less",
"rules": {
"no-descending-specificity": null,
"length-zero-no-unit": null,
"no-duplicate-selectors": null,
"declaration-block-no-duplicate-properties": null,
"comment-empty-line-before": null,
"rule-empty-line-before": null,
"declaration-empty-line-before": null,
"at-rule-empty-line-before": null,
"custom-property-empty-line-before": null,
"font-family-name-quotes": null,
"font-family-no-missing-generic-family-keyword": null,
"declaration-block-no-redundant-longhand-properties": null,
"shorthand-property-no-redundant-values": null,
"declaration-block-no-shorthand-property-overrides": null,
"comment-whitespace-inside": null,
"property-no-vendor-prefix": null,
"selector-no-vendor-prefix": null,
"function-name-case": null,
"selector-class-pattern": null,
"custom-property-pattern": null,
"selector-id-pattern": null,
"selector-pseudo-element-colon-notation": null,
"media-feature-range-notation": null,
"selector-not-notation": null,
"color-function-notation": null,
"alpha-value-notation": null,
"number-max-precision": null,
"at-rule-no-unknown": null, // FIXME
"less/no-duplicate-variables": null,
"less/color-no-invalid-hex": null
}
};

File diff suppressed because it is too large Load diff

View file

@ -60,7 +60,7 @@ ENTRYPOINT ["/bin/bash", "/cryptpad/docker-entrypoint.sh"]
HEALTHCHECK --interval=1m CMD curl -f http://localhost:3000/ || exit 1
# Ports
EXPOSE 3000 3003
EXPOSE 3000 3001 3003
# Run cryptpad on startup
CMD ["npm", "start"]

View file

@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals module */
/* DISCLAIMER:
There are two recommended methods of running a CryptPad instance:
@ -87,10 +89,9 @@ module.exports = {
*/
//httpPort: 3000,
/* httpSafePort purpose is to emulate another origin for the sandbox when
* you don't have two domains at hand (i.e. when httpSafeOrigin not defined).
* It is meant to be used only in case where you are working on a local
* development instance. The default value is your httpPort + 1.
/* httpSafePort allows you to specify an alternative port from which
* the node process should serve sandboxed assets. The default value is
* that of your httpPort + 1. You probably don't need to change this.
*
*/
//httpSafePort: 3001,
@ -191,7 +192,7 @@ module.exports = {
* This archived data still takes up space and so you'll probably still want to
* remove these files after a brief period.
*
* cryptpad/scripts/evict-archived.js is intended to be run daily
* cryptpad/scripts/evict-inactive.js is intended to be run daily
* from a crontab or similar scheduling service.
*
* The intent with this feature is to provide a safety net in case of accidental

View file

@ -9,14 +9,12 @@
* If you want to check all the configurable values, you can open the internal configuration file
but you should not change it directly (/common/application_config_internal.js)
*/
define(['/common/application_config_internal.js'], function (AppConfig) {
// Example: If you want to remove the survey link in the menu:
// AppConfig.surveyURL = "";
// To inform users of the support ticket panel which languages your admins speak:
//AppConfig.supportLanguages = [ 'en', 'fr' ];
return AppConfig;
});

View file

@ -22,13 +22,11 @@ define([
'/common/outer/login-block.js',
'/common/common-hash.js',
'/common/outer/http-command.js',
'/api/config',
'/components/tweetnacl/nacl-fast.min.js',
'/components/scrypt-async/scrypt-async.min.js', // better load speed
], function ($, Listmap, Crypto, Util, NetConfig, Login, Cred, ChainPad, Realtime, Constants, UI,
Feedback, h, LocalStore, Messages, nThen, Block, Hash, ServerCommand,
ApiConfig) {
Feedback, h, LocalStore, Messages, nThen, Block, Hash, ServerCommand) {
var Exports = {
Cred: Cred,
Block: Block,
@ -220,11 +218,6 @@ define([
proxy.edPublic = result.edPublic;
}
if (ApiConfig && Array.isArray(ApiConfig.adminKeys) &&
ApiConfig.adminKeys.includes(proxy.edPublic)) {
localStorage.CP_admin = "1";
}
setTimeout(function () {
Realtime.whenRealtimeSyncs(result.realtime, function () {
proceed(result);

View file

@ -5,18 +5,15 @@
(function () {
// add your module to this map so it gets used
var map = {
'ar': 'اَلْعَرَبِيَّةُ',
'ca': 'Català',
'cs': 'Čeština',
'de': 'Deutsch',
//'el': 'Ελληνικά',
'el': 'Ελληνικά',
'es': 'Español',
'es_CU': 'Español cubano',
'eu': 'Euskara',
'fi': 'Suomi',
'fr': 'Français',
//'hi': 'हिन्दी',
'id': 'Bahasa Indonesia',
'it': 'Italiano',
'ja': '日本語',
'nb': 'Norwegian Bokmål',
@ -24,9 +21,9 @@ var map = {
'pl': 'Polski',
'pt-br': 'Português do Brasil',
'pt-pt': 'Português do Portugal',
//'ro': 'Română',
'ro': 'Română',
'ru': 'Русский',
'sv': 'Svenska',
//'sv': 'Svenska',
//'te': 'తెలుగు',
'uk': 'Українська',
'zh': '中文(簡體)',
@ -48,7 +45,6 @@ var getLanguage = Messages._getLanguage = function () {
(map[l.split('_')[0]] ? l.split('_')[0] : 'en'));
};
var language = getLanguage();
window.cryptpadLanguage = language;
// Translations files were migrated from requirejs modules to json.
// To avoid asking every administrator to update their customized translation files,
@ -92,9 +88,6 @@ define(req, function(AppConfig, Default, Language) {
});
}
let html = typeof(document) !== "undefined" && document.documentElement;
if (html) { html.setAttribute('lang', language); }
var extend = function (a, b) {
for (var k in b) {
if (Array.isArray(b[k])) {
@ -136,6 +129,7 @@ define(req, function(AppConfig, Default, Language) {
}
};
return Messages;
});

View file

@ -15,8 +15,7 @@ define([
'/common/outer/local-store.js',
'/customize/pages.js',
'/common/pad-types.js',
'/common/extensions.js'
], function ($, Config, h, Hash, Constants, Util, TextFit, Msg, AppConfig, LocalStore, Pages, PadTypes, Extensions) {
], function ($, Config, h, Hash, Constants, Util, TextFit, Msg, AppConfig, LocalStore, Pages, PadTypes) {
var urlArgs = Config.requireConf.urlArgs;
var checkEarlyAccess = function (x) {
@ -165,19 +164,9 @@ define([
};
let popup = h('div.cp-extensions-popups');
let utils = { h, Util, Hash };
Extensions.getExtensions('HOMEPAGE_POPUP').forEach(ext => {
if (typeof(ext.check) === "function" && !ext.check()) { return; }
ext.getContent(utils, content => {
$(popup).append(h('div.cp-extensions-popup', content));
});
});
return [
h('div#cp-main', [
Pages.infopageTopbar(),
popup,
notice,
h('div.container.cp-container', [
h('div.row.cp-home-hero', [

View file

@ -18,6 +18,8 @@ define([
return;
}
Msg.install_token = "Install token";
document.title = Msg.install_header;
var frame = function (content) {
@ -25,7 +27,8 @@ define([
h('div#cp-main', [
//Pages.infopageTopbar(),
h('div.container.cp-container', [
h('div.row.cp-page-title', h('h1', Msg.install_header)),
//h('div.row.cp-page-title', h('h1', Msg.install_header)),
h('div.row.cp-page-title', h('h1', Msg.register_header)),
].concat(content)),
Pages.infopageFooter(),
]),
@ -36,12 +39,17 @@ define([
h('div.row.cp-register-det', [
h('div#data.hidden.col-md-6', [
h('h2', Msg.register_notes_title),
Pages.setHTML(h('div.cp-register-notes'), Msg.install_notes)
//Pages.setHTML(h('div.cp-register-notes'), Msg.install_notes)
Pages.setHTML(h('div.cp-register-notes'), Msg.register_notes)
]),
h('div.cp-reg-form.col-md-6', [
h('div#userForm.form-group.hidden', [
h('div.cp-register-instance', [
Msg.install_instance,
Msg._getKey('register_instance', [ Pages.Instance.name ]),
/*h('br'),
h('a', {
href: '/features.html'
}, Msg.register_whyRegister)*/
]),
h('input.form-control#installtoken', {
type: 'text',
@ -67,7 +75,7 @@ define([
/*h('div.checkbox-container', [
UI.createCheckbox('import-recent', Msg.register_importRecent, true)
]),*/
h('button#register', Msg.install_launch)
h('button#register', Msg.login_register)
])
]),
])

View file

@ -1,98 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@import (reference) "./colortheme-all.less";
@import (reference) "./forms.less";
@import (reference) './icon-colors.less';
.admin_main() {
--LessLoader_require: LessLoader_currentFile();
}
& {
// Instance accent color presets
@palette-colors:
#0087FF,
#de0064,
#8c52bc,
#3d7672;
div.cp-palette-container {
.cp-palette-nocolor {
display: none;
}
.instance-colors(@palette-colors; @index) when (@index > 0) {
// loop through the @colors
.instance-colors(@palette-colors; (@index - 1));
@color: extract(@palette-colors, @index);
// make a numbered class selector for each color
.cp-palette-color@{index} {
background-color: @color !important;
color: contrast(@color, @cryptpad_color_grey_800, @cryptpad_color_grey_200) !important;
}
}
.instance-colors(@palette-colors; length(@palette-colors));
}
.cp-admin-customize-apps-grid, .cp-admin-customize-options-grid {
display: grid;
gap: 0.5rem;
}
.cp-admin-customize-apps-grid {
grid-template-columns: 1fr 1fr 1fr;
.cp-appblock {
padding: 0.5rem;
border-radius: @variables_radius;
font-size: 1.2em;
display: flex;
flex-direction: row;
align-items: center;
gap: 0.75rem;
.iconColors_main();
&:hover {
cursor: pointer;
}
i.cp-icon {
font-size: 2.8rem;
}
.cp-app-name {
flex-grow: 1;
}
}
.cp-inactive-app {
background-color: transparent;
opacity: 0.75;
.cp-on-enabled {
visibility: hidden;
}
}
.cp-active-app {
background-color: fade(@cryptpad_text_col, 10%);
.cp-on-enabled {
visibility: visible;
}
}
}
.cp-admin-customize-options-grid {
grid-template-columns: 1fr 1fr;
.cp-optionblock {
padding: 0.5rem;
border-radius: @variables_radius;
background-color: fade(@cryptpad_text_col, 10%);
align-self: start;
.cp-checkmark-label {
font-weight: bold;
}
.cp-option-hint {
margin-left: 30px;
display: inline-block;
}
}
}
}

View file

@ -198,12 +198,6 @@
text-decoration: none;
}
}
.cp-usergrid-user, textarea, a, .fa-times {
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
}
}
}
.cp-alertify-type-container {
overflow: visible !important;
@ -243,10 +237,6 @@
}
}
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
}
}
span.alertify-tabs-active {
background-color: @cp_alertify-fg !important;
@ -273,10 +263,6 @@
input {
.tools_placeholder-color();
outline: none;
&:focus-visible {
outline: @cryptpad_color_brand solid 2px;
}
}
span.cp-password-container {

View file

@ -128,9 +128,9 @@
position: absolute;
box-sizing: border-box;
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
box-shadow: 0px 0px 5px @cp_checkmark-back1;
outline: none;
}
}
@ -216,9 +216,9 @@
height: @checkmark-dim1;
height: var(--checkmark-dim1);
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
box-shadow: 0px 0px 5px @cp_checkmark-back1;
outline: none;
}
}

View file

@ -119,34 +119,10 @@
}
}
// The following palette container is just for the UI components
// The specific colors you want to show have to be defined in your app
// using the classes .cp-palette-nocolor .cp-palette-color1 .cp-palette-color2 etc.
div.cp-palette-container {
display: flex;
justify-content: space-between;
.cp-palette-color {
display: inline-block;
border-radius: 50%;
height: 30px;
width: 30px;
text-align: center;
line-height: 30px;
color: @cp_kanban-fg;
border: 1px solid fade(@cp_kanban-fg, 40%);
&.fa-check { // tick on selected color
color: @cryptpad_text_col;
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
}
}
}
button.btn {
background-color: @cp_buttons-cancel;
box-sizing: border-box;
outline: 0;
align-items: center;
padding: 0 6px;
line-height: 36px;
@ -256,9 +232,11 @@
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
//border: 1px dotted @alertify-base;
box-shadow: 0px 0px 5px @cp_buttons-primary !important;
outline: none;
}
&::-moz-focus-inner {
border: 0;

View file

@ -36,6 +36,9 @@
}
.cp-reminder, .cp-avatar {
cursor: pointer;
&:hover {
background-color: @cp_dropdown-bg-hover;
}
}
.cp-avatar {
.avatar_main(30px);
@ -58,6 +61,9 @@
}
&.cp-clickable {
cursor: pointer;
&:hover {
background-color: @cp_dropdown-bg-hover;
}
}
}
.cp-notification-dismiss {
@ -67,6 +73,9 @@
align-items: center;
justify-content: center;
cursor: pointer;
&:hover {
background-color: @cp_dropdown-bg-hover;
}
}
}
}

View file

@ -80,10 +80,6 @@
text-overflow: ellipsis;
padding-left: 4px;
vertical-align: middle;
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
}
}
.close {
opacity: 1;

View file

@ -77,12 +77,6 @@
&:hover {
background-color: contrast(@cp_toolbar-bg, darken(@cp_toolbar-bg, 5%), lighten(@cp_toolbar-bg, 5%));
}
&:focus {
outline: @cryptpad_color_brand solid 2px;
}
}
button:nth-of-type(1) {
margin-left: 0.3rem;
}
}
@ -780,7 +774,7 @@
padding: 10px;
color: @toolbar-bg-color;
color: var(--toolbar-bg-color);
border-radius: @variables_radius;
border-radius: 5px;
span {
font-size: 45px;

View file

@ -115,8 +115,7 @@
}
}
.fa-times {
border-radius: @variables_radius;
margin-left: 5px;
padding-left: 5px;
cursor: pointer;
height: 100%;
line-height: 25px;

View file

@ -297,29 +297,6 @@
}
}
.cp-extensions-popups {
width: 100%;
.cp-extensions-popup {
background-color: @cp_alertify-bg;
border-radius: @infopages-radius-L;
padding: 10px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
width: 400px;
max-width: 100%;
color: @cryptpad_text_col;
margin-left: 40px;
}
}
@media (max-width: 700px) {
.cp-extensions-popups {
max-width: 90%;
.cp-extensions-popup {
margin-left: 0;
}
}
}
@media (min-width: 576px) and (max-width: 767px) {
.container {
padding-left: 0;

View file

@ -8,8 +8,3 @@
margin: 3cm;
size: A4 portrait;
}
@media print {
body {
background: white !important;
}
}

View file

@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/*
* You can override the translation text using this file.
* The recommended method is to make a copy of this file (/customize.dist/translations/messages.{LANG}.js)
in a 'customize' directory (/customize/translations/messages.{LANG}.js).
* If you want to check all the existing translation keys, you can open the internal language file
but you should not change it directly (/common/translations/messages.{LANG}.js)
*/
define(['/common/translations/messages.ar.js'], function (Messages) {
// Replace the existing keys in your copied file here:
// Messages.button_newpad = "New Rich Text Document";
return Messages;
});

View file

@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/*
* You can override the translation text using this file.
* The recommended method is to make a copy of this file (/customize.dist/translations/messages.{LANG}.js)
in a 'customize' directory (/customize/translations/messages.{LANG}.js).
* If you want to check all the existing translation keys, you can open the internal language file
but you should not change it directly (/common/translations/messages.{LANG}.js)
*/
define(['/common/translations/messages.es_CU.js'], function (Messages) {
// Replace the existing keys in your copied file here:
// Messages.button_newpad = "New Rich Text Document";
return Messages;
});

View file

@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/*
* You can override the translation text using this file.
* The recommended method is to make a copy of this file (/customize.dist/translations/messages.{LANG}.js)
in a 'customize' directory (/customize/translations/messages.{LANG}.js).
* If you want to check all the existing translation keys, you can open the internal language file
but you should not change it directly (/common/translations/messages.{LANG}.js)
*/
define(['/common/translations/messages.id.js'], function (Messages) {
// Replace the existing keys in your copied file here:
// Messages.button_newpad = "New Rich Text Document";
return Messages;
});

View file

@ -3,9 +3,11 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
---
version: '3.8'
services:
cryptpad:
image: "cryptpad/cryptpad:version-2024.6.1"
image: "cryptpad/cryptpad:version-2024.3.0"
hostname: cryptpad
environment:
@ -28,6 +30,7 @@ services:
ports:
- "3000:3000"
- "3001:3001"
- "3003:3003"
ulimits:

View file

@ -31,7 +31,7 @@ fi
cd $CPAD_HOME
if [ "$CPAD_INSTALL_ONLYOFFICE" == "yes" ]; then
./install-onlyoffice.sh --accept-license --trust-repository
./install-onlyoffice.sh --accept-license
fi
npm run build

View file

@ -9,13 +9,11 @@
# in production and require professional support please contact sales@cryptpad.fr
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
listen 443 ssl http2;
listen [::]:443 ssl http2;
# Let's Encrypt webroot
include letsencrypt-webroot;
# Include mime.types to be able to support .mjs files (see "types" below)
include mime.types;
@ -84,9 +82,6 @@ server {
# replace with the IP address of your resolver
resolver 8.8.8.8 8.8.4.4 1.1.1.1 1.0.0.1 9.9.9.9 149.112.112.112 208.67.222.222 208.67.220.220;
# OnlyOffice fonts may be loaded from both domains
if ($uri ~ ^\/common\/onlyoffice\/.*\/fonts\/.*$) { set $allowed_origins "*"; }
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
add_header Access-Control-Allow-Origin "${allowed_origins}";
@ -234,20 +229,6 @@ server {
add_header Cross-Origin-Embedder-Policy require-corp;
}
location ~ ^/extensions.js {
proxy_pass http://localhost:3000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# These settings prevent both NGINX and the API server
# from setting the same headers and creating duplicates
proxy_hide_header Cross-Origin-Resource-Policy;
add_header Cross-Origin-Resource-Policy cross-origin;
proxy_hide_header Cross-Origin-Embedder-Policy;
add_header Cross-Origin-Embedder-Policy require-corp;
}
# Requests for blobs and blocks are now proxied to the API server
# This simplifies NGINX path configuration in the event they are being hosted in a non-standard location
# or with odd unexpected permissions. Serving blobs in this manner also means that it will be possible to

View file

@ -33,14 +33,7 @@ SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
Protocols h2 http/1.1
AddType application/javascript mjs
<Location "/">
LimitRequestBody 157286400
ProxyPass http://localhost:3000/ upgrade=websocket
ProxyPassReverse http://localhost:3000/
</Location>
<Location "/cryptpad_websocket">
ProxyPass http://localhost:3003/ upgrade=websocket
ProxyPassReverse http://localhost:3003/
</Location>
LimitRequestBody 157286400
ProxyPass / http://localhost:3000/ upgrade=websocket
ProxyPassReverse / http://localhost:3000/
</VirtualHost>

View file

@ -9,9 +9,8 @@
# in production and require professional support please contact sales@cryptpad.fr
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
listen 443 ssl http2;
listen [::]:443 ssl http2;
# Let's Encrypt webroot
include letsencrypt-webroot;
@ -71,15 +70,4 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
}
location ^~ /cryptpad_websocket {
proxy_pass http://localhost:3003;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
}
}

View file

@ -6,7 +6,7 @@
set -euo pipefail
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
CONF_DIR=$SCRIPT_DIR/onlyoffice-conf
BUILDS_DIR=$CONF_DIR/onlyoffice-builds.git
OO_DIR=$SCRIPT_DIR/www/common/onlyoffice/dist
@ -14,93 +14,86 @@ PROPS_FILE="$CONF_DIR"/onlyoffice.properties
declare -A PROPS
main() {
mkdir -p "$CONF_DIR"
main () {
mkdir -p "$CONF_DIR"
load_props
load_props
parse_arguments "$@"
parse_arguments "$@"
ask_for_license
ask_for_license
# Remeber the 1st version that is installed. This will help us install only
# needed OnlyOffice versions in a later version of this script.
set_prop oldest_needed_version v1
# Remeber the 1st version that is installed. This will help us install only
# needed OnlyOffice versions in a later version of this script.
set_prop oldest_needed_version v1
mkdir -p "$OO_DIR"
install_version v1 4f370beb
install_version v2b d9da72fd
install_version v4 6ebc6938
install_version v5 88a356f0
install_version v6 abd8a309
install_version v7 e1267803
install_x2t v7.3+1 ab0c05b0e4c81071acea83f0c6a8e75f5870c360ec4abc4af09105dd9b52264af9711ec0b7020e87095193ac9b6e20305e446f2321a541f743626a598e5318c1
mkdir -p "$OO_DIR"
install_version v1 4f370beb
install_version v2b d9da72fd
install_version v4 6ebc6938
install_version v5 88a356f0
install_version v6 abd8a309
install_version v7 9d8b914a
install_x2t v7.3+1 ab0c05b0e4c81071acea83f0c6a8e75f5870c360ec4abc4af09105dd9b52264af9711ec0b7020e87095193ac9b6e20305e446f2321a541f743626a598e5318c1
rm -rf "$BUILDS_DIR"
if command -v rdfind &>/dev/null; then
rdfind -makehardlinks true -makeresultsfile false $OO_DIR/v*
fi
rm -rf "$BUILDS_DIR"
if command -v rdfind &> /dev/null; then
rdfind -makehardlinks true -makeresultsfile false $OO_DIR/v*
fi
}
load_props() {
if [ -e "$PROPS_FILE" ]; then
while IFS='=' read -r key value; do
PROPS["$key"]="$value"
done <"$PROPS_FILE"
fi
load_props () {
if [ -e "$PROPS_FILE" ]; then
while IFS='=' read -r key value; do
PROPS["$key"]="$value"
done < "$PROPS_FILE"
fi
}
set_prop() {
PROPS["$1"]="$2"
set_prop () {
PROPS["$1"]="$2"
for i in "${!PROPS[@]}"; do
echo "$i=${PROPS[$i]}"
done >"$PROPS_FILE"
for i in "${!PROPS[@]}"; do
echo "$i=${PROPS[$i]}"
done > "$PROPS_FILE"
}
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
-h | --help)
show_help
shift
;;
-a | --accept-license)
ACCEPT_LICENSE="1"
shift
;;
-t | --trust-repository)
TRUST_REPOSITORY="1"
shift
;;
*)
show_help
shift
;;
esac
done
parse_arguments () {
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
shift
;;
-a|--accept-license)
ACCEPT_LICENSE="1"
shift
;;
*)
show_help
shift
;;
esac
done
}
ask_for_license() {
if [ ${ACCEPT_LICENSE+x} ] || [ "${PROPS[agree_license]:-no}" == yes ]; then
return
fi
ask_for_license () {
if [ ${ACCEPT_LICENSE+x} ] || [ "${PROPS[agree_license]:-no}" == yes ]; then
return
fi
ensure_command_available curl
ensure_command_available curl
(
echo -e "Please review the license of OnlyOffice:\n\n"
curl https://raw.githubusercontent.com/ONLYOFFICE/web-apps/master/LICENSE.txt 2>/dev/null
) | less
(echo -e "Please review the license of OnlyOffice:\n\n" ; curl https://raw.githubusercontent.com/ONLYOFFICE/web-apps/master/LICENSE.txt 2>/dev/null) | less
read -rp "Do you accept the license? (Y/N): " confirm &&
[[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1
read -rp "Do you accept the license? (Y/N): " confirm \
&& [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1
set_prop "agree_license" yes
set_prop "agree_license" yes
}
show_help() {
cat <<EOF
show_help () {
cat << EOF
install-onlyoffice installs or upgrades OnlyOffice.
NOTE: When you have rdfind installed, it will be used to save ~650MB of disk
@ -114,97 +107,89 @@ OPTIONS:
Accept the license of OnlyOffice and do not ask when running this
script. Read and accept this before using this option:
https://github.com/ONLYOFFICE/web-apps/blob/master/LICENSE.txt
-t, --trust-repository
Automatically configure the cloned onlyoffice-builds repository
as a safe.directory.
https://git-scm.com/docs/git-config/#Documentation/git-config.txt-safedirectory
EOF
exit 1
exit 1
}
ensure_oo_is_downloaded() {
ensure_command_available git
ensure_oo_is_downloaded () {
ensure_command_available git
if ! [ -d "$BUILDS_DIR" ]; then
echo "Downloading OnlyOffice..."
git clone --bare https://github.com/cryptpad/onlyoffice-builds.git "$BUILDS_DIR"
fi
if [ ${TRUST_REPOSITORY+x} ] || [ "${PROPS[trust_repository]:-no}" == yes ]; then
git config --global --add safe.directory /cryptpad/onlyoffice-conf/onlyoffice-builds.git
fi
}
install_version() {
local DIR=$1
local COMMIT=$2
local FULL_DIR=$OO_DIR/$DIR
local LAST_DIR
LAST_DIR=$(pwd)
install_version () {
local DIR=$1
local COMMIT=$2
local FULL_DIR=$OO_DIR/$DIR
local LAST_DIR
LAST_DIR=$(pwd)
if [ ! -e "$FULL_DIR"/.commit ] || [ "$(cat "$FULL_DIR"/.commit)" != "$COMMIT" ]; then
ensure_oo_is_downloaded
if [ ! -e "$FULL_DIR"/.commit ] || [ "$(cat "$FULL_DIR"/.commit)" != "$COMMIT" ]; then
ensure_oo_is_downloaded
rm -rf "$FULL_DIR"
rm -rf "$FULL_DIR"
cd "$BUILDS_DIR"
git worktree add "$FULL_DIR" "$COMMIT"
cd "$BUILDS_DIR"
git worktree add "$FULL_DIR" "$COMMIT"
cd "$LAST_DIR"
cd "$LAST_DIR"
echo "$COMMIT" >"$FULL_DIR"/.commit
echo "$COMMIT" > "$FULL_DIR"/.commit
echo "$DIR updated"
else
echo "$DIR was up to date"
fi
echo "$DIR updated"
else
echo "$DIR was up to date"
fi
if [ ${CLEAR+x} ]; then
rm -f "$FULL_DIR"/.git
fi
if [ ${CLEAR+x} ]; then
rm -f "$FULL_DIR"/.git
fi
}
install_x2t() {
ensure_command_available curl
ensure_command_available sha512sum
ensure_command_available unzip
install_x2t () {
ensure_command_available curl
ensure_command_available sha512sum
ensure_command_available unzip
local VERSION=$1
local HASH=$2
local LAST_DIR
LAST_DIR=$(pwd)
local X2T_DIR=$OO_DIR/x2t
local VERSION=$1
local HASH=$2
local LAST_DIR
LAST_DIR=$(pwd)
local X2T_DIR=$OO_DIR/x2t
if [ ! -e "$X2T_DIR"/.version ] || [ "$(cat "$X2T_DIR"/.version)" != "$VERSION" ]; then
rm -rf "$X2T_DIR"
mkdir -p "$X2T_DIR"
if [ ! -e "$X2T_DIR"/.version ] || [ "$(cat "$X2T_DIR"/.version)" != "$VERSION" ]; then
rm -rf "$X2T_DIR"
mkdir -p "$X2T_DIR"
cd "$X2T_DIR"
cd "$X2T_DIR"
curl "https://github.com/cryptpad/onlyoffice-x2t-wasm/releases/download/$VERSION/x2t.zip" --location --output x2t.zip
# curl "https://github.com/cryptpad/onlyoffice-x2t-wasm/releases/download/v7.3%2B1/x2t.zip" --location --output x2t.zip
echo "$HASH x2t.zip" >x2t.zip.sha512
if ! sha512sum --check x2t.zip.sha512; then
echo "x2t.zip does not match expected checksum"
exit 1
fi
unzip x2t.zip
rm x2t.zip*
curl "https://github.com/cryptpad/onlyoffice-x2t-wasm/releases/download/$VERSION/x2t.zip" --location --output x2t.zip
# curl "https://github.com/cryptpad/onlyoffice-x2t-wasm/releases/download/v7.3%2B1/x2t.zip" --location --output x2t.zip
echo "$HASH x2t.zip" > x2t.zip.sha512
if ! sha512sum --check x2t.zip.sha512; then
echo "x2t.zip does not match expected checksum"
exit 1
fi
unzip x2t.zip
rm x2t.zip*
echo "$VERSION" >"$X2T_DIR"/.version
echo "$VERSION" > "$X2T_DIR"/.version
echo "x2t updated"
else
echo "x2t was up to date"
fi
echo "x2t updated"
else
echo "x2t was up to date"
fi
}
ensure_command_available() {
if ! command -v "$1" &>/dev/null; then
echo "$1 needs to be installed to run this script"
exit 1
fi
ensure_command_available () {
if ! command -v "$1" &> /dev/null; then
echo "$1 needs to be installed to run this script"
exit 1
fi
}
main "$@"

View file

@ -8,10 +8,8 @@ const Decrees = require("./decrees");
const nThen = require("nthen");
const Fs = require("fs");
const Fse = require("fs-extra");
const Path = require("path");
const Nacl = require("tweetnacl/nacl-fast");
const Hash = require('./common-hash');
module.exports.create = function (Env) {
var log = Env.Log;
@ -27,41 +25,6 @@ nThen(function (w) {
console.error(err);
}
}));
}).nThen(function (w) {
let admins = Env.admins || [];
// If we don't have any admin on this instance, print an onboarding link
if (Array.isArray(admins) && admins.length) { return; }
let token = Env.installToken;
let printLink = () => {
let url = `${Env.httpUnsafeOrigin}/install/#${token}`;
console.log('=============================');
console.log('Create your first admin account and customize your instance by visiting');
console.log(url);
console.log('=============================');
};
// If we already have a token, print it
if (token) { return void printLink(); }
// Otherwise create a new token
let decreeName = Path.join(Env.paths.decree, 'decree.ndjson');
token = Hash.createChannelId() + Hash.createChannelId();
let decree = ["ADD_INSTALL_TOKEN",[token],"",+new Date()];
Fs.appendFile(decreeName, JSON.stringify(decree) + '\n', w(function (err) {
if (err) { console.log(err); return; }
Env.installToken = token;
Env.envUpdated.fire();
printLink();
}));
}).nThen(function () {
if (!Env.admins.length) {
Env.Log.info('NO_ADMIN_CONFIGURED', {
message: `Your instance is not correctly configured for production usage. Review its checkup page for more information.`,
details: new URL('/checkup/', Env.httpUnsafeOrigin).href,
});
}
}).nThen(function (w) {
// we assume the server has generated a secret used to validate JWT tokens
if (typeof(Env.bearerSecret) === 'string') { return; }
@ -77,19 +40,9 @@ nThen(function (w) {
], w(function (err) {
if (err) { throw err; }
}));
}).nThen(function (w) {
Fse.mkdirp(Env.paths.block, w(function (err) {
if (err) {
log.error("BLOCK_FOLDER_CREATE_FAILED", err);
}
}));
}).nThen(function (w) {
var fullPath = Path.join(Env.paths.block, 'placeholder.txt');
Fs.writeFile(fullPath, 'PLACEHOLDER\n', w(function (err) {
if (err) {
log.error('BLOCK_PLACEHOLDER_CREATE_FAILED', err);
}
}));
Fs.writeFile(fullPath, 'PLACEHOLDER\n', w());
}).nThen(function () {
// asynchronously create a historyKeeper and RPC together
require('./historyKeeper.js').create(Env, function (err, historyKeeper) {
@ -108,7 +61,7 @@ nThen(function (w) {
};
// spawn ws server and attach netflux event handlers
let Server = NetfluxSrv.create(new WebSocketServer({ server: Env.httpServer}))
NetfluxSrv.create(new WebSocketServer({ server: Env.httpServer}))
.on('channelClose', historyKeeper.channelClose)
.on('channelMessage', historyKeeper.channelMessage)
.on('channelOpen', historyKeeper.channelOpen)
@ -137,65 +90,6 @@ nThen(function (w) {
});
})
.register(historyKeeper.id, historyKeeper.directMessage);
// Store max active WS during the last day (reset when sending ping if enabled)
setInterval(() => {
try {
// Concurrent usage data
let oldWs = Env.maxConcurrentWs || 0;
let oldUniqueWs = Env.maxConcurrentUniqueWs || 0;
let oldChans = Env.maxActiveChannels || 0;
let oldUsers = Env.maxConcurrentRegUsers || 0;
let stats = Server.getSessionStats();
let chans = Server.getActiveChannelCount();
let reg = 0;
let regKeys = [];
Object.keys(Env.netfluxUsers).forEach(id => {
let keys = Env.netfluxUsers[id];
let key = Object.keys(keys || {})[0];
if (!key) { return; }
if (regKeys.includes(key)) { return; }
reg++;
regKeys.push(key);
});
Env.maxConcurrentWs = Math.max(oldWs, stats.total);
Env.maxConcurrentUniqueWs = Math.max(oldUniqueWs, stats.unique);
Env.maxConcurrentRegUsers = Math.max(oldUsers, reg);
Env.maxActiveChannels = Math.max(oldChans, chans);
} catch (e) {}
}, 10000);
// Clean up active registered users and channels (possible memory leak)
setInterval(() => {
try {
let users = Env.netfluxUsers || {};
let online = Server.getOnlineUsers() || [];
let removed = 0;
Object.keys(users).forEach(id => {
if (!online.includes(id)) {
delete users[id];
removed++;
}
});
if (removed) {
Env.Log.info("CLEANED_ACTIVE_USERS_MAP", {removed});
}
} catch (e) {}
try {
let HK = require('./hk-utils');
let chans = Env.channel_cache || {};
let active = Server.getActiveChannels() || [];
let removed = 0;
Object.keys(chans).forEach(id => {
if (!active.includes(id)) {
HK.dropChannel(Env, id);
removed++;
}
});
if (removed) {
Env.Log.info("CLEANED_ACTIVE_CHANNELS_MAP", {removed});
}
} catch (e) {}
}, 30000);
});
});

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals Buffer */
const B32 = require("thirty-two");
const OTP = require("notp");
const nThen = require("nthen");

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process */
const nThen = require("nthen");
const getFolderSize = require("get-folder-size");
const Util = require("../common-util");
@ -101,7 +102,7 @@ var shutdown = function (Env, Server, cb) {
// and allow system functionality to restart the server
};
var getRegisteredUsers = Admin.getRegisteredUsers = function (Env, Server, cb) {
var getRegisteredUsers = function (Env, Server, cb) {
Env.batchRegisteredUsers('', cb, function (done) {
var dir = Env.paths.pin;
var folders;
@ -119,15 +120,11 @@ var getRegisteredUsers = Admin.getRegisteredUsers = function (Env, Server, cb) {
var dir = Env.paths.pin + '/' + f;
Fs.readdir(dir, waitFor(function (err, list) {
if (err) { return; }
// Don't count placeholders
list = list.filter(name => {
return !/\.placeholder$/.test(name);
});
users += list.length;
}));
});
}).nThen(function () {
done(void 0, {users});
done(void 0, users);
});
});
};
@ -470,8 +467,6 @@ var setLastEviction = function (Env, Server, cb, data, unsafeKey) {
// CryptPad_AsyncStore.rpc.send('ADMIN', ['INSTANCE_STATUS], console.log)
var instanceStatus = function (Env, Server, cb) {
cb(void 0, {
appsToDisable: Env.appsToDisable,
restrictRegistration: Env.restrictRegistration,
restrictSsoRegistration: Env.restrictSsoRegistration,
dontStoreSSOUsers: Env.dontStoreSSOUsers,

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals Buffer*/
const Block = module.exports;
const Nacl = require("tweetnacl/nacl-fast");
const nThen = require("nthen");

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process */
const Core = module.exports;
const Util = require("../common-util");
const escapeKeyCharacters = Util.escapeKeyCharacters;

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals Buffer*/
const Quota = module.exports;
//const Util = require("../common-util");
@ -10,8 +11,6 @@ const Https = require("https");
const Http = require("http");
const Util = require("../common-util");
const Stats = require("../stats");
const Admin = require("./admin-rpc.js");
const nThen = require('nthen');
var validLimitFields = ['limit', 'plan', 'note', 'users', 'origin'];
@ -113,83 +112,45 @@ var queryAccountServer = function (Env, cb) {
var done = Util.once(Util.mkAsync(cb));
var rawBody = Stats.instanceData(Env);
Env.Log.info("SERVER_TELEMETRY", rawBody);
var body = JSON.stringify(rawBody);
let send = () => {
Env.Log.info("SERVER_TELEMETRY", rawBody);
var body = JSON.stringify(rawBody);
var options = {
host: 'accounts.cryptpad.fr',
path: '/api/getauthorized',
method: 'POST',
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body)
}
};
var req = Https.request(options, function (response) {
if (!('' + response.statusCode).match(/^2\d\d$/)) {
return void cb('SERVER ERROR ' + response.statusCode);
}
var str = '';
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
try {
var json = JSON.parse(str);
checkUpdateAvailability(Env, json);
done(void 0, json);
} catch (e) {
done(e);
}
});
});
req.on('error', function () {
done();
});
req.end(body);
var options = {
host: 'accounts.cryptpad.fr',
path: '/api/getauthorized',
method: 'POST',
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body)
}
};
if (Env.provideAggregateStatistics) {
let stats = {};
nThen(waitFor => {
Admin.getRegisteredUsers(Env, null, waitFor((err, data) => {
if (err) { return; }
stats.registered = data.users;
if (Env.lastPingRegisteredUsers) {
stats.usersDiff = stats.registered - Env.lastPingRegisteredUsers;
}
Env.lastPingRegisteredUsers = stats.registered;
}));
}).nThen(() => {
if (Env.maxConcurrentWs) {
stats.maxConcurrentWs = Env.maxConcurrentWs;
Env.maxConcurrentWs = 0;
}
if (Env.maxConcurrentUniqueWs) {
stats.maxConcurrentUniqueIPs = Env.maxConcurrentUniqueWs;
Env.maxConcurrentUniqueWs = 0;
}
if (Env.maxConcurrentRegUsers) {
stats.maxConcurrentRegUsers = Env.maxConcurrentRegUsers;
Env.maxConcurrentRegUsers = 0;
}
if (Env.maxActiveChannels) {
stats.maxConcurrentChannels = Env.maxActiveChannels;
Env.maxActiveChannels = 0;
}
rawBody.statistics = stats;
send();
var req = Https.request(options, function (response) {
if (!('' + response.statusCode).match(/^2\d\d$/)) {
return void cb('SERVER ERROR ' + response.statusCode);
}
var str = '';
response.on('data', function (chunk) {
str += chunk;
});
return;
}
send();
response.on('end', function () {
try {
var json = JSON.parse(str);
checkUpdateAvailability(Env, json);
done(void 0, json);
} catch (e) {
done(e);
}
});
});
req.on('error', function () {
done();
});
req.end(body);
};
Quota.shouldContactServer = function (Env) {
return !(Env.blockDailyCheck === true ||

View file

@ -1,6 +0,0 @@
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
module.exports = require("../www/common/common-hash");

View file

@ -169,7 +169,6 @@ var isInteger = function (n) {
var args_isString = function (args) {
return !(!Array.isArray(args) || !isString(args[0]));
};
var args_isInteger = function (args) {
return !(!Array.isArray(args) || !isInteger(args[0]));
};
@ -212,6 +211,10 @@ commands.SET_ARCHIVE_RETENTION_TIME = makeIntegerSetter('archiveRetentionTime');
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_ACCOUNT_RETENTION_TIME', [365]]], console.log)
commands.SET_ACCOUNT_RETENTION_TIME = makeIntegerSetter('accountRetentionTime');
var args_isString = function (args) {
return Array.isArray(args) && typeof(args[0]) === "string";
};
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_ADMIN_EMAIL', ['admin@website.tld']]], console.log)
commands.SET_ADMIN_EMAIL = makeGenericSetter('adminEmail', args_isString);
@ -220,15 +223,6 @@ commands.SET_SUPPORT_MAILBOX = makeGenericSetter('supportMailbox', function (arg
return args_isString(args) && Core.isValidPublicKey(args[0]);
});
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_SUPPORT_KEYS', ["Tdz6+fE9N9XXBY93rW5qeNa/k27yd40c0vq7EJyt7jA=", "Tdz6+fE9N9XXBY93rW5qeNa/k27yd40c0vq7EJyt7jA="]]], console.log)
commands.DISABLE_APPS = function (Env, args) {
if (!Array.isArray(args)) { throw new Error("INVALID_ARGS"); }
if (JSON.stringify(args) === JSON.stringify(Env.appsToDisable)) { return false; }
Env.appsToDisable = args;
return true;
};
commands.SET_SUPPORT_KEYS = function (Env, args) {
const curvePublic = args[0]; // Support mailbox key
const edPublic = args[1]; // Support pin log
@ -241,7 +235,7 @@ commands.SET_SUPPORT_KEYS = function (Env, args) {
Env.supportMailboxKey = curvePublic;
Env.supportPinKey = edPublic;
return true;
};
};
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_PURPOSE', ["development"]]], console.log)
commands.SET_INSTANCE_PURPOSE = makeGenericSetter('instancePurpose', args_isString);
@ -299,7 +293,7 @@ var args_isMaintenance = function (args) {
// whenever that happens we can relax validation a bit to support more formats
var makeBroadcastSetter = function (attr, validation) {
return function (Env, args) {
if ((validation && !validation(args)) && !args_isString(args)) {
if ((validation && !validation(args)) && !args_isString(args)) {
throw new Error('INVALID_ARGS');
}
var str = args[0];

View file

@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process */
const { existsSync, readdirSync } = require('node:fs');
const Crypto = require('crypto');

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* global Buffer */
var HK = module.exports;
const nThen = require('nthen');
@ -625,6 +626,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
var metadata = {};
var lastKnownHash;
var txid;
var priority;
// clients can optionally pass a map of attributes
// if the channel already exists this map will be ignored
@ -633,6 +635,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
lastKnownHash = config.lastKnownHash;
metadata = config.metadata || {};
txid = config.txid;
priority = config.priority;
if (metadata.expire) {
metadata.expire = +metadata.expire * 1000 + (+new Date());
}
@ -676,7 +679,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
if (checkExpired(Env, Server, channelName)) { return void waitFor.abort(); }
// always send metadata with GET_HISTORY requests
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(metadata)], w);
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(metadata), priority], w);
}));
}).nThen(() => {
let msgCount = 0;
@ -687,7 +690,7 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
// avoid sending the metadata message a second time
if (isMetadataMessage(msg) && metadata_cache[channelName]) { return readMore(); }
if (txid) { msg[0] = txid; }
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(msg)], readMore);
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(msg), priority], readMore);
}, (err, reason) => {
// Any error but ENOENT: abort
// ENOENT is allowed in case we want to create a new pad
@ -735,13 +738,13 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
if (msgCount === 0 && !metadata_cache[channelName] && Server.channelContainsUser(channelName, userId)) {
// TODO this might be a good place to reject channel creation by anonymous users
handleFirstMessage(Env, channelName, metadata);
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(metadata)]);
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(metadata), priority]);
}
// End of history message:
let parsedMsg = {state: 1, channel: channelName, txid: txid};
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(parsedMsg)]);
Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(parsedMsg), priority]);
});
});
};

View file

@ -78,26 +78,15 @@ COMMANDS.TOTP_REVOKE = TOTP.TOTP_REVOKE;
COMMANDS.TOTP_WRITE_BLOCK = TOTP.TOTP_WRITE_BLOCK; // Password change only for now (v5.5.0)
COMMANDS.TOTP_REMOVE_BLOCK = TOTP.TOTP_REMOVE_BLOCK;
// Load challenges added by plugins
Object.keys(plugins || {}).forEach(id => {
try {
let plugin = plugins[id];
if (!plugin.challenge) { return; }
let commands = plugin.challenge;
Object.keys(commands).forEach(cmd => {
if (COMMANDS[cmd]) { return; } // Don't overwrite
COMMANDS[cmd] = commands[cmd];
});
} catch (e) {}
});
/*
const SSO = plugins.SSO && plugins.SSO.challenge;
COMMANDS.SSO_AUTH = SSO.SSO_AUTH;
COMMANDS.SSO_AUTH_CB = SSO.SSO_AUTH_CB;
COMMANDS.SSO_WRITE_BLOCK = SSO.SSO_WRITE_BLOCK; // Account creation only
COMMANDS.SSO_UPDATE_BLOCK = SSO.SSO_UPDATE_BLOCK; // Password change
COMMANDS.SSO_VALIDATE = SSO.SSO_VALIDATE;
*/
try {
// SSO plugin may not be installed
const SSO = plugins.SSO && plugins.SSO.challenge;
COMMANDS.SSO_AUTH = SSO.SSO_AUTH;
COMMANDS.SSO_AUTH_CB = SSO.SSO_AUTH_CB;
COMMANDS.SSO_WRITE_BLOCK = SSO.SSO_WRITE_BLOCK; // Account creation only
COMMANDS.SSO_UPDATE_BLOCK = SSO.SSO_UPDATE_BLOCK; // Password change
COMMANDS.SSO_VALIDATE = SSO.SSO_VALIDATE;
} catch (e) {}
var randomToken = () => Nacl.util.encodeBase64(Nacl.randomBytes(24)).replace(/\//g, '-');

View file

@ -161,13 +161,6 @@ var setHeaders = function (req, res) {
}
var h = getHeaders(Env, type);
// Allow main domain to load resources from the sandbox URL
if (!Env.enableEmbedding && req.get('origin') === Env.httpUnsafeOrigin &&
/^\/common\/onlyoffice\/dist\/.*\/fonts\/.*/.test(req.url)) {
h['Access-Control-Allow-Origin'] = Env.httpUnsafeOrigin;
}
applyHeaderMap(res, h);
};
@ -513,11 +506,6 @@ app.use("/block", (req, res, next) => {
next();
});
Object.keys(plugins || {}).forEach(name => {
let plugin = plugins[name];
if (!plugin.addHttpEndpoints) { return; }
plugin.addHttpEndpoints(Env, app);
});
app.use("/customize", Express.static('customize'));
app.use("/customize", Express.static('customize.dist'));
@ -595,7 +583,6 @@ var serveConfig = makeRouteCache(function () {
maxUploadSize: Env.maxUploadSize,
premiumUploadSize: Env.premiumUploadSize,
restrictRegistration: Env.restrictRegistration,
appsToDisable: Env.appsToDisable,
restrictSsoRegistration: Env.restrictSsoRegistration,
httpSafeOrigin: Env.httpSafeOrigin,
enableEmbedding: Env.enableEmbedding,
@ -631,35 +618,6 @@ var serveBroadcast = makeRouteCache(function () {
app.get('/api/config', serveConfig);
app.get('/api/broadcast', serveBroadcast);
(function () {
let extensions = plugins._extensions;
let styles = plugins._styles;
let str = JSON.stringify(extensions);
let str2 = JSON.stringify(styles);
let js = `let extensions = ${str};
let styles = ${str2};
let lang = window.cryptpadLanguage;
let paths = [];
extensions.forEach(name => {
paths.push(\`optional!/\${name}/extensions.js\`);
paths.push(\`optional!json!/\${name}/translations/messages.json\`);
paths.push(\`optional!json!/\${name}/translations/messages.\${lang}.json\`);
});
styles.forEach(name => {
paths.push(\`optional!less!/\${name}/style.less\`);
});
define(paths, function () {
let args = Array.prototype.slice.apply(arguments);
return args;
}, function () {
// ignore missing files
});`;
app.get('/extensions.js', (req, res) => {
res.setHeader('Content-Type', 'text/javascript');
res.send(js);
});
})();
var Define = function (obj) {
return `define(function (){
return ${JSON.stringify(obj, null, '\t')};
@ -753,7 +711,7 @@ app.post('/api/auth', function (req, res, next) {
});
app.use(function (req, res /*, next */) {
if (/^(\/favicon\.ico\/|.*\.js\.map|.*\/translations\/.*\.json)/.test(req.url)) {
if (/^(\/favicon\.ico\/|.*\.js\.map)$/.test(req.url)) {
// ignore common 404s
} else {
Log.info('HTTP_404', req.url);
@ -777,8 +735,7 @@ var server = Http.createServer(app);
nThen(function (w) {
server.listen(Env.httpPort, Env.httpAddress, w());
if (Env.httpSafePort) {
let safeServer = Http.createServer(app);
safeServer.listen(Env.httpSafePort, Env.httpAddress, w());
server.listen(Env.httpSafePort, Env.httpAddress, w());
}
server.on('upgrade', function (req, socket, head) {
// TODO warn admins that websockets should only be proxied in this way in a dev environment

View file

@ -39,6 +39,8 @@ var handlers = {};
handlers[level] = function (ctx, content) { console.error(content); };
});
var noop = function () {};
var createLogType = function (ctx, type) {
if (logLevels.indexOf(type) < logLevels.indexOf(ctx.logLevel)) {
return noop;

View file

@ -4,8 +4,6 @@
const fs = require('node:fs');
const plugins = {};
const extensions = plugins._extensions = [];
const styles = plugins._styles = [];
try {
let pluginsDir = fs.readdirSync(__dirname + '/plugins');
@ -14,18 +12,6 @@ try {
try {
let plugin = require(`./plugins/${name}/index`);
plugins[plugin.name] = plugin.modules;
try {
let hasExt = fs.existsSync(`lib/plugins/${name}/client/extensions.js`);
if (hasExt) {
extensions.push(plugin.name.toLowerCase());
}
} catch (e) {}
try {
let hasStyle = fs.existsSync(`lib/plugins/${name}/client/style.less`);
if (hasStyle) {
styles.push(plugin.name.toLowerCase());
}
} catch (e) {}
} catch (err) {
console.error(err);
}

View file

@ -81,8 +81,8 @@ Stats.instanceData = function (Env) {
if (Env.provideAggregateStatistics) {
// check how many instances provide stats before we put more work into it
data.providesAggregateStatistics = true;
data.statistics = {}; // Filled in lib/commands/quota.js because of async calls
}
return data;
};

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals Buffer */
var Fs = require("fs");
var Fse = require("fs-extra");
var Path = require("path");

View file

@ -3,6 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
/*@flow*/
/* globals Buffer */
var Fs = require("fs");
var Fse = require("fs-extra");
var Path = require("path");

View file

@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* global Buffer */
const ToPull = require('stream-to-pull-stream');
const Pull = require('pull-stream');

View file

@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process, Buffer */
const HK = require("../hk-util");
const Store = require("../storage/file");
const BlobStore = require("../storage/blob");

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* global process */
const Util = require("../common-util");
const nThen = require('nthen');
const OS = require("os");

2598
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"name": "cryptpad",
"description": "a collaborative office suite that is end-to-end encrypted and open-source",
"version": "2024.6.1",
"description": "realtime collaborative visual editor with zero knowledge server",
"version": "2024.3.0",
"license": "AGPL-3.0+",
"repository": {
"type": "git",
@ -13,6 +13,19 @@
},
"dependencies": {
"@mcrowe/minibloom": "^0.2.0",
"chainpad-crypto": "^0.2.5",
"chainpad-server": "^5.1.0",
"cookie-parser": "^1.4.6",
"body-parser": "^1.20.2",
"express": "~4.19.2",
"fs-extra": "^7.0.0",
"get-folder-size": "^2.0.1",
"netflux-websocket": "^1.0.0",
"http-proxy-middleware": "^2.0.6",
"jsonwebtoken": "^9.0.0",
"notp": "^2.0.3",
"nthen": "0.1.8",
"openid-client": "^5.4.2",
"@node-saml/node-saml": "^4.0.5",
"alertify.js": "1.0.11",
"body-parser": "^1.20.2",
@ -20,8 +33,8 @@
"bootstrap-tokenfield": "^0.12.0",
"chainpad": "^5.2.6",
"chainpad-crypto": "^0.2.5",
"chainpad-listmap": "^1.1.0",
"chainpad-netflux": "^1.2.0",
"chainpad-listmap": "^1.0.0",
"chainpad-netflux": "^1.0.0",
"chainpad-server": "^5.2.0",
"ckeditor": "npm:ckeditor4@~4.22.1",
"codemirror": "^5.19.0",
@ -30,7 +43,7 @@
"croppie": "^2.5.0",
"dragula": "3.7.2",
"drawio": "github:cryptpad/drawio-npm#npm-21.8.2+5",
"express": "~4.19.2",
"express": "~4.18.2",
"file-saver": "1.3.1",
"fs-extra": "^7.0.0",
"get-folder-size": "^2.0.1",
@ -44,7 +57,7 @@
"localforage": "^1.5.2",
"marked": "^4.3.0",
"mathjax": "3.0.5",
"netflux-websocket": "^1.2.0",
"netflux-websocket": "^1.0.0",
"notp": "^2.0.3",
"nthen": "0.1.8",
"open-sans-fontface": "^1.4.0",
@ -63,19 +76,19 @@
"thirty-two": "^1.0.2",
"tweetnacl": "~0.12.2",
"ulimit": "0.0.2",
"ws": "^8.17.1",
"ws": "^3.3.1",
"x2js": "^3.4.4"
},
"devDependencies": {
"eslint": "^8.57.0",
"eslint-plugin-compat": "^4.2.0",
"stylelint": "^16.6.1",
"stylelint-config-standard-less": "^3.0.1"
"lesshint": "6.3.7"
},
"overrides": {
"glob-parent": "5.1.2",
"set-value": "4.0.1",
"minimist": "~1.2.3",
"minimatch": "~3.1.2",
"ws": "^8.17.1",
"jquery": "3.6.0"
},
"scripts": {
@ -86,9 +99,9 @@
"offline": "FRESH=1 OFFLINE=1 node server.js",
"offlinedev": "DEV=1 OFFLINE=1 node server.js",
"package": "PACKAGE=1 node server.js",
"lint": "eslint . && stylelint \"./customize.dist/src/less2/**/*.less\"",
"lint": "eslint . && ./node_modules/lesshint/bin/lesshint -c ./.lesshintrc ./customize.dist/src/less2/",
"lint:js": "eslint .",
"lint:less": "stylelint \"./customize.dist/src/less2/**/*.less\"",
"lint:less": "./node_modules/lesshint/bin/lesshint -c ./.lesshintrc ./customize.dist/src/less2/",
"lint:translations": "node ./scripts/translations/lint-translations.js",
"unused-translations": "node ./scripts/translations/unused-translations.js",
"test": "node scripts/TestSelenium.js",
@ -98,7 +111,5 @@
"clear": "node scripts/clear.js",
"installtoken": "node scripts/install.js"
},
"browserslist": [
"> 0.5%, last 2 versions, Firefox ESR, not dead, not op_mini all"
]
"browserslist": ["> 0.5%, last 2 versions, Firefox ESR, not dead, not op_mini all"]
}

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
# CryptPad
CryptPad is a collaboration suite that is end-to-end-encrypted and open-source. It is built to enable collaboration, synchronizing changes to documents in real time. Because all data are encrypted, in the eventuality of a breach, attackers have no way of seeing the stored content. Moreover, if the administrators dont alter the code, they and the service also cannot infer any piece of information about the users' content.
CryptPad is a collaboration suite that is end-to-end-encrypted and open-source. It is built to enable collaboration, synchronizing changes to documents in real time. Because all data is encrypted, the service and its administrators have no way of seeing the content being edited and stored.
![Drive screenshot](screenshot.png "preview of the CryptDrive")
@ -24,7 +24,7 @@ Configuring CryptPad for production requires a little more work, but the process
## Current version
The most recent version and all past release notes can be found on the [releases page on GitHub](https://github.com/cryptpad/cryptpad/releases/).
The most recent version and all past release notes can be found [here](https://github.com/cryptpad/cryptpad/releases/).
## Setup using Docker
@ -36,7 +36,7 @@ Previously, Docker images were community maintained, had their own repository an
CryptPad offers a variety of collaborative tools that encrypt your data in your browser
before it is sent to the server and your collaborators. In the event that the server is
compromized, the database holds encrypted data that is not of much value to attackers.
compromized the database holds encrypted data that is not of much value to attackers.
The code which performs the encryption is still loaded from the host server like any
other web page, so you still need to trust the administrator to keep their server secure
@ -44,29 +44,23 @@ and to send you the right code. An expert can download code from the server and
that it isn't doing anything malicious like leaking your encryption keys, which is why
this is considered an [active attack].
The platform is designed to minimize what data is exposed to its operators. User
registration and account access are based on cryptographic keys that are derived from your
username and password. Hence, the server never needs to see either, and you don't need to
worry about whether they are being stored securely. It is impossible to verify whether a
server's operators are logging your IP or other activity, so if you consider this
information sensitive it is safest to assume it is being recorded and access your
preferred instance via [Tor browser].
The platform is designed to minimize what data is exposed to its operators. User registration
and account access is based on a cryptographic key that is derived from your username
and password so the server never needs to see either and you don't need to worry about
whether they are being stored securely. It is impossible to verify whether a server's
operators are logging your IP or other activity, so if you consider this information
sensitive it is safest to assume it is being recorded and access your preferred instance
via [Tor browser].
A correctly configured instance has safeguards to prevent collaborators from doing some
nasty things like injecting scripts into collaborative documents or uploads. The project
is actively maintained and bugs that our safeguards don't catch tend to get fixed quickly.
For this reason it is best to only use instances that are running the most recent version,
which is currently on a three-month release cycle. It is difficult for a non-expert to
which is currently on a three-week release cycle. It is difficult for a non-expert to
determine whether an instance is otherwise configured correctly, so we are actively
working on allowing administrators to opt in to a [public directory of
servers](https://cryptpad.org/instances/) that
working on allowing administrators to opt in to a public directory of servers that
meet our strict criteria for safety.
For end users, a [guide](https://blog.cryptpad.org/2024/03/14/Most-Secure-CryptPad-Usage/)
is provided in our blog to help understand the security of CryptPad. This blog post
also explains and show the best practices when using CryptPad and clarify what end-to-end
encryption entails and not.
# Translations
CryptPad can be translated with nothing more than a web browser via our

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* global process */
var WebDriver = require("selenium-webdriver");
var nThen = require('nthen');

View file

@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process */
var Fs = require("fs");
var Fse = require("fs-extra");
var Path = require("path");

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals Buffer */
var Https = require('https');
var Config = require("../lib/load-config");
var Package = require("../package.json");

View file

@ -40,4 +40,5 @@ nThen(function (w) {
console.log(token);
var url = config.httpUnsafeOrigin + '/install/';
console.log(`Please visit ${url} to create your first admin user`);
});

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process */
const jwt = require("jsonwebtoken");
const Sessions = require("../lib/storage/sessions.js");

View file

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process */
var Client = require("../../lib/client");
var Nacl = require("tweetnacl/nacl-fast");
var nThen = require("nthen");

View file

@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process */
var Client = require("../../lib/client/");
var Crypto = require("../../www/components/chainpad-crypto");
var Mailbox = Crypto.Mailbox;

View file

@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* globals process */
var Client = require("../../lib/client/");
var Crypto = require("../../www/components/chainpad-crypto");
var Mailbox = Crypto.Mailbox;

View file

@ -2,6 +2,9 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/*
globals process
*/
var Express = require('express');
var Http = require('http');
var Fs = require('fs');
@ -68,6 +71,13 @@ nThen(function (w) {
Env.Log.info("WEBSERVER_LISTENING", {
origin: url,
});
if (!Env.admins.length) {
Env.Log.info('NO_ADMIN_CONFIGURED', {
message: `Your instance is not correctly configured for production usage. Review its checkup page for more information.`,
details: new URL('/checkup/', Env.httpUnsafeOrigin).href,
});
}
} catch (err) {
Env.Log.error("INVALID_ORIGIN", {
httpUnsafeOrigin: Env.httpUnsafeOrigin,

View file

@ -9,14 +9,12 @@
@import (reference) "../../customize/src/less2/include/creation.less";
@import (reference) '../../customize/src/less2/include/framework.less';
@import (reference) '../../customize/src/less2/include/export.less';
@import (reference) '../../customize/src/less2/include/admin.less';
&.cp-app-admin {
.framework_min_main();
.sidebar-layout_main();
.limit-bar_main();
.creation_main();
.admin_main();
display: flex;
flex-flow: column;
@ -34,16 +32,6 @@
border-radius: 5px;
background-color: @cryptpad_color_brand;
}
input.cp-admin-color-picker {
vertical-align: middle;
}
.cp-palette-container {
display: inline-flex;
width: ~"calc(100% - 5rem)";
padding-left: 0.5rem;
vertical-align: middle;
}
.cp-admin-color-preview {
& > div {
margin-top: @sidebar_base-margin;

View file

@ -5,7 +5,6 @@
define([
'jquery',
'/common/toolbar.js',
'/common/pad-types.js',
'/components/nthen/index.js',
'/common/sframe-common.js',
'/common/common-interface.js',
@ -18,11 +17,11 @@ define([
'/common/hyperscript.js',
'/common/clipboard.js',
'json.sortify',
'/customize/application_config.js',
'/api/config',
'/api/instance',
'/lib/datepicker/flatpickr.js',
'/install/onboardscreen.js',
'/common/hyperscript.js',
'css!/lib/datepicker/flatpickr.min.css',
'css!/components/bootstrap/dist/css/bootstrap.min.css',
'css!/components/components-font-awesome/css/font-awesome.min.css',
@ -30,7 +29,6 @@ define([
], function(
$,
Toolbar,
PadTypes,
nThen,
SFCommon,
UI,
@ -43,12 +41,11 @@ define([
h,
Clipboard,
Sortify,
AppConfig,
ApiConfig,
Instance,
Flatpickr,
Onboarding,
Flatpickr
) {
var APP = window.APP = {};
var Nacl = window.nacl;
@ -93,12 +90,6 @@ define([
'forcemfa',
]
},
'apps': { // Msg.admin_cat_apps
icon: 'fa fa-wrench',
content: [
'apps',
]
},
'users' : { // Msg.admin_cat_users
icon : 'fa fa-address-card-o',
content : [
@ -171,22 +162,6 @@ define([
const blocks = sidebar.blocks;
// EXTENSION_POINT:ADMIN_CATEGORY
common.getExtensions('ADMIN_CATEGORY').forEach(ext => {
if (!ext || !ext.id || !ext.name || !ext.content) {
return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext);
}
if (categories[ext.id]) {
return console.error('Extension point ID already used', ext);
}
console.error(ext);
categories[ext.id] = {
icon: ext.icon,
name: ext.name,
content: ext.content
};
});
const flushCache = (cb) => {
cb = cb || function () {};
sFrameChan.query('Q_ADMIN_RPC', {
@ -634,6 +609,7 @@ define([
UI.log(Messages._getKey('ui_saved', [Messages.admin_emailTitle]));
});
});
var nav = blocks.nav([button]);
var form = blocks.form([
@ -645,35 +621,6 @@ define([
cb(form);
});
sidebar.addItem('apps', function (cb) {
const appsToDisable = ApiConfig.appsToDisable || [];
const grid = Onboarding.createAppsGrid(appsToDisable);
var save = blocks.activeButton('primary', '', Messages.settings_save, function (done) {
sFrameChan.query('Q_ADMIN_RPC', {
cmd: 'ADMIN_DECREE',
data: ['DISABLE_APPS', appsToDisable]
}, function (e, response) {
if (e || response.error) {
UI.warn(Messages.error);
console.error(e, response);
done(false);
return;
}
flushCache();
done(true);
UI.log(Messages._getKey('ui_saved', [Messages.admin_appSelection]));
});
});
let form = blocks.form([
grid
], blocks.nav([save]));
cb(form);
});
sidebar.addItem('instance-info-notice', function(cb){
var key = 'instance-info-notice';
var notice = blocks.alert('info', key, [Messages.admin_infoNotice1, ' ', Messages.admin_infoNotice2]);
@ -843,7 +790,7 @@ define([
var currentContainer = blocks.block([], 'cp-admin-customize-logo');
let redraw = () => {
var current = h('img', {src: '/api/logo?'+(+new Date()),alt:'Custom logo'}); // XXX
var current = h('img', {src: '/api/logo?'+(+new Date())});
$(currentContainer).empty().append(current);
};
redraw();
@ -958,7 +905,7 @@ define([
setColor(color, done);
});
let onColorPicked = () => {
let $input = $(input).on('change', () => {
require(['/lib/less.min.js'], (Less) => {
let color = $input.val();
let lColor = Less.color(color.slice(1));
@ -978,8 +925,7 @@ define([
$preview.find('.cp-admin-color-preview-dark a').attr('style', `color: ${lightColor} !important`);
$preview.find('.cp-admin-color-preview-light a').attr('style', `color: ${color} !important`);
});
};
let $input = $(input).on('change', onColorPicked).addClass('cp-admin-color-picker');
});
UI.confirmButton($remove, {
classes: 'btn-danger',
@ -989,18 +935,9 @@ define([
setColor('', () => {});
});
var colors = UIElements.makePalette(4, (color, $color) => {
// onselect
let rgb = $color.css('background-color');
let hex = Util.rgbToHex(rgb);
$input.val(hex);
onColorPicked();
});
$(label).append(colors);
let form = blocks.form([
labelCurrent,
label,
label
], blocks.nav([btn, remove, btn.spinner]));
cb([form, labelPreview]);
@ -2710,10 +2647,9 @@ define([
var onRefresh = function () {
sFrameChan.query('Q_ADMIN_RPC', {
cmd: 'REGISTERED_USERS',
}, function (e, arr) {
}, function (e, data) {
pre.innerText = '';
let data = arr[0];
pre.append(String(data.users));
pre.append(String(data));
});
};
onRefresh();
@ -3288,6 +3224,10 @@ define([
$active.empty();
if (Broadcast && Broadcast.surveyURL) {
var a = blocks.link(Messages.admin_surveyActive, Broadcast.surveyURL);
$(a).click(function (e) {
e.preventDefault();
common.openUnsafeURL(Broadcast.surveyURL);
});
$active.append([a, removeButton]);
}
});
@ -3895,32 +3835,6 @@ define([
cb(opts);
});
// EXTENSION_POINT:ADMIN_ITEM
let utils = {
h, Util, Hash
};
common.getExtensions('ADMIN_ITEM').forEach(ext => {
if (!ext || !ext.id || typeof(ext.getContent) !== "function") {
return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext);
}
if (sidebar.hasItem(ext.id)) {
return console.error('Extension point ID already used', ext);
}
sidebar.addItem(ext.id, cb => {
ext.getContent(common, blocks, utils, content => {
cb(content);
});
}, {
noTitle: !ext.title,
noHint: !ext.description,
title: ext.title,
hint: ext.description
});
});
sidebar.makeLeftside(categories);
};

View file

@ -106,7 +106,7 @@ define([
framework._.toolbar.$theme.append($showAuthorColors);
markers.setButton($showAuthorColors);
};
var mkPrintButton = function (framework, $content, $print) {
var mkPrintButton = function (framework, $content) {
var $printButton = framework._.sfCommon.createButton('print', true);
$printButton.click(function () {
$print.html($content.html());
@ -115,8 +115,8 @@ define([
framework.feedback('PRINT_CODE');
UI.clearTooltipsDelay();
});
var $dropdownEntry = UIElements.getEntryFromButton($printButton);
framework._.toolbar.$drawer.append($dropdownEntry);
var $print = UIElements.getEntryFromButton($printButton);
framework._.toolbar.$drawer.append($print);
};
var mkMarkdownTb = function (editor, framework) {
var $codeMirrorContainer = $('#cp-app-code-container');

View file

@ -240,15 +240,11 @@ define([
if (!(tab.content || tab.disabled) || !tab.title) { return; }
var content = h('div.alertify-tabs-content', tab.content);
var title = h('span.alertify-tabs-title'+ (tab.disabled ? '.disabled' : ''), h('span.tab-title-text',{id: 'cp-tab-' + tab.title.toLowerCase(), 'aria-hidden':"true"}, tab.title));
$(title).attr('tabindex', '0');
if (tab.icon) {
var icon = h('i', {class: tab.icon, 'aria-labelledby': 'cp-tab-' + tab.title.toLowerCase()});
$(title).prepend(' ').prepend(icon);
}
Util.onClickEnter($(title), function (event) {
event.preventDefault();
event.stopPropagation();
$(title).click(function () {
if (tab.disabled) { return; }
var old = tabs[active];
if (old.onHide) { old.onHide(); }
@ -304,17 +300,14 @@ define([
var $root = $t.parent();
var $input = $root.find('.token-input');
$input.attr('tabindex', 0);
var $button = $(h('button.btn.btn-primary', [
h('i.fa.fa-plus'),
h('span', Messages.tag_add)
]));
Util.onClickEnter($button, function (e) {
$button.click(function () {
$t.tokenfield('createToken', $input.val());
e.stopPropagation();
});
var $container = $(h('span.cp-tokenfield-container'));
@ -332,47 +325,27 @@ define([
if (!$tokens.length) {
$container.prepend(h('span.tokenfield-empty', Messages.kanban_noTags));
}
$tokens.find('.close').attr('tabindex', 0).on('keydown', e => {
e.stopPropagation();
});
$tokens.find('.token-label').attr('tabindex', 0).on('keydown', function (e) {
if (e.which === 13 || e.which === 32) {
$(this).dblclick();
}
e.stopPropagation();
});
$form.append($input);
$form.append($button);
if (isEdit) { $button.find('span').text(Messages.tag_edit); }
else { $button.find('span').text(Messages.add); }
$container.append($form);
$input.focus();
isEdit = false;
called = false;
});
};
resetUI();
const focusInput = () => {
let active = document.activeElement;
if ($.contains($container[0], active)) {
setTimeout(() => {
$input.focus();
});
}
};
$t.on('tokenfield:removedtoken', function () {
resetUI();
focusInput();
});
$t.on('tokenfield:editedtoken', function () {
resetUI();
focusInput();
});
$t.on('tokenfield:createdtoken', function () {
$input.val('');
resetUI();
focusInput();
});
$t.on('tokenfield:edittoken', function () {
isEdit = true;
@ -513,7 +486,7 @@ define([
var navs = [];
buttons.forEach(function (b) {
if (!b.name || !b.onClick) { return; }
var button = h('button', { 'class': b.className || '' }, [
var button = h('button', { tabindex: '1', 'class': b.className || '' }, [
b.iconClass ? h('i' + b.iconClass) : undefined,
b.name
]);
@ -536,8 +509,7 @@ define([
divClasses: 'left'
}, todo);
} else {
Util.onClickEnter($(button), function (e) {
e.stopPropagation();
$(button).click(function () {
todo();
});
}
@ -576,40 +548,6 @@ define([
if (opt.forefront) { $(frame).addClass('forefront'); }
return frame;
};
let addTabListener = frame => {
// find focusable elements
let modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible').filter(':not(:disabled)');
if (modalElements.length === 0) {
// there are no focusable elements -> nothing to do for us here
return;
}
// intialize with focus on first element
modalElements[0].focus();
$(frame).on('keydown', function (e) {
modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible').filter(':not(:disabled)'); // for modals with dynamic content
if (e.which === 9) { // Tab
if (e.shiftKey) {
// On the first element, shift+tab goes to last
if (document.activeElement === modalElements[0]) {
e.preventDefault();
modalElements[modalElements.length - 1].focus();
}
} else {
// On the last element, tab goes to first
if (document.activeElement === modalElements[modalElements.length - 1]) {
e.preventDefault();
modalElements[0].focus();
}
}
}
});
};
UI.openCustomModal = function (content, opt) {
var frame = dialog.frame([
content
@ -626,9 +564,6 @@ define([
setTimeout(function () {
Notifier.notify();
});
addTabListener(frame);
return frame;
};
@ -807,20 +742,13 @@ define([
var $ok = $(ok).click(function (ev) { close(true, ev); });
var $cancel = $(cancel).click(function (ev) { close(false, ev); });
document.body.appendChild(frame);
addTabListener(frame);
listener = listenForKeys(function () {
// Only trigger OK if cancel is not focused
if (document.activeElement === $cancel[0]) {
return void $cancel.click();
}
$ok.click();
}, function () {
$cancel.click();
}, frame);
document.body.appendChild(frame);
setTimeout(function () {
Notifier.notify();
$(frame).find('.ok').focus();
@ -887,19 +815,15 @@ define([
};
var newCls2 = config.new ? 'new' : '';
$(originalBtn).addClass('cp-button-confirm-placeholder').addClass(newCls2).on('click keydown', function (e) {
if (e.type === 'click' || (e.type === 'keydown' && e.key === 'Enter')) {
e.stopPropagation();
// If we have a validation function, continue only if it's true
if (config.validate && !config.validate()) { return; }
i = 1;
to = setTimeout(todo, INTERVAL);
$(originalBtn).hide().after(content);
$(button).focus();
}
$(originalBtn).addClass('cp-button-confirm-placeholder').addClass(newCls2).click(function (e) {
e.stopPropagation();
// If we have a validation function, continue only if it's true
if (config.validate && !config.validate()) { return; }
i = 1;
to = setTimeout(todo, INTERVAL);
$(originalBtn).hide().after(content);
});
return {
reset: function () {
done(false);
@ -953,14 +877,12 @@ define([
opts = opts || {};
var attributes = merge({
type: 'password',
tabindex: '0',
tabindex: '1',
autocomplete: 'one-time-code', // https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#values
}, opts);
var input = h('input.cp-password-input', attributes);
var eye = h('span.fa.fa-eye.cp-password-reveal', {
tabindex: 0
});
var eye = h('span.fa.fa-eye.cp-password-reveal');
var $eye = $(eye);
var $input = $(input);
@ -977,8 +899,7 @@ define([
$input.focus();
});
} else {
Util.onClickEnter($eye, function (e) {
e.stopPropagation();
$eye.click(function () {
if ($eye.hasClass('fa-eye')) {
$input.prop('type', 'text');
$input.focus();
@ -1004,8 +925,7 @@ define([
title: text,
href: href,
target: "_blank",
'data-tippy-placement': "right",
'aria-label': Messages.help_genericMore //TBC XXX
'data-tippy-placement': "right"
});
return q;
};
@ -1144,21 +1064,6 @@ define([
}
};
UI.getNewIcon = function (type) {
var icon = h('i.fa.fa-file-text-o');
if (AppConfig.applicationsIcon && AppConfig.applicationsIcon[type]) {
icon = AppConfig.applicationsIcon[type];
var font = icon.indexOf('cptools') === 0 ? 'cptools' : 'fa';
if (type === 'fileupload') { type = 'file'; }
if (type === 'folderupload') { type = 'file'; }
if (type === 'link') { type = 'drive'; }
var appClass = ' cp-icon cp-icon-color-'+type;
icon = h('i', {'class': font + ' ' + icon + appClass});
}
return icon;
};
var $defaultIcon = $('<span>', {"class": "fa fa-file-text-o"});
UI.getIcon = function (type) {
var $icon = $defaultIcon.clone();
@ -1300,18 +1205,18 @@ define([
if (labelOpts.class) { labelOpts.class += ' cp-checkmark'; }
// Mark properties
var markOpts = { tabindex: 0, role: 'checkbox', 'aria-checked': checked, 'aria-labelledby': inputOpts.id + '-label' };
var markOpts = { tabindex: 0 };
$.extend(markOpts, opts.mark || {});
var input = h('input', inputOpts);
var $input = $(input);
var mark = h('span.cp-checkmark-mark', markOpts);
var $mark = $(mark);
var label = h('span.cp-checkmark-label', {id: inputOpts.id + '-label'}, labelTxt);
var label = h('span.cp-checkmark-label', labelTxt);
$mark.keydown(function (e) {
if ($input.is(':disabled')) { return; }
if (e.which === 32 || e.which === 13){
if (e.which === 32) {
e.stopPropagation();
e.preventDefault();
$input.prop('checked', !$input.is(':checked'));
@ -1323,10 +1228,8 @@ define([
if (!opts.labelAlt) { return; }
if ($input.is(':checked') !== checked) {
$(label).text(opts.labelAlt);
$mark.attr('aria-checked', 'true');
} else {
$(label).text(labelTxt);
$mark.attr('aria-checked', 'false');
}
});
@ -1364,7 +1267,7 @@ define([
$(mark).keydown(function (e) {
if ($input.is(':disabled')) { return; }
if (e.which === 13 || e.which === 32) {
if (e.which === 32) {
e.stopPropagation();
e.preventDefault();
if ($input.is(':checked')) { return; }

View file

@ -173,12 +173,8 @@ define([
var removeBtn, el;
if (config.remove) {
removeBtn = h('span.fa.fa-times');
$(removeBtn).attr('tabindex', '0');
$(removeBtn).on('click keydown', function(event) {
if (event.type === 'click' || (event.type === 'keydown' && event.key === 'Enter')) {
event.preventDefault();
config.remove(el);
}
$(removeBtn).click(function () {
config.remove(el);
});
}
@ -188,7 +184,6 @@ define([
'data-curve': data.curvePublic || '',
'data-name': name.toLowerCase(),
'data-order': i,
'tabindex': config.noSelect ? '-1' : '0',
style: 'order:'+i+';'
},[
avatar,
@ -236,13 +231,6 @@ define([
}
onSelect();
});
$div.on('keydown', '.cp-usergrid-user', function (e) {
if (e.which === 13) {
e.preventDefault();
e.stopPropagation();
$(this).trigger('click');
}
});
}
return {
@ -2657,7 +2645,7 @@ define([
var urlArgs = (Config.requireConf && Config.requireConf.urlArgs) || '';
var logo = h('img', { src: '/customize/CryptPad_logo.svg?' + urlArgs });
var fill1 = h('div.cp-creation-fill.cp-creation-logo',{ role: 'presentation' }, logo);
var fill1 = h('div.cp-creation-fill.cp-creation-logo', logo);
var fill2 = h('div.cp-creation-fill');
var $creation = $('<div>', { id: 'cp-creation', tabindex:1 });
$creationContainer.append([fill1, $creation, fill2]);
@ -4297,76 +4285,5 @@ define([
return UI.errorLoadingScreen(msg, false, false);
};
UIElements.makePalette = (maxColors, onSelect) => {
let palette = [''];
for (var i=1; i<=maxColors; i++) { palette.push('color'+i); }
let offline = false;
let selectedColor = '';
let container = h('div.cp-palette-container');
let $container = $(container);
var all = [];
palette.forEach(function (color, i) {
var $color = $(h('button.cp-palette-color.fa'));
all.push($color);
$color.addClass('cp-palette-'+(color || 'nocolor'));
$color.keydown(function (e) {
if (e.which === 13) {
e.stopPropagation();
e.preventDefault();
$color.click();
}
});
$color.click(function () {
if (offline) { return; }
if (color === selectedColor) { return; }
selectedColor = color;
$container.find('.cp-palette-color').removeClass('fa-check');
$color.addClass('fa-check');
onSelect(color, $color);
}).appendTo($container);
$color.keydown(e => {
if (e.which === 37) {
e.preventDefault();
if (i === 0) {
all[all.length - 1].focus();
} else {
all[i - 1].focus();
}
}
if (e.which === 39) {
e.preventDefault();
if (i === (all.length - 1)) {
all[0].focus();
} else {
all[i + 1].focus();
}
}
if (e.which === 9) {
if (e.shiftKey) {
all[0].focus();
return;
}
all[all.length - 1].focus();
}
});
});
container.disable = state => {
offline = !!state;
};
container.getValue = () => {
return selectedColor;
};
container.setValue = color => {
$container.find('.cp-palette-color').removeClass('fa-check');
let $color = $container.find('.cp-palette-'+(color || 'nocolor'));
$color.addClass('fa-check');
selectedColor = color;
};
return container;
};
return UIElements;
});

View file

@ -606,9 +606,6 @@
parseInt(h.slice(4,6), 16),
];
};
Util.rgbToHex = function (rgb) {
return `#${rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/).slice(1).map(n => parseInt(n, 10).toString(16).padStart(2, '0')).join('')}`;
};
Util.isSmallScreen = function () {
return window.innerHeight < 800 || window.innerWidth < 800;

View file

@ -2822,15 +2822,6 @@ define([
initFeedback(data.feedback);
}
if (data.edPublic) {
if (Array.isArray(Config.adminKeys) &&
Config.adminKeys.includes(data.edPublic)) {
// Doesn't provides extra-rights but may show
// additional warnings in the UI
localStorage.CP_admin = "1";
}
}
if (data.loggedIn) {
window.CP_logged_in = true;
}

View file

@ -1197,12 +1197,11 @@ define([
});
};
// `app`: true (force open with the app), false (force open in preview),
// `app`: true (force open wiht the app), false (force open in preview),
// falsy (open in preview if default is not using the app)
var defaultInApp = ['application/pdf'];
var openFile = function (el, isRo, app) {
// In anonymous drives, `el` already contains file data
var data = el.channel ? el : manager.getFileData(el);
var data = manager.getFileData(el);
if (data.static) {
if (data.href) {
@ -2247,7 +2246,6 @@ define([
$element.prepend(img);
$(img).addClass('cp-app-drive-element-grid cp-app-drive-element-thumbnail');
$(img).attr("draggable", false);
$(img).attr("role", "presentation");
addTitleIcon(element, $name);
} else {
common.displayThumbnail(href || data.roHref, data.channel, data.password, $element, function ($thumb) {

View file

@ -1,63 +0,0 @@
// SPDX-FileCopyrightText: 2024 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
define([
'optional!/extensions.js'
], (Extensions) => {
const ext = {};
ext.getExtensions = id => {
let e = ext[id];
if (!Array.isArray(e)) { e = []; }
return e;
};
if (!Array.isArray(Extensions) || !Extensions.length) { return ext; }
let all = Extensions.slice();
while(all.length) {
let current = all.splice(0, 3);
let f = current[0];
if (typeof(f) !== "function") {
continue;
}
let defaultLang = current[1];
let lang = current[2];
if (!Object.keys(lang).length && Object.keys(defaultLang).length) {
// If our language doesn't exists, use default
lang = defaultLang;
} else if (Object.keys(defaultLang).length) {
// Otherwise fill our language with missing keys
Object.keys(defaultLang).forEach(key => {
if (typeof(lang[key]) !== "undefined") { return; }
lang[key] = defaultLang[key];
});
}
lang._getKey = function (key, argArray) {
if (!lang[key]) { return '?'; }
var text = lang[key];
if (typeof(text) === 'string') {
return text.replace(/\{(\d+)\}/g, function (str, p1) {
if (typeof(argArray[p1]) === 'string' || typeof(argArray[p1]) === "number") {
return argArray[p1];
}
return '';
});
} else {
return text;
}
};
let currentExt = f(lang) || {};
Object.keys(currentExt).forEach(key => {
ext[key] = ext[key] || [];
Array.prototype.push.apply(ext[key], currentExt[key]); // concat in place
});
}
return ext;
});

View file

@ -367,13 +367,6 @@ define([
UI.log(Messages.saved);
});
});
$(addBtn).on('keydown', function () {
if (event.keyCode === 13) {
event.preventDefault();
event.stopPropagation();
$(addBtn).click();
}
});
var called = false;
redrawAll = function (reload) {
@ -466,9 +459,6 @@ define([
var setLock = function (locked) {
$(link).find('.cp-overlay').toggle(locked);
$(link).find('.cp-usergrid-user').attr('tabindex', locked ? -1 : 0);
$(link).find('.cp-usergrid-filter input').prop('disabled', locked);
$(link).find('.cp-access-add').prop('disabled', locked);
};
// Remove owner column
@ -724,13 +714,6 @@ define([
UI.log(Messages.saved);
});
});
$(addBtn).on('keydown', function () {
if (event.keyCode === 13) {
event.preventDefault();
event.stopPropagation();
$(addBtn).click();
}
});
var called = false;
redrawAll = function (reload) {
@ -1042,13 +1025,6 @@ define([
});
});
});
$(passwordOk).on('keydown', function (e) {
if (e.keyCode === 13) {
e.preventDefault();
e.stopPropagation();
$(passwordOk).click();
}
});
$d.append(changePass);
}
if (owned) {

View file

@ -385,13 +385,13 @@ define([
h('label', Messages.sharedFolders_share),
h('br'),
] : [
UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:0} }),
UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:1} }),
];
if (opts.static) { linkContent = []; }
linkContent.push(h('div.cp-spacer'));
linkContent.push(UI.dialog.selectableArea('', { id: 'cp-share-link-preview', tabindex: 0, rows:3}));
linkContent.push(UI.dialog.selectableArea('', { id: 'cp-share-link-preview', tabindex: 1, rows:3}));
// Show alert if the pad is password protected
if (opts.hasPassword) {
@ -553,7 +553,7 @@ define([
var embedContent = [
h('p', Messages.viewEmbedTag),
UI.dialog.selectableArea(opts.getEmbedValue(), { id: 'cp-embed-link-preview', tabindex: 0, rows: 3})
UI.dialog.selectableArea(opts.getEmbedValue(), { id: 'cp-embed-link-preview', tabindex: 1, rows: 3})
];
// Show alert if the pad is password protected
@ -611,24 +611,24 @@ define([
labelEdit = Messages.share_formEdit;
labelView = Messages.share_formView;
auditor = UI.createRadio('accessRights', 'cp-share-form', Messages.share_formAuditor, false, {
mark: {tabindex:0},
mark: {tabindex:1},
});
}
var burnAfterReading = (hashes.viewHash && canBAR) ?
UI.createRadio('accessRights', 'cp-share-bar', Messages.burnAfterReading_linkBurnAfterReading, false, {
mark: {tabindex:0},
mark: {tabindex:1},
label: {style: "display: none;"}
}) : undefined;
var rights = h('div.msg.cp-inline-radio-group', [
h('label',{ for: 'cp-share-editable-true' }, Messages.share_linkAccess),
h('div.radio-group',[
UI.createRadio('accessRights', 'cp-share-editable-false',
labelView, true, { mark: {tabindex:0} }),
labelView, true, { mark: {tabindex:1} }),
canPresent ? UI.createRadio('accessRights', 'cp-share-present',
Messages.share_linkPresent, false, { mark: {tabindex:1} }) : undefined,
UI.createRadio('accessRights', 'cp-share-editable-true',
labelEdit, false, { mark: {tabindex:0} }),
labelEdit, false, { mark: {tabindex:1} }),
auditor]),
burnAfterReading,
]);
@ -921,7 +921,7 @@ define([
var cb = Util.once(Util.mkAsync(_cb));
var linkContent = [
UI.dialog.selectableArea(opts.getLinkValue(), {
id: 'cp-share-link-preview', tabindex: 0, rows:2
id: 'cp-share-link-preview', tabindex: 1, rows:2
})
];

View file

@ -4,7 +4,6 @@
define([
'jquery',
'/api/config',
'/components/nthen/index.js',
'/common/common-interface.js',
'/common/common-ui-elements.js',
@ -14,7 +13,6 @@ define([
'/common/hyperscript.js',
], function(
$,
ApiConfig,
nThen,
UI,
UIElements,
@ -24,26 +22,17 @@ define([
h
) {
const Sidebar = {};
const keyToCamlCase = (key) => {
return key.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
};
Sidebar.blocks = function (app, common) {
let blocks = {};
// sframe-common shim
if (!common) {
common = {
openURL: url => {
window.open(url);
},
openUnsafeURL: url => {
window.open(ApiConfig.httpSafeOrigin + '/bounce/#' + encodeURIComponent(url));
}
};
}
Sidebar.create = function (common, app, $container) {
const $leftside = $(h('div#cp-sidebarlayout-leftside')).appendTo($container);
const $rightside = $(h('div#cp-sidebarlayout-rightside')).appendTo($container);
const sidebar = {
$leftside,
$rightside
};
const items = {};
let blocks = sidebar.blocks = {};
blocks.labelledInput = (label, input, inputBlock) => {
let uid = Util.uid();
let id = `cp-${app}-item-${uid}`;
@ -120,7 +109,7 @@ define([
element
]);
};
blocks.pre = (value) => {
blocks.pre = (value) => {
return h('pre', value);
};
@ -231,7 +220,9 @@ define([
return button;
};
const keyToCamlCase = (key) => {
return key.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
};
blocks.activeCheckbox = (data) => {
const state = data.getState();
const key = data.key;
@ -255,52 +246,34 @@ define([
return box;
};
return blocks;
};
Sidebar.create = function (common, app, $container) {
const $leftside = $(h('div#cp-sidebarlayout-leftside')).appendTo($container);
const $rightside = $(h('div#cp-sidebarlayout-rightside')).appendTo($container);
const sidebar = {
$leftside,
$rightside
};
const items = {};
sidebar.blocks = Sidebar.blocks(app, common);
sidebar.addItem = (key, get, options) => {
const safeKey = keyToCamlCase(key);
const div = h(`div.cp-sidebarlayout-element`, {
'data-item': key,
style: 'display:none;'
});
items[key] = div;
$rightside.append(div);
get((content) => {
if (content === false) {
delete items[key];
return void $(div).remove();
}
if (content === false) { return; }
options = options || {};
const title = options.noTitle ? undefined : h('label.cp-item-label', {
id: `cp-${app}-${key}`
}, options.title || Messages[`${app}_${safeKey}Title`] || key);
}, Messages[`${app}_${safeKey}Title`] || key);
const hint = options.noHint ? undefined : h('span.cp-sidebarlayout-description',
options.hint || Messages[`${app}_${safeKey}Hint`] || 'Coming soon...');
Messages[`${app}_${safeKey}Hint`] || 'Coming soon...');
if (hint && options.htmlHint) {
hint.innerHTML = Messages[`${app}_${safeKey}Hint`];
}
$(div).append(title).append(hint).append(content);
const div = h(`div.cp-sidebarlayout-element`, {
'data-item': key,
style: 'display:none;'
}, [
title,
hint,
content
]);
items[key] = div;
$rightside.append(div);
});
};
sidebar.hasItem = key => {
return !key || !!items[key];
};
sidebar.addCheckboxItem = (data) => {
const key = data.key;
let blocks = sidebar.blocks;
let box = blocks.activeCheckbox(data);
sidebar.addItem(key, function (cb) {
cb(box);
@ -352,7 +325,7 @@ define([
'data-category': key
}, [
icon,
category.name || Messages[`${app}_cat_${key}`] || key,
Messages[`${app}_cat_${key}`] || key,
]);
var $item = $(item).appendTo(container);
Util.onClickEnter($item, function () {

View file

@ -107,11 +107,9 @@ define([
var myOOId;
var sessionId = Hash.createChannelId();
var cpNfInner;
let integrationChannel;
var evOnPatch = Util.mkEvent();
var evOnSync = Util.mkEvent();
var evIntegrationSave = Util.mkEvent();
// This structure is used for caching media data and blob urls for each media cryptpad url
var mediasData = {};
@ -181,11 +179,15 @@ define([
});
};
const getNewUserIndex = function () {
const ids = content.ids || {};
const indexes = Object.values(ids).map((user) => user.index);
const maxIndex = Math.max(...indexes);
return maxIndex === -Infinity ? 1 : maxIndex+1;
var getUserIndex = function () {
var i = 1;
var ids = content.ids || {};
Object.keys(ids).forEach(function (k) {
if (ids[k] && ids[k].index && ids[k].index >= i) {
i = ids[k].index + 1;
}
});
return i;
};
var setMyId = function () {
@ -196,7 +198,7 @@ define([
myOOId = Util.createRandomInteger();
// f: function used in .some(f) but defined outside of the while
var f = function (id) {
return ids[id].ooid === myOOId;
return ids[id] === myOOId;
};
while (Object.keys(ids).some(f)) {
myOOId = Util.createRandomInteger();
@ -205,7 +207,7 @@ define([
var myId = getId();
ids[myId] = {
ooid: myOOId,
index: getNewUserIndex(),
index: getUserIndex(),
netflux: metadataMgr.getNetfluxId()
};
oldIds = JSON.parse(JSON.stringify(ids));
@ -315,10 +317,7 @@ define([
isCp: cp
}
}, function (err, h) {
if (!err) {
evOnSync.fire();
evIntegrationSave.fire();
}
if (!err) { evOnSync.fire(); }
cb(err, h);
});
},
@ -913,18 +912,6 @@ define([
});
};
const findUserByOOId = function(ooId) {
return Object.values(content.ids)
.find((user) => user.ooid === ooId);
};
const getMyOOIndex = function() {
const user = findUserByOOId(myOOId);
return user
? user.index
: content.ids.length; // Assign an unused id to read-only users
};
var getParticipants = function () {
var users = metadataMgr.getMetadata().users;
var i = 1;
@ -956,19 +943,19 @@ define([
isCloseCoAuthoring:false,
view: false
});
const myOOIndex = getMyOOIndex();
if (!myUniqueOOId) { myUniqueOOId = String(myOOId) + myOOIndex; }
i++;
if (!myUniqueOOId) { myUniqueOOId = String(myOOId) + i; }
p.push({
id: String(myOOId),
id: myUniqueOOId,
idOriginal: String(myOOId),
username: metadataMgr.getUserData().name || Messages.anonymous,
indexUser: myOOIndex,
indexUser: i,
connectionId: metadataMgr.getNetfluxId() || Hash.createChannelId(),
isCloseCoAuthoring:false,
view: false
});
return {
index: myOOIndex,
index: i,
list: p.filter(Boolean)
};
};
@ -1431,9 +1418,6 @@ define([
debug(obj, 'toOO');
chan.event('CMD', obj);
if (obj && obj.type === "saveChanges") {
evIntegrationSave.fire();
}
};
chan.on('CMD', function (obj) {
@ -1481,10 +1465,6 @@ define([
send({ type: "message" });
break;
case "saveChanges":
if (readOnly) {
return;
}
// If we have unsaved data before reloading for a checkpoint...
if (APP.onStrictSaveChanges) {
delete APP.unsavedLocks;
@ -1612,15 +1592,13 @@ define([
var x2tConvertData = function (data, fileName, format, cb) {
var sframeChan = common.getSframeChannel();
var editor = getEditor();
var fonts = editor && editor.FontLoader.fontInfos;
var files = editor && editor.FontLoader.fontFiles.map(function (f) {
var e = getEditor();
var fonts = e && e.FontLoader.fontInfos;
var files = e && e.FontLoader.fontFiles.map(function (f) {
return { 'Id': f.Id, };
});
var type = common.getMetadataMgr().getPrivateData().ooType;
const images = editor
? structuredClone(window.frames[0].AscCommon.g_oDocumentUrls.getUrls())
: {};
var images = (e && window.frames[0].AscCommon.g_oDocumentUrls.urls) || {};
// Fix race condition which could drop images sometimes
// ==> make sure each image has a 'media/image_name.ext' entry as well
@ -1631,7 +1609,7 @@ define([
});
// Add theme images
var theme = editor && window.frames[0].AscCommon.g_image_loader.map_image_index;
var theme = e && window.frames[0].AscCommon.g_image_loader.map_image_index;
if (theme) {
Object.keys(theme).forEach(function (url) {
if (!/^(\/|blob:|data:)/.test(url)) {
@ -1645,7 +1623,7 @@ define([
type: type,
fileName: fileName,
outputFormat: format,
images: (editor && window.frames[0].AscCommon.g_oDocumentUrls.urls) || {},
images: (e && window.frames[0].AscCommon.g_oDocumentUrls.urls) || {},
fonts: fonts,
fonts_files: files,
mediasSources: getMediasSources(),
@ -1859,11 +1837,6 @@ define([
}
delete APP.oldCursor;
}
if (integrationChannel) {
APP.onDocumentUnlock = () => {
integrationChannel.event('EV_INTEGRATION_READY');
};
}
}
delete APP.startNew;
@ -2078,15 +2051,6 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
if (blobUrl) {
delete downloadImages[name];
debug("CryptPad Image already loaded " + blobUrl);
// Fix: https://github.com/cryptpad/cryptpad/issues/1500
// Maybe OO was reloaded, but the CryptPad cache is still intact?
// -> Add the image to OnlyOffice again.
const documentUrls = window.frames[0].AscCommon.g_oDocumentUrls;
if (!(data.name in documentUrls.getUrls())) {
documentUrls.addImageUrl(data.name, blobUrl);
}
return void callback(blobUrl);
}
@ -2600,22 +2564,6 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
});
};
sframeChan.on('EV_INTEGRATION_DOWNLOADAS', function (format) {
console.error('DOWNLOAD AS RECEIVED');
var data = getContent();
x2tConvertData(data, "document.bin", format, function (xlsData) {
UI.removeModals();
if (xlsData) {
var blob = new Blob([xlsData], {type: "application/bin;charset=utf-8"});
if (integrationChannel) {
integrationChannel.event('EV_INTEGRATION_ON_DOWNLOADAS',
blob, { raw: true });
}
return;
}
UI.warn(Messages.error);
});
});
sframeChan.on('EV_OOIFRAME_REFRESH', function (data) {
// We want to get the "bin" content of a sheet from its json in order to download
// something useful from a non-onlyoffice app (download from drive or settings).
@ -2720,6 +2668,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
};
var onCheckpoint = function (cp) {
// We want to load a checkpoint:
console.log('XXX onCheckpoint', JSON.stringify(cp));
loadCp(cp);
};
var setHistoryMode = function (bool) {
@ -3168,73 +3117,6 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
UI.removeLoadingScreen();
};
let convertImportBlob = (blob, title) => {
new Response(blob).arrayBuffer().then(function (buffer) {
var u8Xlsx = new Uint8Array(buffer);
x2tImportData(u8Xlsx, title, 'bin', function (bin) {
if (!bin) {
return void UI.errorLoadingScreen(Messages.error);
}
var blob = new Blob([bin], {type: 'text/plain'});
var file = getFileType();
resetData(blob, file);
//saveToServer(blob, title);
Title.updateTitle(title);
UI.removeLoadingScreen();
});
});
};
if (privateData.integration) {
let cfg = privateData.integrationConfig || {};
common.openIntegrationChannel(APP.onLocal);
integrationChannel = common.getSframeChannel();
var integrationSave = function (cb) {
var ext = cfg.fileType;
var upload = Util.once(function (_blob) {
integrationChannel.query('Q_INTEGRATION_SAVE', {
blob: _blob
}, cb, {
raw: true
});
});
var data = getContent();
x2tConvertData(data, "document.bin", ext, function (xlsData) {
UI.removeModals();
if (xlsData) {
var blob = new Blob([xlsData], {type: "application/bin;charset=utf-8"});
upload(blob);
return;
}
UI.warn(Messages.error);
});
};
const integrationHasUnsavedChanges = function(unsavedChanges, cb) {
integrationChannel.query('Q_INTEGRATION_HAS_UNSAVED_CHANGES', unsavedChanges, cb);
};
var inte = common.createIntegration(integrationSave,
integrationHasUnsavedChanges);
if (inte) {
evIntegrationSave.reg(function () {
inte.changed();
});
}
integrationChannel.on('Q_INTEGRATION_NEEDSAVE', function (data, cb) {
integrationSave(function (obj) {
if (obj && obj.error) { console.error(obj.error); }
cb();
});
});
if (privateData.initialState) {
var blob = privateData.initialState;
let title = `document.${cfg.fileType}`;
console.error(blob, title);
return convertImportBlob(blob, title);
}
}
if (privateData.isNewFile && privateData.fromFileData) {
try {
(function () {

View file

@ -11,15 +11,12 @@ define([
'/common/sframe-common-outer.js'
], function (nThen, ApiConfig, DomReady, Hash, SFCommonO) {
var isIntegration = Boolean(window.CP_integration_outer);
var integration = window.CP_integration_outer || {};
// Loaded in load #2
var hash, href, version;
nThen(function (waitFor) {
DomReady.onReady(waitFor());
}).nThen(function (waitFor) {
var obj = SFCommonO.initIframe(waitFor, true, integration.pathname);
var obj = SFCommonO.initIframe(waitFor, true);
href = obj.href;
hash = obj.hash;
var parsed = Hash.parsePadUrl(href);
@ -27,14 +24,9 @@ define([
var opts = parsed.getOptions();
version = opts.versionHash;
}
if (isIntegration) {
href = integration.href;
hash = integration.hash;
}
}).nThen(function (/*waitFor*/) {
var addData = function (obj) {
let path = (integration && integration.pathname) || window.location.pathname;
obj.ooType = path.replace(/^\//, '').replace(/\/$/, '');
obj.ooType = window.location.pathname.replace(/^\//, '').replace(/\/$/, '');
obj.ooVersionHash = version;
obj.ooForceVersion = localStorage.CryptPad_ooVersion || "";
};
@ -162,21 +154,18 @@ define([
Utils.initUnsafeIframe(obj, cb);
});
};
SFCommonO.start({
hash: hash,
href: href,
type: 'oo',
useCreationScreen: true,
addData: addData,
addRpc: addRpc,
getPropChannels: getPropChannels,
messaging: true,
useCreationScreen: !isIntegration,
noDrive: true,
integration: isIntegration,
integrationUtils: integration.utils,
integrationConfig: integration.config || {},
initialState: integration.initialState || undefined
messaging: true
});
});
});

View file

@ -3014,8 +3014,6 @@ define([
// Make sure we have a valid user object before emitting cacheready
if (rt.proxy && !rt.proxy.drive) { return; }
returned.edPublic = rt.proxy.edPublic;
onCacheReady(clientId, function () {
if (typeof(cb) === "function") { cb(returned); }
onCacheReadyEvt.fire();
@ -3049,8 +3047,6 @@ define([
drive[Constants.oldStorageKey] = [];
}
*/
returned.edPublic = rt.proxy.edPublic;
// Drive already exist: return the existing drive, don't load data from legacy store
if (store.manager) {
// If a cache is loading, make sure it is complete before calling onReady
@ -3160,7 +3156,6 @@ define([
loadUniversal(Cursor, 'cursor', function () {});
loadUniversal(Integration, 'integration', function () {});
loadUniversal(Messenger, 'messenger', function () {});
loadOnlyOffice();
store.messenger = store.modules['messenger'];
// And now we're ready

View file

@ -1055,7 +1055,7 @@ define([
var removeClient = function (ctx, cId) {
var idx = ctx.clients.indexOf(cId);
if (idx !== -1) { ctx.clients.splice(idx, 1); }
ctx.clients.splice(idx, 1);
Object.keys(ctx.calendars).forEach(function (id) {
var cal = ctx.calendars[id];

View file

@ -6,8 +6,8 @@
importScripts('/components/requirejs/require.js');
window = self; // eslint-disable-line no-global-assign
localStorage = { // eslint-disable-line no-global-assign
window = self;
localStorage = {
setItem: function (k, v) { localStorage[k] = v; },
getItem: function (k) { return localStorage[k]; }
};

View file

@ -6,8 +6,8 @@
importScripts('/components/requirejs/require.js');
window = self; // eslint-disable-line no-global-assign
localStorage = { // eslint-disable-line no-global-assign
window = self;
localStorage = {
setItem: function (k, v) { localStorage[k] = v; },
getItem: function (k) { return localStorage[k]; }
};

View file

@ -6,8 +6,8 @@
importScripts('/components/requirejs/require.js');
window = self; // eslint-disable-line no-global-assign
localStorage = { // eslint-disable-line no-global-assign
window = self;
localStorage = {
setItem: function (k, v) { localStorage[k] = v; },
getItem: function (k) { return localStorage[k]; }
};

View file

@ -12,7 +12,7 @@ define([
var CURRENT_VERSION = X2T.CURRENT_VERSION = CurrentVersion.currentVersion;
var debug = function (str) {
//if (localStorage.CryptPad_dev !== "1") { return; }
if (localStorage.CryptPad_dev !== "1") { return; }
console.debug(str);
};

View file

@ -12,22 +12,12 @@ define([
OOCurrentVersion.currentVersion,
);
let availablePadTypes = AppConfig.availablePadTypes.filter(
(t) => ooEnabled || !OO_APPS.includes(t)
let availableTypes = AppConfig.availablePadTypes.filter(
(t) => ooEnabled || !OO_APPS.includes(t),
);
let availableTypes;
if (ApiConfig.appsToDisable) {
availableTypes = availablePadTypes.filter(value => !ApiConfig.appsToDisable.includes(value));
} else {
availableTypes = availablePadTypes;
}
var appsToSelect = availablePadTypes.filter(value => !['drive', 'teams', 'file', 'contacts', 'convert'].includes(value));
return {
availableTypes,
appsToSelect,
isAvailable: function (type) {
return availableTypes.includes(type);

View file

@ -648,8 +648,8 @@ define([
const integrationHasUnsavedChanges = function(unsavedChanges, cb) {
integrationChannel.query('Q_INTEGRATION_HAS_UNSAVED_CHANGES', unsavedChanges, cb);
};
var inte = common.createIntegration(integrationSave,
integrationHasUnsavedChanges);
var inte = common.createIntegration(onLocal, cpNfInner.chainpad,
integrationSave, integrationHasUnsavedChanges);
if (inte) {
integration = true;
evIntegrationSave.reg(function () {

View file

@ -176,10 +176,6 @@ define([
else { editor.execCommand("insertTab"); }
}
},
//remove focus from editor
"Esc": function () {
editor.display.input.blur();
},
"Shift-Tab": function () {
editor.execCommand("indentLess");
},

View file

@ -9,6 +9,8 @@ define([
module.create = function (
Common,
onLocal,
chainpad,
saveHandler,
unsavedChangesHandler) {

View file

@ -78,7 +78,6 @@ define([
requireConfig.urlArgs + '#' + encodeURIComponent(JSON.stringify(req)));
$i.attr('allowfullscreen', 'true');
$i.attr('allow', 'clipboard-write');
$i.attr('title', 'iframe');
$('iframe-placeholder').after($i).remove();
// This is a cheap trick to avoid loading sframe-channel in parallel with the
@ -2077,16 +2076,6 @@ define([
cfg.integrationUtils.save(obj, cb);
}
});
sframeChan.on('EV_INTEGRATION_READY', function () {
if (cfg.integrationUtils && cfg.integrationUtils.onReady) {
cfg.integrationUtils.onReady();
}
});
sframeChan.on('EV_INTEGRATION_ON_DOWNLOADAS', function (obj) {
if (cfg.integrationUtils && cfg.integrationUtils.onDownloadAs) {
cfg.integrationUtils.onDownloadAs(obj);
}
});
sframeChan.on('Q_INTEGRATION_HAS_UNSAVED_CHANGES', function (obj, cb) {
if (cfg.integrationUtils && cfg.integrationUtils.onHasUnsavedChanges) {
cfg.integrationUtils.onHasUnsavedChanges(obj, cb);
@ -2100,15 +2089,6 @@ define([
integrationSave = function (cb) {
sframeChan.query('Q_INTEGRATION_NEEDSAVE', null, cb);
};
if (cfg.integrationUtils) {
if (cfg.integrationUtils.setDownloadAs) {
cfg.integrationUtils.setDownloadAs(format => {
sframeChan.event('EV_INTEGRATION_DOWNLOADAS', format);
});
}
}
}
if (cfg.messaging) {

View file

@ -34,7 +34,6 @@ define([
'/common/common-constants.js',
'/components/localforage/dist/localforage.min.js',
'/common/hyperscript.js',
'/common/extensions.js'
], function (
$,
ApiConfig,
@ -65,8 +64,7 @@ define([
Language,
Constants,
localForage,
h,
Ext
h
) {
// Chainpad Netflux Inner
var funcs = {};
@ -777,8 +775,6 @@ define([
return Util.checkRestrictedApp(app, AppConfig, ea, priv.plan, priv.loggedIn);
};
funcs.getExtensions = Ext.getExtensions;
funcs.mailbox = {};
Object.freeze(funcs);

View file

@ -1195,7 +1195,6 @@ MessengerUI, Messages, Pages, PadTypes) {
if (![13,32,46].includes(e.which)) { return; }
e.stopPropagation();
if (e.which === 46) {
$('body').find('.cp-dropdown-content li').first().focus();
return $(el).find('.cp-notification-dismiss').click();
}
$(el).find('.cp-notification-content').click();

View file

@ -366,85 +366,5 @@
"login_invalUser": "Изисква се потребителско име",
"login_confirm": "Потвърдете паролата",
"login_unhandledError": "Възникна неочаквана грешка :(",
"settings_exportWarning": "Забележка: този инструмент все още е в бета версия и може да има проблеми с мащабируемостта. За по-добра производителност се препоръчва да оставите този раздел на фокус - без превключване на друг раздел.",
"settings_export_reading": "Четене от вашият CryptDrive...",
"settings_export_download": "Изтегляне и декриптиране на вашите документи...",
"settings_export_compressing": "Данните се компресират...",
"settings_exportError": "Вижте грешките",
"settings_exportErrorEmpty": "Този документ не може да бъде експортиран (липсващо или невалидно съдържание).",
"settings_exportErrorOther": "Възникна грешка при опит за експортиране на този документ: {0}",
"settings_resetNewTitle": "Почистване на CryptDrive",
"settings_resetButton": "Премахване",
"settings_resetDone": "Вашият диск вече е празен!",
"settings_resetError": "Неправилен текст за потвърждение. Вашият CryptDrive не е променен.",
"settings_resetTipsAction": "Нулиране",
"settings_resetTips": "Съвети",
"settings_resetTipsButton": "Нулиране на наличните съвети в CryptDrive",
"settings_resetTipsDone": "Всички съвети вече са видими отново.",
"settings_thumbnails": "Миниатюри",
"settings_disableThumbnailsAction": "Деактивиране на създаването на миниатюри във вашия CryptDrive",
"settings_resetThumbnailsAction": "Почистване",
"settings_resetThumbnailsDescription": "Почистване на всички миниатюри на документи, съхранени във вашия браузър.",
"settings_resetThumbnailsDone": "Всички миниатюри са изтрити.",
"settings_importTitle": "Импортиране на последните документи в браузъра във вашия CryptDrive",
"settings_export_done": "Вашето сваляне приключи!",
"settings_exportErrorDescription": "Не успяхме да добавим следните документи в експортирания файл:",
"settings_exportErrorMissing": "Този документ липсва на нашите сървъри (изтекъл му е срокът на съхранение или е изтрит от собственика му)",
"settings_reset": "Премахване на всички файлове и папки от вашия CryptDrive",
"settings_resetPrompt": "С това действие ще премахне всички документи от вашето устройство.<br>Сигурни ли сте, че искате да продължите?<br>Напишете “<em>Обичам CryptPad</em>”, за да потвърдите.",
"settings_disableThumbnailsDescription": "Миниатюрите се създават автоматично и се съхраняват във вашия браузър, когато влезете в нов документ. Можете да деактивирате тази функция тук.",
"settings_autostoreTitle": "Съхранение на документи в CryptDrive",
"settings_import": "Импортиране",
"settings_importConfirm": "Сигурни ли сте, че искате да импортирате последните документи от този браузър в CryptDrive във потребителския ви акаунт?",
"settings_importDone": "Импортирането завърши",
"settings_autostoreHint": "<b>Автоматично</b> Всички документи, които ползвате, се съхраняват във вашия CryptDrive.<br><b>Ръчно (винаги се иска потвърждаване)</b> Ако все още не сте съхранили документ, ще бъдете попитани дали искате, да ги съхранявате във вашия CryptDrive.<br><b>Ръчно (никога не се иска потвърждаване)</b> Документите не се съхраняват автоматично във вашия CryptDrive. Опцията за съхраняването им ще бъде скрита.",
"settings_autostoreYes": "Автоматично",
"settings_autostoreNo": "Ръчно (никога не се иска потвърждаване)",
"settings_autostoreMaybe": "Ръчно (вининаги се иска потвърждаване)",
"settings_userFeedbackTitle": "Обратна връзка",
"settings_userFeedbackHint1": "CryptPad предоставя обратна връзка на сървъра, за да ни уведоми как да подобрим вашия опит. ",
"settings_userFeedbackHint2": "Съдържанието на вашите документи никога няма да бъде споделено със сървъра.",
"settings_userFeedback": "Активиране на обратната връзка с потребителя",
"settings_deleteTitle": "Изтриване на акаунта",
"settings_deleteHint": "Изтриването на акаунта е окончателно. Вашият CryptDrive и вашият списък с документи ще бъдат изтрити от сървъра. Останалите ви документи ще бъдат изтрити след 90 дни, ако никой друг не ги е съхранил в своя CryptDrive.",
"settings_deleteButton": "Изтриване на акаунта си",
"settings_deleteModal": "Споделете следната информация с вашия администратор на CryptPad, за да бъдат премахнати данните ви от сървъра им.",
"settings_publicSigningKey": "Публичен ключ за подписване",
"settings_deleted": "Вашият потребителски акаунт вече е изтрит. Натиснете OK, за да се върнете на началната страница.",
"settings_anonymous": "Не сте влезли. Настройките тук са специфични за този браузър.",
"settings_logoutEverywhereButton": "Излизане",
"settings_logoutEverywhereTitle": "Затваряне на отдалечената сесия",
"settings_logoutEverywhere": "Принудително излизане от всички други сесии",
"settings_driveDuplicateTitle": "Дубликати на притежавани документи",
"settings_driveDuplicateLabel": "Скриване на дубликатите",
"settings_codeIndentation": "Отстъп при писане на код (интервали)",
"settings_codeUseTabs": "Отстъп с помощта на раздели (вместо интервали)",
"settings_codeFontSize": "Размер на шрифта в редактора за код",
"settings_padWidth": "Максималната ширина на редактора",
"settings_padWidthLabel": "Намалете ширината на редактора",
"settings_padSpellcheckTitle": "Проверка на правописа",
"settings_logoutEverywhereConfirm": "Сигурен ли си? Ще трябва да влезеш на всичките си устройства.",
"settings_driveDuplicateHint": "Когато преместите вашите документи в споделена папка, копие от тях се запазва във вашия CryptDrive, за да се гарантира, контрола ви върху него. Можете да скриете дублираните файлове. Само споделената версия ще бъде видима, освен ако не бъде изтрита, в този случай оригиналът ще се покаже на предишното си място.",
"settings_padWidthHint": "Превключване между режим на страница (по подразбиране), който ограничава ширината на текстовия редактор, и използване на цялата ширина на екрана.",
"settings_padSpellcheckHint": "Тази опция ви позволява да активирате проверка на правописа в документи с форматиран текст. Правописните грешки ще бъдат подчертани в червено и ще трябва да задържите клавиша Ctrl или Meta, докато щраквате с десния бутон, за да видите опциите.",
"settings_padSpellcheckLabel": "Активиране на проверката на правописа в документи с форматиран текст",
"settings_padOpenLinkTitle": "Отваряне на връзки при първо щракване",
"settings_padOpenLinkHint": "С тази възможност можете да отваряте вградени връзки при щракване без изскачащ прозорец за показване",
"settings_padOpenLinkLabel": "Разрешаване на отварянето на директната връзка",
"settings_ownDriveTitle": "Актуализиране на профила",
"settings_ownDriveHint": "По-старите акаунти нямат достъп до най-новите функции поради технически причини. Безплатното обновяване ще активира текущите функции и ще подготви вашия CryptDrive за бъдещи обновявания.",
"settings_ownDriveButton": "Надграждане на профила ви",
"settings_ownDriveConfirm": "Надграждането на вашия акаунт може да отнеме известно време. Ще трябва да влезете отново през всичките си устройства. Сигурен ли сте?",
"settings_ownDrivePending": "Вашият профил се надгражда. Моля, не затваряйте и не презареждайте тази страница, докато процесът не приключи.",
"settings_changePasswordTitle": "Промяна на паролата",
"settings_changePasswordHint": "Променете паролата на профила си. Въведете текущата си парола и потвърдете новата парола, като я въведете два пъти.<br><b>Не можем да възстановим паролата ви, ако я забравите, така че бъдете много внимателни!</b>",
"settings_changePasswordButton": "Промяна на парола",
"settings_changePasswordCurrent": "Текуща парола",
"settings_changePasswordNew": "Нова парола",
"settings_changePasswordNewConfirm": "Потвърждаване на новата парола",
"settings_changePasswordConfirm": "Сигурни ли сте, че искате да промените паролата си? Ще трябва да влезете отново през всичките си устройства.",
"settings_changePasswordPending": "Вашата парола се обновява. Моля, не затваряйте и не презареждайте тази страница, докато процесът не приключи.",
"settings_cursorColorTitle": "Цвят на курсора",
"settings_changePasswordError": "Възникна неочаквана грешка. Ако не можете да влезете или да промените паролата си, свържете се с администраторите на CryptPad.",
"settings_changePasswordNewPasswordSameAsOld": "Вашата нова парола трябва да е различна от настоящата."
"settings_exportWarning": "Забележка: този инструмент все още е в бета версия и може да има проблеми с мащабируемостта. За по-добра производителност се препоръчва да оставите този раздел на фокус - без превключване на друг раздел."
}

View file

@ -534,8 +534,8 @@
"features_f_file1": "Importar i compartir fitxers",
"features_f_reg": "Avantatges dels usuaris/es registrats/des",
"features_f_reg_note": "Amb avantatges addicionals",
"features_f_support": "Assistència més ràpida",
"features_f_supporter_note": "Ajudeu el CryptPad a ser econòmicament viable i demostreu que el programari pot respectar la privadesa i ser finançat voluntàriament pels usuaris",
"features_f_support": "Suport més ràpid",
"features_f_supporter_note": "Ajudeu a CryptPad a ser financerament viable i demostreu que el programari pot respectar la privadesa i ser finançat voluntàriament pels usuaris",
"features_f_storage2_note": "De 5GB a 50GB segons el pla, s'ha augmentat el límit a {0}MB per a les baixades de fitxers",
"features_f_subscribe": "Subscriure's",
"features_f_supporter": "Donar suport a la defensa de la privadesa",
@ -544,7 +544,7 @@
"features_f_storage1": "Emmagatzematge personal ({0})",
"features_f_storage1_note": "Els documents emmagatzemats al vostre CryptDrive no s'eliminen a causa de la inactivitat",
"features_f_register": "Registreu-vos gratuïtament",
"features_f_support_note": "Resposta prioritària de l'equip d'administració per correu electrònic i sistema de tiquets integrat",
"features_f_support_note": "Resposta prioritària de l'equip d'administració per correu electrònic i sistema de tiquets de suport integrat",
"features_f_subscribe_note": "Cal un compte registrat per subscriure's",
"view": "mostra",
"four04_pageNotFound": "No hem pogut trobar la pàgina que cercàveu.",
@ -632,7 +632,7 @@
"form_text_text": "Text",
"form_default": "La teva pregunta aquí?",
"form_type_input": "Text",
"support_cat_abuse": "Informa d'un abús",
"support_cat_abuse": "Informa d'abús",
"form_type_radio": "Elecció",
"broadcast_translations": "Traduccions",
"form_type_sort": "Llista ordenada",
@ -740,7 +740,7 @@
"form_anonAnswer": "Les respostes a aquest formulari són anònimes",
"pad_settings_title": "Configuració del document",
"fc_openIn": "Obre a {0}",
"supportPage": "Assistència",
"supportPage": "Suport",
"fm_filterBy": "Filtre",
"undo": "Desfés",
"support_answer": "Respon",
@ -811,7 +811,7 @@
"autostore_settings": "Podeu activar l'emmagatzematge automàtic de documents a la pàgina <a>Configuració</a>.",
"autostore_store": "Desa",
"autostore_hide": "No ho desis",
"crowdfunding_button": "Doneu suport al CryptPad",
"crowdfunding_button": "Doneu suport a CryptPad",
"settings_codeSpellcheckLabel": "Activa la verificació ortogràfica a l'editor de codi",
"admin_activeSessionsTitle": "Connexions actives",
"admin_registeredTitle": "Usuaris registrats",
@ -894,7 +894,7 @@
"history_fastPrev": "Sessió d'edició anterior",
"history_userNext": "Autor següent",
"snaphot_title": "Instantània",
"unableToDisplay": "No s'ha pogut mostrar el document. Premeu Esc per tornar a carregar la pàgina. Si el problema persisteix, contacteu amb l'assistència.",
"unableToDisplay": "No s'ha pogut mostrar el document. Premeu Esc per tornar a carregar la pàgina. Si el problema persisteix, contacteu amb el suport.",
"admin_archiveButton": "Arxiu",
"register_notes_title": "Notes importants",
"settings_cacheTitle": "Memòria cau",
@ -960,7 +960,7 @@
"fm_link_name_placeholder": "El meu enllaç",
"form_anonName": "El vostre nom",
"fm_link_warning": "Avís: l'URL excedeix els 200 caràcters",
"admin_support_premium": "Tiquets prèmium:",
"admin_support_premium": "Tiquets de recompensa:",
"fm_link_invalid": "URL no vàlid",
"calendar_str_monthly": "{0} mesos",
"form_willClose": "Aquest formulari es tancarà el {0}",
@ -974,7 +974,7 @@
"calendar_rec_yearly_nth": "Cada {0} {1} de {2}",
"calendar_rec_monthly_nth": "Cada {0} {1} del mes",
"calendar_nth_last": "últim",
"admin_cat_support": "Assistència",
"admin_cat_support": "Suport",
"friendRequest_later": "Decideix més tard",
"history_restoreDrivePrompt": "Esteu segur que voleu substituir la versió actual de CryptDrive per la versió mostrada?",
"owner_add": "{0} vol que sigueu propietari del document <b>{1}</b>. Ho accepteu?",
@ -1076,7 +1076,7 @@
"support_cat_drives": "Unitat o equip",
"comments_edited": "Editat",
"comments_submit": "Envia",
"support_debuggingDataHint": "La informació següent s'inclou en els tiquets d'assistència que envieu. Cap d'ells permet als administradors accedir o desxifrar els vostres documents. Aquesta informació està xifrada de manera que només els administradors poden llegir-la.",
"support_debuggingDataHint": "La informació següent s'inclou en els tiquets de suport que envieu. Cap d'ells permet als administradors accedir o desencriptar els vostres documents. Aquesta informació està xifrada de manera que només els administradors poden llegir-la.",
"ui_ms": "mil·lisegons",
"autostore_pad": "document",
"ui_collapse": "Contrau",
@ -1170,24 +1170,24 @@
"autostore_saved": "El document s'ha desat correctament al vostre CryptDrive!",
"autostore_forceSave": "Desa el fitxer al vostre CryptDrive",
"autostore_notAvailable": "Heu de desar aquest document al vostre CryptDrive abans de poder utilitzar aquesta característica.",
"crowdfunding_popup_text": "<h3>Necessitem la vostra ajuda!</h3>Per assegurar que el CryptPad es desenvolupa activament, us convidem a donar suport al projecte a través de la pàgina OpenCollective, on podeu veure el nostre <b>Full de ruta</b> i <b>Objectius de finançament</b>.",
"admin_supportInitPrivate": "La vostra instància de CryptPad està configurada per utilitzar una bústia de correu d'assistència, però el vostre compte no té la clau privada correcta per accedir-hi. Utilitzeu el següent formulari per afegir o actualitzar la clau privada al vostre compte.",
"crowdfunding_popup_text": "<h3>Necessitem la vostra ajuda!</h3>Per assegurar que CryptPad es desenvolupa activament, us convidem a donar suport al projecte a través de la pàgina OpenCollective, on podeu veure el nostre <b>Full de ruta</b> i <b>Objectius de finançament</b>.",
"admin_supportInitPrivate": "La vostra instància de CryptPad està configurada per utilitzar una bústia de correu compatible, però el vostre compte no té la clau privada correcta per accedir-hi. Utilitzeu el següent formulari per afegir o actualitzar la clau privada al vostre compte.",
"admin_supportAddError": "Clau privada no vàlida",
"admin_supportInitTitle": "Inicialització de la bústia d'assistència",
"admin_supportInitHint": "Podeu configurar una bústia d'assistència per tal de donar als usuaris de la vostra instància de CryptPad una manera de contactar de manera segura si tenen algun problema amb el seu compte.",
"admin_supportListTitle": "Bústia de correu d'assistència",
"admin_supportListHint": "Aquesta és la llista de tiquets enviats pels usuaris a la bústia d'assistència. Tots els administradors poden veure els missatges i les seves respostes. No es pot tornar a obrir un tiquet tancat. Només podeu suprimir (amagar) tiquets tancats i els tiquets eliminats encara són visibles per altres administradors.",
"support_disabledTitle": "L'assistència no està activada",
"support_disabledHint": "Aquesta instància de CryptPad encara no està configurada per a utilitzar un formulari d'assistència.",
"admin_supportInitTitle": "Permet la inicialització de la bústia de correu",
"admin_supportInitHint": "Podeu configurar una bústia d'assistència per tal de donar als usuaris de la vostra instància de CryptPad una manera de contactar-vos de manera segura si tenen algun problema amb el seu compte.",
"admin_supportListTitle": "Bústia de correu de suport",
"admin_supportListHint": "Aquesta és la llista de tiquets enviats pels usuaris a la bústia de suport. Tots els administradors poden veure els missatges i les seves respostes. No es pot tornar a obrir un bitllet tancat. Només podeu eliminar (amagar) tiquets tancats i els tiquets eliminats encara són visibles per altres administradors.",
"support_disabledTitle": "El suport no està habilitat",
"support_disabledHint": "Aquesta instància de CryptPad encara no està configurada per utilitzar un formulari de suport.",
"support_cat_new": "Tiquet nou",
"support_formTitle": "Tiquet nou",
"support_formTitleError": "Error: el títol està buit",
"support_formContentError": "Error: el contingut està buit",
"support_cat_tickets": "Tiquets existents",
"support_listTitle": "Tiquets d'assistència",
"support_listHint": "Aquesta és la llista d'entrades enviades als administradors i les seves respostes. No es pot tornar a obrir un tiquet tancat, però es pot fer un de nou. Podeu amagar els bitllets que s'han tancat.",
"support_listTitle": "Tiquets de suport",
"support_listHint": "Aquesta és la llista d'entrades enviades als administradors i les seves respostes. No es pot tornar a obrir un bitllet tancat, però es pot fer un de nou. Podeu amagar els bitllets que s'han tancat.",
"support_close": "Tanca el tiquet",
"support_remove": "Suprimeix el tiquet",
"support_remove": "Elimina el tiquet",
"support_showData": "Mostra/oculta les dades de l'usuari",
"support_from": "<b>De:</b> {0}",
"support_closed": "Aquest tiquet s'ha tancat",
@ -1198,7 +1198,7 @@
"notifications_cat_pads": "Compartit amb mi",
"notifications_cat_archived": "Història",
"notifications_dismissAll": "Descarta-ho tot",
"support_notification": "Un administrador ha respost al vostre tiquet d'assistència",
"support_notification": "Un administrador ha respost al vostre tiquet de suport",
"team_title": "Equip: {0}",
"team_quota": "Límit d'emmagatzematge del vostre equip",
"settings_codeBrackets": "Tanca automàticament els claudàtors",
@ -1412,7 +1412,7 @@
"admin_broadcastButton": "Envia",
"admin_broadcastActive": "Missatge actiu",
"admin_broadcastCancel": "Suprimeix el missatge",
"settings_deleteWarning": "Avís: esteu subscrit a un pla prèmium (pagat o donat per un altre usuari). Cancel·leu el vostre pla abans d'esborrar el vostre compte, ja que no serà possible fer-ho sense contactar amb l'assistència un cop el vostre compte hagi estat eliminat.",
"settings_deleteWarning": "Avís: esteu subscrit a un pla premium (pagat o donat per un altre usuari). Cancel·leu el vostre pla abans d'esborrar el vostre compte, ja que no serà possible sense contactar amb el suport un cop el vostre compte hagi estat eliminat.",
"settings_deleteContinue": "Suprimeix el meu compte",
"oo_cantMigrate": "Aquest full excedeix la mida màxima de càrrega i és massa gran per a ser migrat.",
"calendar_import_temp": "Importa aquest calendari",
@ -1426,13 +1426,13 @@
"reminder_now": "<b>{0}</b> ha començat",
"reminder_minutes": "<b>{0}</b> començarà en {1} minut(s)",
"reminder_time": "<b>{0}</b> avui a {1}",
"oo_conversionSupport": "El navegador no pot gestionar la conversió a i des dels formats ofimàtics. Suggerim que utilitzeu una versió recent del Firefox o Chrome.",
"oo_conversionSupport": "El navegador no pot gestionar la conversió a i des dels formats ofimàtics. Suggerim utilitzar una versió recent del Firefox o Chrome.",
"oo_importBin": "Feu clic a D'acord per a importar el format .bin intern de CryptPad.",
"admin_emailTitle": "Correu electrònic de contacte de l'administrador",
"admin_emailHint": "Establiu aquí el correu electrònic de contacte per a la vostra instància",
"admin_supportPrivTitle": "Clau privada de la bústia de correu d'assistència",
"admin_supportInitGenerate": "Genera claus d'assistència",
"admin_supportPrivHint": "Mostra la clau privada que els altres administradors necessitaran per poder veure els tiquets d'assistència. Es mostrarà al panell d'administració un formulari per introduir aquesta clau.",
"admin_supportPrivTitle": "Dona suport a la clau privada de la bústia",
"admin_supportInitGenerate": "Genera claus de suport",
"admin_supportPrivHint": "Mostra la clau privada que els altres administradors hauran de veure els tiquets de suport. Es mostrarà un formulari per introduir aquesta clau al seu plafó d'administració.",
"admin_supportPrivButton": "Mostra la clau",
"share_formEdit": "Autor",
"form_sort_hint": "Arrossegueu aquests elements des de la majoria (1) fins al mínim ({0}) preferit.",
@ -1499,7 +1499,7 @@
"form_answerAs": "Respon com a",
"ui_expand": "Expandeix",
"form_totalResponses": "Total de respostes: {0}",
"support_premiumPriority": "Els usuaris prèmium ajuden a millorar la usabilitat de CryptPad i es beneficien de respostes prioritzades als seus tiquets d'assistència.",
"support_premiumPriority": "Els usuaris premium ajuden a millorar la usabilitat de CryptPad i es beneficien de respostes prioritzades als seus bitllets de suport.",
"support_premiumLink": "Mostra les opcions de subscripció",
"toolbar_collapse": "Redueix la barra d'eines",
"toolbar_expand": "Expandeix la barra d'eines",
@ -1528,15 +1528,15 @@
"admin_archiveNote": "Nota",
"admin_descriptionHint": "El text descriptiu mostrat per aquesta instància a la llista d'instàncies públiques a cryptpad.org",
"footer_source": "Codi font",
"support_warning_prompt": "Trieu la categoria més rellevant per al vostre problema. Això ajuda els administradors a prioritzar i proporciona més suggeriments per a quina informació proporcionar",
"support_warning_account": "Tingueu en compte que els administradors no poden restablir les contrasenyes. Si heu perdut les credencials al vostre compte, però encara hi esteu connectat, podeu <a>migrar les vostres dades a un compte nou</a>",
"support_warning_drives": "Tingueu en compte que els administradors no poden identificar carpetes i documents pel seu nom. Per a carpetes compartides, proporcioneu un <a>identificador de document </a>",
"support_warning_document": "Especifiqueu quin tipus de document està causant el problema i proporcioneu un <a>identificador de document </a> o un enllaç",
"support_warning_prompt": "Trieu la categoria més rellevant per al vostre problema. Això ajuda als administradors a trigar i proporciona més suggeriments per a quina informació proporcionar",
"support_warning_account": "Tingueu en compte que els administradors no poden restablir les contrasenyes. Si heu perdut les credencials al vostre compte però encara hi esteu connectat, podeu <a>migrar les vostres dades a un compte nou</a>",
"support_warning_drives": "Tingueu en compte que els administradors no poden identificar carpetes i documents per nom. Per a carpetes compartides, proporcioneu un identificador de document <a></a>",
"support_warning_document": "Especifiqueu quin tipus de document està causant el problema i proporcioneu un identificador de document <a></a> o un enllaç",
"calendar_list_end": "{0} o {1}",
"calendar_rec_every_date": "Cada {0}",
"support_warning_bug": "Especifiqueu en quin navegador es produeix el problema i si hi ha instal·lades extensions. Proporcioneu el màxim detall possible sobre el problema i els passos necessaris per reproduir-lo",
"support_warning_abuse": "Informeu del contingut que viola les <a>condicions del servei</a>. Proporcioneu enllaços als documents o perfils d'usuari infractors i descriviu com estan violant els termes. Qualsevol informació addicional sobre el context en què heu descobert el contingut o el comportament pot ajudar els administradors a prevenir futures violacions",
"support_warning_other": "Quina és la naturalesa de la vostra consulta? Proporcioneu tanta informació rellevant com us sigui possible per a facilitar-nos la gestió del problema",
"support_warning_other": "Quina és la naturalesa de la seva consulta? Si us plau, proporcioni la màxima informació rellevant possible per a facilitar-nos que abordem la seva qüestió ràpidament",
"support_cat_document": "Document",
"ui_openDirectly": "Aquesta funcionalitat no està disponible si el CryptPad està incrustat en un altre lloc web. Voleu obrir el document en una pestanya nova?",
"support_cat_debugging": "Depura les dades",
@ -1571,7 +1571,7 @@
"form_editable_on": "Una vegada i edita",
"chrome68": "Sembla que esteu utilitzant el navegador Chrome o Chromium versió 68. Conté un error que fa que la pàgina es torni completament blanca després d'uns segons o que la pàgina no respongui als clics. Per a solucionar aquest problema, podeu canviar a una altra pestanya i tornar enrere, o intentar desplaçar-vos per la pàgina. Aquest error s'ha de corregir en la versió següent del navegador.",
"admin_updateLimitHint": "Forçar una actualització dels límits d'emmagatzematge dels usuaris es pot fer en qualsevol moment, però només és necessari en cas d'error",
"admin_supportInitHelp": "El servidor encara no està configurat per tenir una bústia de correu d'assistència. Si voleu que una bústia d'assistència rebi missatges dels vostres usuaris, hauríeu de demanar a l'administrador del servidor que executi l'script ubicat a «./scripts/generate-admin-keys.js», després deseu la clau pública al fitxer «config.js» i envieu la clau privada.",
"admin_supportInitHelp": "El servidor encara no està configurat per tenir una bústia de correu compatible. Si voleu que una bústia de suport rebi missatges dels vostres usuaris, hauríeu de demanar a l'administrador del servidor que executi l'script ubicat a «./scripts/generate-admin-keys.js», després deseu la clau pública al fitxer «config.js» i envieu la clau privada.",
"support_formHint": "Utilitzeu aquest formulari per contactar amb seguretat amb els administradors sobre problemes i preguntes.<br>Tingueu en compte que alguns problemes/preguntes ja es poden abordar a la <a>Guia d'usuari de CryptPad</a>. No creeu un tiquet nou si ja teniu un tiquet obert sobre el mateix problema. En canvi, responeu al vostre missatge original amb qualsevol informació addicional.",
"requestEdit_confirm": "{1} ha demanat la possibilitat d'editar el document <b>{0}</b>. Voleu concedir l'accés?",
"owner_removedPending": "{0} ha cancel·lat la vostra oferta de propietat de <b>{1}</b>",
@ -1666,56 +1666,5 @@
"status": "Pàgina d'estat",
"admin_diskUsageWarning": "Utilitzeu-ho amb precaució! Depenent de la mida de les dades emmagatzemades a la instància, generar aquest informe pot consumir tota la memòria disponible al servidor i originar una fallada.",
"dph_pad_pw": "El document s'ha protegit amb una contrasenya nova",
"dph_sf_destroyed_team": "Un propietari ha destruït la carpeta compartida <b>{0}</b> a la unitat de l'equip <b>{1}</b>",
"admin_invitationEmail": "Adreça de l'usuari",
"admin_registrationSsoTitle": "Tanca el registre per SSO",
"admin_invitationCreate": "Crea un enllaç d'invitació",
"admin_invitationTitle": "Enllaços d'invitació",
"admin_invitationLink": "Enllaç d'invitació",
"admin_invitationDeleteConfirm": "Segur que voleu eliminar aquesta invitació?",
"admin_usersTitle": "Directori d'usuari",
"admin_invitationCopy": "Copia l'enllaç",
"admin_invitationAlias": "Nom d'usuari",
"admin_usersRemove": "Suprimeix",
"admin_usersAdd": "Afegeix l'usuari conegut",
"admin_usersRemoveConfirm": "Segur que voleu suprimir aquest usuari del directori? Encara podrà accedir i utilitzar el seu compte.",
"admin_storeSsoLabel": "Desa automàticament els usuaris SSO",
"register_invalidToken": "L'enllaç d'invitació no és vàlid",
"ssoauth_header": "Contrasenya CryptPad",
"ssoauth_form_hint_login": "Introduïu la contrasenya CryptPad",
"duplicate": "Duplica",
"calendar_desc": "Descripció",
"calendar_description": "Descripció: {0}{1}",
"sso_login_description": "Inicieu la sessió amb",
"sso_register_description": "Registreu-vos amb",
"kanban_showTags": "Mostra totes les etiquetes",
"kanban_hideTags": "Mostra menys etiquetes",
"admin_forcemfaTitle": "Autenticació de dos factors obligatòria",
"admin_forcemfaHint": "Es demanarà a tots els usuaris de la instància que estableixin una autenticació de dos factors per a iniciar la sessió.",
"calendar_rec_change_first": "S'està movent el primer esdeveniment de la repetició a un calendari diferent. També es mouran tots els esdeveniments repetits.",
"admin_logoTitle": "Logotip personalitzat",
"admin_cat_security": "Seguretat",
"admin_cat_customize": "Personalitza",
"admin_colorTitle": "Color d'èmfasi",
"admin_logoHint": "SVG, PNG o JPG, mida màxima 200 KB",
"admin_logoButton": "Puja el logotip",
"admin_colorHint": "Canvieu el color d'èmfasi de la instància del CryptPad. Comproveu que el text i els botons són llegibles amb prou contrast als temes clars i foscos.",
"admin_logoRemoveButton": "Restableix el predefinit",
"admin_colorCurrent": "Color d'èmfasi actual",
"admin_supportDisabled": "S'ha desactivat el sistema d'assistència.",
"admin_colorChange": "Canvia el color",
"admin_colorPick": "Trieu un color",
"admin_colorPreview": "Previsualització",
"admin_supportSetupHint": "Creeu o actualitzeu les claus d'assistència.",
"admin_supportSetupTitle": "Inicialitza l'assistència",
"admin_supportEnabled": "S'ha activat el sistema d'assistència.",
"admin_supportInit": "Inicialitza el help-desk en aquesta instància",
"admin_cat_users": "Directori d'usuari",
"calendar_rec_change": "S'està movent un esdeveniment repetit a un calendari diferent. Només podeu aplicar el canvi a aquest esdeveniment, o a tots els repetits.",
"loading_mfa_required": "Cal autenticació de dos factors en aquesta instància. Actualitzeu el vostre compte fent servir una aplicació d'autenticació i el formulari de sota.",
"admin_invitationHint": "Els enllaços d'invitació creen un compte cadascú, fins i tot si el registre es troba tancat. El nom d'usuari i l'adreça electrònica només són per poder identificar-vos. El CryptPad no enviarà per correu l'enllaç d'invitació (ni cap altra cosa), copieu-lo i envieu-lo fent servir el canal segur que trieu.",
"admin_usersHint": "Llista dels comptes coneguts d'aquesta instància. Seleccioneu a continuació per a afegir comptes automàticament, o introduïu la informació manualment amb el formulari.",
"admin_usersBlock": "URL de blocatge d'inici de sessió de l'usuari (opcional)",
"ssoauth_form_hint_register": "Afegiu una contrasenya CryptPad per a més seguretat, o deixeu-la buida i continueu. Si no afegiu una contrasenya, els administradors de la instància tindran a l'abast les claus que protegeixen les vostres dades.",
"admin_storeInvitedLabel": "Desa automàticament els usuaris convidats"
"dph_sf_destroyed_team": "Un propietari ha destruït la carpeta compartida <b>{0}</b> a la unitat de l'equip <b>{1}</b>"
}

View file

@ -607,8 +607,8 @@
"admin_activeSessionsHint": "Anzahl aktiver Websocket-Verbindungen (und verbundener IP-Adressen)",
"admin_activePadsTitle": "Aktive Dokumente",
"admin_activePadsHint": "Anzahl der Dokumente, die gerade angesehen oder bearbeitet werden",
"admin_registeredTitle": "Nutzer und Team-Drives",
"admin_registeredHint": "Anzahl aktiver Drives auf deiner Instanz",
"admin_registeredTitle": "Registrierte Nutzer",
"admin_registeredHint": "Anzahl der auf deiner Instanz registrierten Nutzer",
"admin_updateLimitTitle": "Nutzer-Quotas aktualisieren",
"admin_updateLimitHint": "Das Erzwingen einer Aktualisierung der Speicherbegrenzungen für Nutzer ist jederzeit möglich, aber nur im Fehlerfall notwendig",
"admin_updateLimitButton": "Quotas aktualisieren",
@ -1019,7 +1019,7 @@
"admin_getlimitsTitle": "Individuelle Regeln",
"admin_limit": "Aktuelle Begrenzung: {0}",
"admin_defaultlimitHint": "Speicherplatzbegrenzung für CryptDrives (Benutzer und Teams), sofern keine individuelle Regel festgelegt wurde",
"admin_registrationHint": "Besucher der Instanz können keine Accounts erstellen. Einladungen können von Administratoren erstellt werden.",
"admin_registrationHint": "Erlaube keine neuen Benutzerregistrierungen",
"admin_cat_quota": "Speicher für Benutzer",
"admin_invalLimit": "Wert für Speicherplatzbegrenzung ist ungültig",
"admin_limitSetNote": "Notiz",
@ -1668,7 +1668,7 @@
"admin_diskUsageWarning": "Mit Vorsicht zu verwenden! Je nach Größe der auf der Instanz gespeicherten Daten kann die Erstellung dieses Berichts den gesamten auf dem Server verfügbaren Speicher verbrauchen und zu einem Absturz führen.",
"dph_sf_destroyed": "Geteilter Ordner <b>{0}</b> wurde vom Eigentümer zerstört",
"calendar_desc": "Beschreibung",
"admin_forcemfaHint": "Alle Benutzer dieser Instanz werden aufgefordert, eine Zwei-Faktor-Authentifizierung für die Anmeldung bei ihrem Account einzurichten. Beachte, dass bestehende Benutzer nicht in der Lage sein werden, ihren Account weiterhin zu nutzen, ohne eine TOTP-Anwendung einzurichten.",
"admin_forcemfaHint": "Alle Benutzer dieser Instanz werden aufgefordert, eine Zwei-Faktor-Authentifizierung für die Anmeldung bei ihrem Account einzurichten.",
"ssoauth_form_hint_register": "Füge ein CryptPad-Passwort für zusätzliche Sicherheit hinzu oder lasse es leer und fahre fort. Wenn du kein Passwort hinzufügst, können die Administratoren der Instanz auf die Schlüssel zum Schutz deiner Daten zugreifen.",
"ssoauth_form_hint_login": "Bitte gib dein CryptPad-Passwort ein",
"loading_mfa_required": "Auf dieser Instanz ist eine Zwei-Faktor-Authentifizierung erforderlich. Bitte aktualisiere deinen Account mit einer Authentifizierungs-App und dem folgenden Formular.",
@ -1763,22 +1763,5 @@
"support_movePending": "In das Archiv verschieben",
"support_cat_legacy": "Alte Daten",
"support_legacyTitle": "Alte Support-Daten ansehen",
"support_userNotification": "Neues Support-Ticket oder neue Antwort: {0}",
"install_token": "Installations-Token",
"install_header": "Installation",
"admin_appSelection": "Konfiguration der Anwendungen",
"install_launch": "Einrichtung der Instanz",
"install_instance": "Erstelle den ersten Admin-Account und fahre dann mit der Anpassung dieser Instanz fort",
"admin_appsTitle": "Anwendungen der Instanz",
"onboarding_save_error": "Einige Einstellungen konnten nicht korrekt gespeichert werden. Bitte besuche den Administrationsbereich, um die Werte zu überprüfen.",
"admin_appsHint": "Wähle aus, welche Anwendungen auf dieser Instanz aktiviert werden sollen.",
"admin_cat_apps": "Anwendungen",
"admin_onboardingNameTitle": "Willkommen auf deiner CryptPad-Instanz",
"install_notes": "<ul class=\"cp-notes-list\"><li>Erstelle auf dieser Seite deinen ersten Administrator-Account. Administratoren verwalten die Einstellungen der Instanz einschließlich der Speicherplatzkontingente und haben Zugriff auf die Moderationswerkzeuge.</li><li>Dein Passwort ist der geheime Schlüssel, der alle deine Dokumente und Administratorrechte auf dieser Instanz verschlüsselt. <span class=\"red\">Wenn du es verlierst, gibt es keine Möglichkeit, deine Daten wiederherzustellen.</span></li><li>Wenn du einen gemeinsam genutzten Computer verwendest, <span class=\"red\">denke daran, dich abzumelden,</span> wenn du fertig bist. Wird das Browserfenster einfach geschlossen, bleibt dein Account zugänglich.</li></ul>",
"onboarding_upload": "Logo auswählen",
"admin_onboardingOptionsTitle": "Einstellungen der Instanz",
"admin_onboardingNamePlaceholder": "Name der Instanz",
"admin_onboardingDescPlaceholder": "Beschreibungstext für die Instanz",
"admin_onboardingOptionsHint": "Bitte wähle die geeignete Option für deine Instanz.<br>Diese Einstellungen können später im Administrationsbereich geändert werden.",
"admin_onboardingNameHint": "Bitte wähle einen Namen, eine Beschreibung, eine Akzentfarbe und ein Logo (alle Angaben sind optional)"
"support_userNotification": "Neues Support-Ticket oder neue Antwort: {0}"
}

View file

@ -553,7 +553,7 @@
"password_info": "El documento que intenta abrir no existe o está protegido con una contraseña. Ingrese la contraseña correcta para acceder a su contenido.",
"creation_newPadModalDescription": "Haz clic en una aplicación para crear un nuevo documento. Tú también puedes presionar <b>Tab</b> para seleccionar la aplicación y presiona <b>Enter</b> para confirmar.",
"toolbar_degraded": "Actualmente hay más de {0} editores en este documento. La lista de usuarios y el chat están desactivados para mejorar el rendimiento.",
"oo_lostEdits": "Lamentablemente, las ediciones recientes no guardadas no se pudieron recuperar después de sincronizar contenido nuevo.",
"oo_lostEdits": "Lamentablemente, las ediciones recientes no guardadas no se pueden recuperar después de sincronizar el nuevo contenido.",
"properties_passwordError": "Se ha producido un error al intentar cambiar la contraseña. Por favor, inténtelo de nuevo.",
"properties_passwordSame": "Las nuevas contraseñas deben diferir de la actual.",
"properties_confirmChange": "¿Está seguro? Al cambiar la contraseña se eliminará su historial. Los usuarios que no tengan la nueva contraseña perderán el acceso a este documento",
@ -863,7 +863,7 @@
"form_open": "Abrir",
"form_isPrivate": "Las respuestas son privadas",
"form_isPublic": "Las respuestas son públicas",
"form_makePublicWarning": "¿Estás seguro de querer hacer públicas las respuestas a este formulario? Las respuestas pasadas y futuras serán visibles para los participantes. Esta acción no se puede deshacer.",
"form_makePublicWarning": "¿Estás seguro/a que quieres hacer las respuestas a este formulario públicas? Las respuestas pasadas y futuras serán visibles por los participantes. Esto no se puede deshacer.",
"form_makePublic": "Publicar respuestas",
"form_invalidQuestion": "Pregunta {0}",
"form_invalidWarning": "Hay errores en algunas respuestas:",
@ -875,7 +875,7 @@
"form_backButton": "Atrás",
"form_viewButton": "Ver",
"form_answerAnonymous": "Respuesta anónima en {0}",
"form_showSummary": "Mostrar resumen",
"form_showSummary": "Mostrar sumario",
"form_showIndividual": "Mostrar respuestas individuales",
"form_editor": "Editor",
"form_results_empty": "No hay respuestas",
@ -887,49 +887,49 @@
"form_delete": "Eliminar",
"form_reset": "Reiniciar",
"form_submit": "Enviar",
"form_maxOptions": "Máximo {0} respuesta(s)",
"form_maxOptions": "respuesta(s) máximas {0}",
"form_description_default": "Tu texto aquí",
"form_type_page": "Salto de página",
"form_type_md": "Descripción",
"form_sort_hint": "Por favor arrastre estos ítems desde el más (1) al menos ({0}) preferido.",
"form_type_sort": "Lista ordenada",
"form_type_poll": "Encuesta",
"form_type_multicheck": "Grilla de casillas de verificación",
"form_type_multicheck": "Cuadrícula de casillas de verificación",
"form_type_checkbox": "Casilla de verificación",
"form_type_multiradio": "Grilla de opciones",
"form_type_multiradio": "Escoge la red",
"form_type_radio": "Opción",
"form_type_textarea": "Párrafo",
"form_type_input": "Texto",
"form_default": "¿Tu pregunta aquí?",
"form_text_number": "Número",
"form_text_email": "Correo",
"form_text_url": "Enlace",
"form_text_url": "Link",
"form_text_text": "Texto",
"form_textType": "Tipo de texto",
"form_pollYourAnswers": "Tus respuestas",
"form_pollTotal": "Total",
"form_poll_switch": "Invertir ejes",
"form_poll_time": "Hora",
"form_poll_switch": "Intercambio de ejes",
"form_poll_time": "Tiempo",
"form_poll_day": "Día",
"form_poll_text": "Texto",
"form_editType": "Tipo de opción",
"form_editMaxLength": "Máximo de caracteres",
"form_editMax": "Máximo de opciones seleccionables",
"form_editMaxLength": "Máximos carácteres",
"form_editMax": "Máximas opciones seleccionables",
"form_editBlock": "Editar",
"form_invalid": "Formulario inválido",
"share_formView": "Participante",
"share_formAuditor": "Auditor",
"share_formEdit": "Autor",
"share_formAuditor": "Auditor/a",
"share_formEdit": "Autor/a",
"admin_supportPrivButton": "Mostrar llave",
"admin_supportPrivHint": "Muestra la llave privada que otros administradores necesitarán para ver tickets de soporte. Se mostrará un formulario para ingresar esta clave en su panel de administración.",
"admin_supportPrivHint": "Muestra la llave privada que otros/as administradores/as necesitarán para ver tickets de soporte. Una forma de ingresar esta llave será mostrada en su panel de administrador/a.",
"admin_supportInitGenerate": "Generar llaves de soporte",
"admin_supportPrivTitle": "Llave privada del buzón de soporte",
"admin_emailHint": "Establece el correo de contacto para tu instancia aquí",
"admin_emailTitle": "Correo de contacto del administrador",
"admin_emailTitle": "Correo de contacto del administrador/a",
"oo_importBin": "Presiona OK para importar el formato .bin interno de CryptPad.",
"oo_conversionSupport": "Tu navegador no puede manejar la conversión hacia y desde formatos de office. Sugerimos usar una versión reciente de Firefox o Chrome.",
"register_registrationIsClosed": "La registración está cerrada.",
"mediatag_defaultImageName": "imagen",
"mediatag_defaultImageName": "imágen",
"genericCopySuccess": "Copiado al portapapeles",
"toolbar_storeInDrive": "Guardar en CryptDrive",
"calendar_noNotification": "Ninguno",
@ -957,9 +957,9 @@
"calendar_newEvent": "Nuevo evento",
"calendar_import": "Añadir a mis calendarios",
"calendar_errorNoCalendar": "Ningún calendario editable seleccionado",
"calendar_deleteOwned": "Se mantendrá visible para otros usuarios con los que se haya compartido.",
"calendar_deleteTeamConfirm": "¿Estás seguro que quieres eliminar este calendario del equipo?",
"calendar_deleteConfirm": "¿Estás seguro que quieres eliminar este calendario de tu cuenta?",
"calendar_deleteOwned": "Se mantendrá visible para otros/as usuarios/as con los que se haya compartido.",
"calendar_deleteTeamConfirm": "¿Estás seguro/a que quieres eliminar este calendario del equipo?",
"calendar_deleteConfirm": "¿Estás seguro/a que quieres eliminar este calendario de tu cuenta?",
"calendar_today": "Hoy",
"calendar_month": "Mes",
"calendar_week": "Semana",
@ -972,73 +972,73 @@
"calendar_import_temp": "Importar este calendario",
"pad_goToAnchor": "Ir al anclaje",
"oo_cantMigrate": "Esta hoja excede el tamaño máximo de subida y es muy grande para ser migrada.",
"footer_roadmap": "Plan de acción",
"settings_deleteSubscription": "Administrar mi suscripción",
"footer_roadmap": "Hoja de ruta",
"settings_deleteSubscription": "Manejar mi suscripción",
"settings_deleteContinue": "Eliminar mi cuenta",
"settings_deleteWarning": "Advertencia: actualmente estás suscrito a un plan premium (pagado o dado por otro usuario). Por favor cancela tu plan antes de eliminar tu cuenta, de otra forma tendrás que contactar al soporte para poder cancelar tu plan.",
"broadcast_newCustom": "Mensaje de los administradores",
"settings_deleteWarning": "Advertencia: actualmente estás suscrito/a a un plan premium (pagado o dado por otro/a usuario/a). Por favor cancela tu plan antes de eliminar tu cuenta ya que no será posible sin contactar a soporte una vez tu cuenta esté eliminada.",
"broadcast_newCustom": "Mensaje de los/as administradores/as",
"broadcast_preview": "Previsualizar notificación",
"broadcast_defaultLanguage": "Volver a este idioma",
"broadcast_translations": "Traducciones",
"admin_broadcastCancel": "Eliminar mensaje",
"admin_broadcastActive": "Mensaje activo",
"admin_broadcastButton": "Enviar",
"admin_broadcastHint": "Envía un mensaje a todos los usuarios en esta instancia. Todos los usuarios nuevos y existentes lo recibirán como una notificación. Previsualiza los mensajes antes de enviarlos con \"Previsualizar notificación\". Las notificaciones de previsualización tienen un ícono rojo y son visibles sólo para ti.",
"admin_broadcastButton": "Envíar",
"admin_broadcastHint": "Envía un mensaje a todos/as los/as usuarios/as en esta instancia. Todos/as los/as usuarios/as nuevos/as y existentes lo recibirán como una notificación. Previsualiza los mensajes antes de enviarlos con \"Previsualizar notificación\". Las notificaciones de previsualización tienen un ícono rojo y son visibles sólo para ti.",
"admin_broadcastTitle": "Mensaje de difusión",
"broadcast_surveyURL": "Enlace del cuestionario",
"broadcast_surveyURL": "Link del cuestionario",
"admin_surveyActive": "Abrir cuestionario",
"admin_surveyCancel": "Eliminar",
"admin_surveyButton": "Guardar cuestionario",
"broadcast_newSurvey": "Un nuevo cuestionario está disponible. Presiona para abrir.",
"admin_surveyHint": "Añade, actualiza o borra un enlace a un cuestionario externo. Los usuarios recibirán una notificación y el cuestionario se mantendrá disponible desde el menú del usuario.",
"admin_surveyHint": "Añade, actualiza o borra un link a un cuestionario externo. Los/as usuarios/as recibirán una notificación y el cuestionario se mantendrá disponible desde el menú de usuario/a.",
"admin_surveyTitle": "Cuestionario",
"broadcast_maintenance": "Un mantenimiento está planeado entre las <b>{0}</b> y <b>{1}</b>. CryptPad puede que no esté disponible durante ese tiempo.",
"broadcast_maintenance": "Un mantenimiento está planeado entre las <b>{0}</b> y <b>{1}</b>. CryptPad puede no estar disponible durante ese tiempo.",
"broadcast_end": "Terminar",
"broadcast_start": "Empezar",
"admin_maintenanceCancel": "Cancelar mantenimiento",
"admin_maintenanceButton": "Planear mantenimiento",
"admin_maintenanceHint": "Planear un mantenimiento en esta instancia y notificar a todos los usuarios. Limitado a un mantenimiento activo en un momento dado.",
"admin_maintenanceHint": "Planear un mantenimiento en esta instancia y notificar a todos/as los/as usuarios/as. Limitado a un mantenimiento activo en un momento dado.",
"admin_maintenanceTitle": "Mantenimiento",
"admin_cat_broadcast": "Difusión",
"fm_cantUploadHere": "No se puede subir un archivo aquí",
"importError": "Error al importar (formato incorrecto)",
"importError": "Fallo al importar (formato incorrecto)",
"addOptionalPassword": "Añadir una contraseña (opcional)",
"settings_colortheme_custom": "Personalizar",
"settings_colortheme_custom": "Personalizado",
"pad_settings_show": "Mostrar",
"pad_settings_hide": "Ocultar",
"pad_settings_comments": "Escoge si los comentarios deberían ser visibles u oculta por defecto.",
"pad_settings_outline": "Escoge si la tabla de contenidos debería ser visible u oculta por defecto.",
"pad_settings_hide": "Esconder",
"pad_settings_comments": "Escoge si los comentarios deberían ser visibles o escondidos por defecto.",
"pad_settings_outline": "Escoge si la tabla de contemidos debería ser visible o escondida por defecto.",
"pad_settings_width_large": "Ancho total",
"pad_settings_width_small": "Modo de página",
"pad_settings_info": "Configuraciones por defecto para este documento. Estos serán aplicados cuando usuarios nuevos visiten este documento.",
"pad_settings_info": "Configuraciones por defecto para este documento. Estos serán aplicados cuando usuarios/as nuevos/as visiten este documento.",
"pad_settings_title": "Configuración del documento",
"settings_colorthemeTitle": "Tema de color",
"settings_colorthemeHint": "Cambiar los colores de CryptPad en este dispositivo.",
"settings_colortheme_default": "Configuración predeterminada del sistema ({0})",
"settings_colortheme_light": "Claro",
"settings_colortheme_dark": "Oscuro",
"settings_colorthemeTitle": "Tema del color",
"settings_colorthemeHint": "Cambiar los colores en general de CryptPad en este dispositivo.",
"settings_colortheme_default": "Tema del sistema por defecto ({0})",
"settings_colortheme_light": "Blanco",
"settings_colortheme_dark": "Negro",
"settings_cat_style": "Apariencia",
"admin_performancePercentHeading": "Porcentaje",
"admin_performanceTimeHeading": "Tiempo (segundos)",
"admin_performanceKeyHeading": "Comando",
"admin_performanceProfilingTitle": "Rendimiento",
"admin_performanceProfilingHint": "Una visión general del tiempo total dedicado a ejecutar varios comandos del lado del servidor",
"admin_performanceProfilingHint": "Una visión general del tiempo total gastado ejecutando varios comandos en el lado del servidor",
"admin_cat_performance": "Rendimiento",
"redo": "Rehacer",
"undo": "Deshacer",
"settings_cacheButton": "Borrar caché existente",
"settings_cacheButton": "Limpiar caché existente",
"settings_cacheCheckbox": "Activar caché en este dispositivo",
"settings_cacheHint": "CryptPad guarda partes de tus documentos en la memoria de tu navegador para poder ahorrar conexión y mejorar los tiempos de carga. Puedes desactivar el caché si tu dispositivo no tiene mucho espacio libre. Por razones de seguridad, el caché siempre es borrado cuando cierras sesión, pero puedes borrarlo manualmente si quieres recuperar espacio de almacenamiento en tu dispositivo.",
"settings_cacheHint": "CryptPad guarda partes de tus documentos en la memoria de tu navegador para poder ahorrar en uso de la red y mejorar los tiempos de carga. Puedes desactivar el caché si tu dispositivo no tiene mucho espacio libre. Por razones de seguridad, el caché siempre es limpiado cuando cierras sesión, pero puedes limpiarlo manualmente si quieres recuperar espacio de almacenamiento en tu máquina.",
"settings_cacheTitle": "Caché",
"docs_link": "Documentación",
"creation_helperText": "Abrir en documentación",
"creation_expiresIn": "Destruir en",
"register_warning_note": "Debido a la naturaleza encriptada de CryptPad, los administradores no podrán recuperar los datos en caso de que olvides tu nombre de usuario y/o contraseña. Por favor, guárdalos en un lugar seguro.",
"register_notes": "<ul class=\"cp-notes-list\"><li>Tu contraseña es la llave secreta que encripta todos tus documentos. <span class=\"red\">Si la pierdes no hay forma que podamos recuperar tus datos.</span></li><li>Si estás usando una computadora compartida, <span class=\"red\">recuerda cerrar la sesión</span> cuando termines. Cerrar solo la ventana del navegador dejará tu cuenta expuesta. </li><li>Para quedarte con los documentos que creaste y/o guardaste sin iniciar sesión, marca \"Importar documentos de tu sesión de invitado\".</li></ul>",
"creation_expiresIn": "Expira en",
"register_warning_note": "Debido a la naturaleza encriptada de CryptPad, los/as administradores/as de servicio no podrán recuperar los datos en caso de que olvides tu nombre de usuario/a y/o contraseña. Por favor guardalos en un lugar seguro.",
"register_notes": "<ul class=\"cp-notes-list\"><li>Tu contraseña es la llave secreta que encripta todos tus documentos. <span class=\"red\">Si la pierdes no hay forma que podamos recuperar tus datos.</span></li><li>Si estás usando una computadora compartida, <span class=\"red\">recuerda cerrar la sesión</span> cuando estés listo/a. Tan solo cerrar la ventana del navegador dejará a tu cuenta expuesta. </li><li>Para mantener los documentos que creaste y/o guardaste sin acceder, marca \"Importar documentos de tu sesión de invitado/a\".</li></ul>",
"register_notes_title": "Notas importantes",
"offlineError": "No se han podido sincronizar los datos más recientes, esta página no puede ser mostrada ahora. La carga continuará cuando tu conexión al servicio sea restaurada.",
"share_noContactsOffline": "Actualmente estás fuera de línea. Los contactos no están disponibles.",
"access_offline": "Actualmente estás fuera de línea. La administración de acceso no está disponible.",
"access_offline": "Actualmente estás fuera de línea. Manejo de acceso no está disponible.",
"admin_support_first": "Creado en: ",
"admin_support_collapse": "Colapsar",
"admin_support_open": "Mostrar",
@ -1046,10 +1046,10 @@
"admin_support_answered": "Tickets respondidos:",
"admin_support_normal": "Tickets sin responder:",
"admin_support_premium": "Tickets premium:",
"contacts_confirmCancel": "¿Estás seguro que quieres cancelar tu solicitud de contacto con <b>{0}</b>?",
"history_trimPrompt": "Este documento ha acumulado {0} de historial que puede ralentizar el tiempo de carga. Considera borrar el historial si no lo necesita.",
"contacts_confirmCancel": "¿Estás seguro/a que quieres cancelar tu solicitud de contacto con <b>{0}</b>?",
"history_trimPrompt": "Este documento ha acumulado {0} de historial que puede ralentizar el tiempo de carga. Considere borrar el historial si no es necesario.",
"mediatag_loadButton": "Cargar adjunto",
"settings_mediatagSizeHint": "Tamaño máximo en megabytes (MB) para cargar automáticamente elementos multimedia (imágenes, vídeos, pdf) dentro de los documentos. Elementos más grandes que el tamaño especificado pueden ser cargados manualmente. Usa \"-1\" para cargar siempre los elementos multimedia automáticamente.",
"settings_mediatagSizeHint": "Tamaño máximo en megabytes (MB) para automáticamente cargar elementos multimedia (imágenes, vídeos, pdf) incrustados en documentos. Elementos más grandes que el tamaño especificado pueden ser cargados manualmente. Use \"-1\" para siempre cargar los elementos multimedia automáticamente.",
"settings_mediatagSizeTitle": "Límite automático de descarga",
"mediatag_notReady": "Por favor complete la descarga",
"pad_mediatagOpen": "Abrir archivo",
@ -1067,33 +1067,33 @@
"admin_unarchiveButton": "Restaurar",
"admin_unarchiveHint": "Restaurar un documento que fue previamente archivado",
"admin_archiveButton": "Archivo",
"admin_archiveHint": "Poner un documento no disponible sin eliminarlo permanentemente. Será puesto en un directorio 'archivo' y eliminado luego de unos días (se puede configurar en el archivo de configuración del servidor).",
"errorPopupBlocked": "CryptPad necesita poder abrir nuevas pestañas para operar. Por favor permita las ventanas emergentes en la barra de direcciones de su navegador. Estas ventanas nunca van a ser usadas para mostrar anuncios.",
"unableToDisplay": "No se puede mostrar el documento. Por favor presione Esc para recargar la página. Si el problema persiste, por favor contacte al soporte.",
"admin_archiveHint": "Hacer un documento no disponible sin eliminarlo permanentemente. Será puesto en un directorio 'archivo' y eliminado luego de unos días (configurable en el archivo de configuración del servidor).",
"errorPopupBlocked": "CryptPad necesita poder abrir nuevas pestañas para operar. Por favor permita las ventanas emergentes en la barra de direcciones de su navegador. Estas ventanas nunca van a ser usadas para mostrarle anuncios.",
"unableToDisplay": "No se puede mostrar este documento. Por favor presione Esc para recargar la página. Si el problema persiste, por favor contacte a soporte.",
"documentID": "Identificador del documento",
"error_unhelpfulScriptError": "Error de script: Vea la consola del navegador para detalles",
"error_unhelpfulScriptError": "Error de script: Vea la consola del navegador para los detalles",
"tag_edit": "Editar",
"tag_add": "Añadir",
"loading_state_5": "Reconstruir documento",
"loading_state_4": "Cargar equipos",
"loading_state_3": "Cargar carpetas compartidas",
"loading_state_2": "Actualizar contenido",
"loading_state_2": "Actualizar el contenido",
"loading_state_1": "Cargar el disco",
"loading_state_0": "Construir interfaz",
"fm_shareFolderPassword": "Proteger esta carpeta con una contraseña (opcional)",
"access_destroyPad": "Destruir este documento o carpeta permanentemente",
"fm_deletedFolder": "Carpeta eliminada",
"admin_limitUser": "Llave pública del usuario",
"admin_limitUser": "Llave pública del usuario/a",
"team_exportButton": "Descargar",
"team_exportHint": "Descargar todos los documentos en el disco de este equipo. Los documentos serán descargados en formatos que sean legibles por otras aplicaciones cuando el formato esté disponible. Cuando el formato no esté disponible, los documentos serán descargados en un formato legible por CryptPad.",
"team_exportHint": "Descargar todos los documentos en el disco de este equipo. Los documentos serán descargados en formatos que sean legibles para otras aplicaciones cuando cierto formato esté disponible. Cuando cierto formato no esté disponible, los documentos serán descargados en un formato legible por CryptPad.",
"team_exportTitle": "Descargar disco del equipo",
"admin_cat_quota": "Almacenamiento del usuario",
"admin_invalLimit": "Valor de límite no válido",
"admin_cat_quota": "Almacenamiento del usuario/a",
"admin_invalLimit": "Valor de límite inválido",
"admin_invalKey": "Llave pública inválida",
"admin_limitSetNote": "Nota",
"admin_limitMB": "Límite (en MB)",
"admin_setlimitTitle": "Aplicar un límite personalizado",
"admin_setlimitHint": "Establecer límites personalizados para usuarios usando su llave pública. Puedes actualizar o borrar un límite existente.",
"admin_setlimitHint": "Establecer límites personalizados para usuarios/as usando su llave pública. Puedes actualizar o borrar un límite existente.",
"admin_limitNote": "Nota: {0}",
"admin_limitPlan": "Plan: {0}",
"admin_getlimitsTitle": "Límites personalizados",
@ -1101,13 +1101,13 @@
"admin_limit": "Límite actual: {0}",
"admin_setlimitButton": "Establecer límite",
"admin_defaultlimitTitle": "Límite de almacenamiento (MB)",
"admin_defaultlimitHint": "Límite de almacenamiento máximo para los CryptDrives (usuarios y equipos) cuando no se aplica ninguna regla",
"admin_defaultlimitHint": "Límite de almacenamiento máximo para los CryptDrives (usuarios/as y equipos) cuando no hay una regla personalizada aplicada",
"admin_registrationTitle": "Cerrar registración",
"admin_registrationHint": "Los visitantes de la instancia no pueden crear cuentas. Las invitaciones pueden ser creadas por los administradores.",
"snapshots_cantMake": "La captura no pudo ser creada. Has sido desconectado.",
"snapshots_notFound": "Esta captura ya no existe debido a que el historial del documento ha sido borrado.",
"snapshot_error_exists": "Ya hay una captura de esta versión",
"snapshots_ooPickVersion": "Debes seleccionar una versión antes de crear una captura",
"admin_registrationHint": "No permitir a ningún usuario/a nuevo/a registrarse",
"snapshots_cantMake": "La instantánea no pudo ser creada. Estás desconectado/a.",
"snapshots_notFound": "Esta instantánea ya no existe debido a que el historial del documento ha sido borrado.",
"snapshot_error_exists": "Ya hay una instantánea de esta versión",
"snapshots_ooPickVersion": "Debes seleccionar una versión antes de crear una instantánea",
"oo_version": "Versión: ",
"oo_version_latest": "Último",
"snapshots_delete": "Eliminar",
@ -1115,50 +1115,50 @@
"snapshots_close": "Cerrar",
"snapshots_restore": "Restaurar",
"snapshots_open": "Abrir",
"snapshots_placeholder": "Título de la captura",
"snapshots_new": "Nueva captura",
"snapshots_button": "Capturas",
"snaphot_title": "Captura",
"infobar_versionHash": "Actualmente estás viendo una versión antigua de este documento ({0}).",
"snapshots_placeholder": "Título de la instantánea",
"snapshots_new": "Nueva Instantánea",
"snapshots_button": "Instantáneas",
"snaphot_title": "Instantánea",
"infobar_versionHash": "Actualmente estás viendo una versión pasada de este documento ({0}).",
"history_restoreDriveDone": "CryptDrive restaurado",
"history_restoreDrivePrompt": "¿Estás seguro de que quieres reemplazar la versión actual del CryptDrive con la versión mostrada?",
"history_restoreDrivePrompt": "¿Estás seguro/a de que quieres reemplazar la versión actual del CryptDrive con la versión mostrada?",
"history_restoreDriveTitle": "Restaurar la versión seleccionada del CryptDrive",
"history_userNext": "Siguiente autor",
"history_userNext": "Siguiente autor/a",
"history_fastNext": "Siguiente sesión de edición",
"history_userPrev": "Autor previo",
"history_userPrev": "Autor/a previo/a",
"history_fastPrev": "Sesión de edición previa",
"share_versionHash": "Estás a punto de compartir la versión del historial seleccionada del documento en el modo de solo lectura. Esto también <b>dará acceso de visión</b> para todas las versiones del documento.",
"history_shareTitle": "Compartir un enlace a esta versión",
"history_cantRestore": "Restauración fallida. Desconectado.",
"share_versionHash": "Estás a punto de compartir la versión del historial seleccionado del documento en el modo de solo lectura. Esto también <b>dará acceso de visión</b> para todas las versiones del documento.",
"history_shareTitle": "Compartir un link a esta versión",
"history_cantRestore": "Restauración fallida. Estás desconectado/a.",
"history_close": "Cerrar",
"history_restore": "Restaurar",
"share_bar": "Crear enlace",
"share_bar": "Crear link",
"settings_cat_kanban": "Kanban",
"settings_kanbanTagsOr": "O",
"settings_kanbanTagsAnd": "Y",
"settings_kanbanTagsHint": "Selecciona como quieres que actúe el filtro de etiquetas cuando se seleccionen múltiples etiquetas: mostrar solo tarjetas que contienen todas las etiquetas seleccionadas (Y) o mostrar tarjetas que contienen cualquiera de las etiquetas seleccionadas (O)",
"settings_kanbanTagsHint": "Selecciona como quieres que actúe el filtro de etiquetas cuando se seleccionen múltiples etiquetas: solo mostrar tarjetas conteniendo todas las etiquetas seleccionadas (Y) o mostrar tarjetas conteniendo cualquiera de las etiquetas seleccionadas (O)",
"settings_kanbanTagsTitle": "Filtro de etiquetas",
"pad_tocHide": "Resumen",
"pad_tocHide": "Esquema",
"fm_noResult": "No se encontraron resultados",
"fm_restricted": "No tienes acceso",
"fm_emptyTrashOwned": "Tu basurero contiene documentos que te pertenecen. Puedes <b>borrarlos</b> solamente de tu disco, o <b>destruirlos</b> para todos los usuarios.",
"fm_emptyTrashOwned": "Tu basurero contiene documentos que te pertenecen. Puedes <b>borrarlos</b> solamente de tu disco, o <b>detruirlos</b> para todos/as los/as usuarios/as.",
"support_formCategoryError": "Error: la categoría está vacía",
"support_category": "Escoge una categoría",
"oo_refresh": "Refrescar",
"notification_folderSharedTeam": "{0} ha compartido una carpeta con el equipo {2}: <b>{1}</b>",
"notification_folderSharedTeam": "{0} ha compartido una carpet con el equipo {2}: <b>{1}</b>",
"notification_fileSharedTeam": "{0} ha compartido un archivo con el equipo {2}: <b>{1}</b>",
"notification_padSharedTeam": "{0} ha compartido un documento con el equipo {2}: <b>{1}</b>",
"support_addAttachment": "Añadir adjunto",
"support_attachments": "Adjuntos",
"support_cat_all": "Todo",
"support_cat_other": "Otros",
"support_cat_bug": "Reporte de errores",
"support_cat_bug": "Reporte de fallos",
"support_cat_data": "Pérdida de contenido",
"support_cat_account": "Cuenta de usuario",
"support_cat_account": "Cuenta de usuario/a",
"info_privacyFlavour": "<a>Política de privacidad</a> para esta instancia",
"user_about": "Acerca de CryptPad",
"info_imprintFlavour": "<a>Información legal</a> acerca de los administradores de esta instancia",
"settings_safeLinkDefault": "Los links seguros ahora están activados por defecto. Por favor usa <i></i><b>Compartir</b> menu para compartir links en lugar de la barra de direcciones de tu navegador.",
"info_imprintFlavour": "<a>Información legal</a> acerca de los/as administradores/as de esta instancia",
"settings_safeLinkDefault": "Los links seguros ahora están activados por defecto. Por favor usa el menú <i></i><b>Compartir</b> para compartir links en lugar de la barra de direcciones de tu navegador.",
"support_languagesPreamble": "El equipo de soporte habla los siguientes idiomas:",
"slide_textCol": "Color del texto",
"slide_backCol": "Color de fondo",
@ -1169,20 +1169,20 @@
"toolbar_savetodrive": "Guardar como imagen",
"toolbar_insert": "Insertar",
"toolbar_theme": "Tema",
"todo_move": "Tu lista de cosas por hacer ahora está en el kanban <b>{0}</b> en tu disco.",
"todo_move": "Tu lista de cosas por hacer ahora está en el kanban <b>{0}</b> en tu Disco.",
"fm_sort": "Ordenar",
"comments_error": "No se puede añadir comentario aquí",
"comments_error": "No se puede comentar aquí",
"settings_padNotifCheckbox": "Desactivar las notificaciones de comentarios",
"settings_padNotifHint": "Ignorar notificaciones cuando alguien responda a uno de tus comentarios",
"settings_padNotifHint": "Ignorar las notificaciones cuando alguien responda a uno de tus comentarios",
"comments_comment": "Comentar",
"comments_resolve": "Resolver",
"comments_reply": "Responder",
"comments_submit": "Enviar",
"comments_submit": "Envíar",
"comments_edited": "Editado",
"comments_deleted": "Comentario eliminado por su autor",
"comments_deleted": "Comentario eliminado por su autor/a",
"mentions_notification": "{0} te ha mencionado en <b>{1}</b>",
"unknownPad": "Documento desconocido",
"comments_notification": "Respuestas a tu comentario \"{0}\" en <b>{1}</b>",
"comments_notification": "Responde a tu comentario \"{0}\" en <b>{1}</b>",
"cba_title": "Colores del autor",
"oo_login": "Por favor accede o regístrate para mejorar el rendimiento de las hojas de cálculo.",
"cba_hide": "Esconder los colores del autor",
@ -1209,9 +1209,9 @@
"kanban_body": "Contenido",
"kanban_title": "Título",
"teams": "Equipos",
"allow_text": "Usar una lista de acceso significa que solo los usuarios seleccionados y propietarios podrán acceder a este documento.",
"allow_text": "Usar una lista de acceso significa que solo los/as usuarios/as seleccionados/as y propietarios/as podrán acceder a este documento.",
"logoutEverywhere": "Cerrar sesión en todos lados",
"owner_text": "El o los propietarios de un documento son los únicos usuarios autorizados a: añadir o quitar propietarios, restringir acceso al documento con una lista de acceso, o eliminar el documento.",
"owner_text": "El/los/as propietario/a/s de un documento son los/as únicos/as usuarios/as autorizados/as para: añadir/expulsar propietarios/as, restringir acceso al documento con una lista de acceso, o eliminar el documento.",
"access_muteRequests": "Silenciar solicitudes de acceso para este documento",
"allow_label": "Lista de acceso: {0}",
"allow_disabled": "desactivado",
@ -1249,32 +1249,32 @@
"oo_sheetMigration_complete": "Versión actualizada disponible, presione OK para recargar.",
"admin_consentToContactTitle": "Consentir a contacto",
"admin_checkupButton": "Ejecutar diagnóstico",
"admin_checkupHint": "CryptPad incluye una página que diagnostica automáticamente problemas comunes de configuración y sugiere cómo corregirlos si es necesario.",
"admin_checkupTitle": "Validar la configuración de la instancia",
"admin_updateAvailableButton": "Ver notas de la versión",
"admin_updateAvailableHint": "Una nueva versión de CryptPad está disponible",
"admin_checkupHint": "CryptoPad incluye una página que automáticamente diagnostica errores comunes y sugiere cómo corregirlos si fuera necesario.",
"admin_checkupTitle": "Valide la configuración de la instancia",
"admin_updateAvailableButton": "Ver las notas de lanzamiento",
"admin_updateAvailableHint": "Una versión nueva de CryptPad está disponible",
"admin_updateAvailableTitle": "Nuevas versiones",
"admin_cat_network": "Red",
"mdToolbar_embed": "Incrustar archivo",
"restrictedLoginPrompt": "No estás autorizado a acceder a este documento. <a>Accede</a> si crees que tu cuenta debería tener acceso.",
"restrictedLoginPrompt": "No estás autorizado/a a acceder a este documento. <a>Accede</a> si crees que tu cuenta debería poder accederlo.",
"copyToClipboard": "Copiar al portapapeles",
"settings_driveRedirect": "Redirígeme automáticamente",
"settings_driveRedirectHint": "La redirección automática desde la página de inicio al drive cuando se inicia sesión ya no está habilitada por defecto. El comportamiento anterior puede habilitarse a continuación.",
"settings_driveRedirect": "Redirigirme automáticamente",
"settings_driveRedirectHint": "La redirección automática desde la página de inicio al disco cuando ya accedió ya no está activada por defecto. El comportamiento de legado puede ser activado abajo.",
"settings_driveRedirectTitle": "Redirección a la página de inicio",
"form_page": "Página {0}/{1}",
"form_clear": "Limpiar",
"form_addMultipleHint": "Añadir múltiples fechas y horas",
"form_addMultipleHint": "Añadir múltiples fechas y tiempos",
"form_addMultiple": "Añadir todo",
"form_anonymous_blocked": "Las respuestas de invitados están bloqueadas para este formulario. Debes <a href=\"/login/\">iniciar sesión</a> o <a href=\"/register/\">registrarte</a> para enviar respuestas.",
"form_add_item": "Añadir elemento",
"form_anonymous_blocked": "Las respuestas de invitados/a están bloqueadas para este formulario. Debes <a href=\"/login/\">acceder</a> o <a href=\"/register/\">registrarte</a> para enviar respuestas.",
"form_add_item": "Añadir ítem",
"form_add_option": "Añadir opción",
"form_newItem": "Nuevo elemento",
"form_newItem": "Nuevo ítem",
"form_newOption": "Nueva opción",
"form_defaultItem": "Elemento {0}",
"form_defaultItem": "Ítem {0}",
"form_defaultOption": "Opción {0}",
"form_anonymous_off": "Bloqueado",
"form_anonymous_on": "Permitido",
"form_anonymous": "Acceso de invitado (sin sesión iniciada)",
"form_anonymous": "Acceso de invitado/a (sin acceder)",
"oo_sheetMigration_loading": "Actualizando tu documento a la última versión. Porfavor espera aproximadamente 1 minuto.",
"oo_exportInProgress": "Exportación en progreso",
"oo_importInProgress": "Importación en progreso",
@ -1453,50 +1453,50 @@
"toolbar_expand": "Expandir barra de herramientas",
"toolbar_collapse": "Colapsar barra de herramientas",
"support_premiumLink": "Ver opciones de suscripción",
"support_premiumPriority": "Los usuarios premium ayudan a respaldar las mejoras en la usabilidad de CryptPad y se benefician de respuestas prioritarias a sus solicitudes de soporte.",
"form_totalResponses": "Total de respuestas: {0}",
"support_premiumPriority": "Los/as usuarios/as premium ayudan a financiar mejoras a la usabilidad de CryptPad y se benefician de respuestas priorizadas a sus tickets de soporte.",
"form_totalResponses": "Respuestas totales: {0}",
"ui_expand": "Expandir",
"ui_collapse": "Colapsar",
"fm_link_invalid": "URL no válida",
"fm_link_warning": "Advertencia: la URL excede los 200 caracteres",
"fm_link_invalid": "URL inválida",
"fm_link_warning": "Advertencia: la URL excede los 200 carácteres",
"form_anonName": "Tu nombre",
"notification_linkShared": "{0} ha compartido un enlace contigo: <b>{1}</b>",
"fm_link_name_placeholder": "Mi enlace",
"notification_linkShared": "{0} ha compartido un link contigo: <b>{1}</b>",
"fm_link_name_placeholder": "Mí link",
"fm_link_url": "URL",
"fm_link_name": "Nombre del Enlace",
"fm_link_type": "Enlace",
"fm_link_new": "Nuevo enlace",
"notification_openLink": "Has recibido un enlace <b>{0}</b> de {1}:",
"fm_link_name": "Nombre del link",
"fm_link_type": "Link",
"fm_link_new": "Nuevo link",
"notification_openLink": "Has recibido un link <b>{0}</b> de {1}:",
"form_exportCSV": "Exportar a CSV",
"team_leaveOwner": "Por favor, reduce privilegios de propietario antes de salir del equipo. Ten en cuenta que los equipos deben tener al menos un propietario; añade uno antes de proceder si actualmente eres el único.",
"admin_instancePurposeHint": "¿Porqué usas esta instancia? Tu respuesta será usada para ayudar al plan de desarrollo si la telemetría está activada.",
"team_leaveOwner": "Por favor degradate del rol de propietario/a antes de dejar el equipo. Ten en cuenta que los equipos deben tener al menos un/a propietario/a, por favor añade uno/a antes de proceder si actualmente eres el único/a propietario/a.",
"admin_instancePurposeHint": "¿Porqué diriges esta instancia? Tu respuesta será usada para informar al plan de desarrollo si su telemetría esta activada.",
"admin_purpose_business": "Para una empresa u organización comercial",
"admin_purpose_public": "Para proveer un servicio gratuito al público",
"admin_purpose_education": "Para una escuela o universidad",
"admin_purpose_org": "Para una organización sin fines de lucro o grupo de defensa",
"admin_purpose_personal": "Para mí, familia, o amigos",
"admin_purpose_education": "Para una escuela, colegio o universidad",
"admin_purpose_org": "Para una organización sin ánimos de lucro o un grupo de defensa",
"admin_purpose_personal": "Para mí, familia, o amigos/as",
"admin_purpose_experiment": "Para probar la plataforma o desarrollar nuevas funciones",
"admin_purpose_noanswer": "Prefiero no decirlo",
"admin_instancePurposeTitle": "Propósito de la instancia",
"resources_learnWhy": "Entérate por qué fue bloqueada",
"resources_openInNewTab": "Abrir en una nueva pestaña",
"resources_imageBlocked": "CryptPad bloqueó una imagen remota",
"resources_learnWhy": "Conoce por qué fue bloqueado",
"resources_openInNewTab": "Abrirlo en una nueva pestaña",
"resources_imageBlocked": "CryptPad bloqueó una imágen remota",
"fc_open_formro": "Abrir (como participante)",
"form_poll_hint": "<i></i>: Si, <i></i>: No, <i></i>: Aceptar",
"form_poll_hint": "<i></i>: Si, <i></i>: No, <i></i>: Aceptable",
"admin_provideAggregateStatisticsLabel": "Proveer estadísticas adicionales",
"admin_provideAggregateStatisticsHint": "Puedes optar por incluir mediciones de uso adicionales para los desarrolladores, tal como el número aproximado de usuarios diarios y registrados en tu instancia.",
"admin_provideAggregateStatisticsTitle": "Estadísticas adicionales",
"admin_provideAggregateStatisticsHint": "Puedes optar por incluir mediciones de uso adicionales para los/as desarrolladores/as, tal como el número aproximado de usuarios/as diarios y registrados/as para tu instancia.",
"admin_provideAggregateStatisticsTitle": "Agregación estadística",
"admin_blockDailyCheckLabel": "Desactivar telemetría del servidor",
"admin_blockDailyCheckHint": "Las instancias de CryptPad envían un mensaje al servidor de los desarrolladores una vez al día al iniciarse. Esto les permite llevar un registro de cuántos servidores se están ejecutando y qué versiones del software. Puedes optar por no participar en esta medición a continuación. El contenido de este mensaje se puede encontrar en el registro del servidor de la aplicación para tu revisión.",
"admin_blockDailyCheckHint": "Las instancias de CryptPad envian un mensaje al servidor de los/as desarrolladores/as cuando son lanzadas y una vez por día a partir de entonces. Esto les permite mantenerse al tanto de cuantos servidores están funcionando con que versiones del software. Puedes salirte de esta medición abajo. Los contenidos de este mensaje pueden ser encontrados en el registro de la aplicación del servidor para tu revisión.",
"admin_blockDailyCheckTitle": "Telemetría del servidor",
"admin_removeDonateButtonLabel": "No promocionar campañas de crowdfunding",
"admin_removeDonateButtonHint": "El desarrollo de CryptPad está parcialmente financiado por subvenciones públicas y donaciones. Publicitar nuestros esfuerzos de crowdfunding en tu instancia ayuda a los desarrolladores a continuar mejorando la plataforma para todos, pero puedes desactivar estos avisos si los consideras inapropiados.",
"admin_removeDonateButtonTitle": "Participación Crowdfunding",
"admin_removeDonateButtonLabel": "No publicar las campañas de financiación colectiva",
"admin_removeDonateButtonHint": "El desarrollo de CryptPad es financiado parcialmente por subvenciones públicas y donaciones. Publicar nuestros esfuerzos de financiación colectiva en tu instancia ayuda a los/as desarrolladores/as a continuar mejorando la plataforma para todos/as, pero puedes desactivar estos abisos si los encuentras inapropiados.",
"admin_removeDonateButtonTitle": "Participación en la financiación colectiva",
"admin_listMyInstanceLabel": "Listar esta instancia",
"admin_listMyInstanceHint": "Si tu instancia es adecuada para el uso público puedes aceptar que sea enlistada en los directorios de la red. La telemetría del servidor debe estar activada para que esto tenga efecto.",
"admin_listMyInstanceTitle": "Listar mi instancia en directorios públicos",
"admin_consentToContactLabel": "Acepto",
"admin_consentToContactHint": "La telemetría del servidor incluye el correo electrónico de contacto del administrador para que los desarrolladores puedan notificarte sobre problemas graves con el software o la configuración. Nunca será compartido, vendido ni utilizado con fines de marketing. Acepta para ser contactado si deseas ser informado de problemas críticos en tu servidor.",
"admin_listMyInstanceHint": "Si tu instancia es adecuada para el uso público puedes consentir a que sea enlistada en los directorios de la red. La telemetría del servidor debe estar activada para que esto tenga algún efecto.",
"admin_listMyInstanceTitle": "Listar mi instancia en los directorios públicos",
"admin_consentToContactLabel": "Consiento",
"admin_consentToContactHint": "La telemetría del servidor incluye el correo de contacto del administrador/a para que así los/as desarrolladores/as puedan notificarte de problemas serios con el software o tu configuración. Nunca será compartido, vendido, o usado por razones de marketing. Consiente al contacto si te gustaría estar informado/a de problemas críticos en tu servidor.",
"calendar_nth_5": "quinto",
"calendar_nth_last": "último",
"calendar_rec_monthly_nth": "Cada {0} {1} del mes",

File diff suppressed because it is too large Load diff

View file

@ -1717,51 +1717,5 @@
"admin_supportEnabled": "Laguntza-sistema gaituta dago.",
"admin_supportDisabled": "Laguntza-sistema desgaituta dago.",
"admin_supportDelete": "Desgaitu laguntza",
"admin_colorHint": "Aldatu zure CryptPad instantziaren nabarmentze kolorea. Ziurtatu testua eta botoiak kontraste nahikoarekin irakur daitezkeela gai argietan zein ilunetan.",
"admin_supportAdd": "Gehitu kontaktu bat laguntza-taldeari",
"admin_supportConfirm": "Ziur zaude? Honek lehendik dauden sarrera guztiak ezabatuko ditu eta moderatzaile guztien sarbidea blokeatuko da.",
"admin_supportMembers": "Laguntza taldea",
"admin_supportRotateNotify": "Abisua: gako berriak sortu dira baina ustekabeko errore batek sistemak moderatzaileei bidaltzea eragotzi du. Mesedez, kendu eta gehitu berriro laguntza-taldeko kide guztiak",
"support_cat_settings": "Ezarpenak",
"support_cat_search": "Bilatu",
"support_cat_closed": "Itxita",
"support_cat_open": "Sarrera-ontzia",
"support_cat_legacy": "Zaharra",
"support_pending": "Artxibatutako sarrerak:",
"support_pending_tag": "Artxibatuta",
"support_active_tag": "Sarrera-ontzia",
"support_closed_tag": "Itxita",
"support_privacyTitle": "Erantzun anonimoki",
"moderationPage": "Laguntza mahaia",
"admin_supportInit": "Hasieratu laguntza mahaia instantzia honetan",
"support_openTicketTitle": "Ireki txartel bat erabiltzaile batekin",
"support_privacyHint": "Markatu aukera hau zure erabiltzaile-izenaren ordez \"Laguntza-taldea\" gisa erantzuteko",
"support_notificationsHint": "Markatu aukera hau txartel eta erantzun berrien jakinarazpenak desgaitzeko",
"support_notificationsTitle": "Desgaitu jakinarazpenak",
"support_recordedEmpty": "Kode-zatirik ez",
"support_userChannel": "Erabiltzailearen jakinarazpenen kanalaren IDa",
"support_openTicketHint": "Kopiatu hartzailearen erabiltzailearen datuak bere profil-orritik edo lehendik dagoen laguntza-txartel batetik. Mezu honi buruzko CryptPad jakinarazpena jasoko dute.",
"support_recordedId": "Kode-zatiaren ID (esklusiboa)",
"support_userKey": "Erabiltzailearen gako publikoa",
"support_invalChan": "Jakinarazpen-kanal baliogabea",
"support_recordedTitle": "Kode-zatiak",
"admin_supportTeamTitle": "Kudeatu laguntza taldea",
"support_pasteUserData": "Itsatsi erabiltzailearen datuak hemen",
"support_legacyButton": "Lortu txartel aktiboak",
"support_recordedHint": "Gorde testu arrunta klik bakarreko lasterbide gisa laguntza-mezuetan txertatzeko.",
"support_recordedContent": "Edukia",
"support_legacyTitle": "Ikusi laguntza-datu zaharrak",
"support_searchLabel": "Bilatu (titulua edo txartelaren ID)",
"support_legacyHint": "Ikusi laguntza sistema zaharraren txartelak eta berrerabili berrian.",
"support_legacyDump": "Esportatu guztiak",
"support_insertRecorded": "Txertatu kode-zatia",
"support_legacyClear": "Ezabatu kontu honetarako",
"support_moveActive": "Eraman aktibora",
"support_team": "Laguntza taldea",
"support_answerAs": "<b>{0}</b> gisa erantzuten",
"support_movePending": "Eraman artxibora",
"admin_supportOpen": "Ireki laguntza tresnak",
"support_copyUserData": "Kopiatu erabiltzailearen datuak",
"support_userNotification": "Laguntza-txartel edo erantzun berria: {0}",
"admin_supportTeamHint": "Gehitu eta kendu jendea instantziako laguntza-taldetik"
"admin_colorHint": "Aldatu zure CryptPad instantziaren nabarmentze kolorea. Ziurtatu testua eta botoiak kontraste nahikoarekin irakur daitezkeela gai argietan zein ilunetan."
}

View file

@ -609,8 +609,8 @@
"admin_activeSessionsHint": "Nombre de connexions websocket actives (et adresses IP uniques connectées)",
"admin_activePadsTitle": "Documents actifs",
"admin_activePadsHint": "Nombre de documents uniques actuellement ouverts (lus ou modifiés)",
"admin_registeredTitle": "Drives utilisateur·ices et équipes",
"admin_registeredHint": "Nombre de drives actifs sur votre instance",
"admin_registeredTitle": "Utilisateur·ices enregistré·es",
"admin_registeredHint": "Nombre d'utilisateur·ices enregistré·es sur votre instance",
"admin_updateLimitTitle": "Mettre à jour les quotas",
"admin_updateLimitHint": "Forcer la mise à jour des limites de stockage des utilisateur·ices peut être effectué à tout moment, mais cela n'est utile que lorsqu'une erreur survient",
"admin_updateLimitButton": "Mettre à jour les quotas",
@ -1018,7 +1018,7 @@
"admin_defaultlimitTitle": "Limite de stockage (Mo)",
"admin_defaultlimitHint": "Limite de stockage maximum pour le CryptDrive (utilisateur·ices et équipes) si aucune règle spéciale n'est appliquée",
"admin_registrationTitle": "Fermer l'enregistrement",
"admin_registrationHint": "Les visiteur·ices de l'instance ne sont pas autorisé·es à créer un compte. Des invitations peuvent être créées par les administrateur·ices.",
"admin_registrationHint": "Ne pas autoriser l'enregistrement de nouvelles·aux utilisateur·ices",
"snapshots_cantMake": "La capture n'a pas pu être effectuée. Vous êtes déconnecté.",
"snapshots_notFound": "Cette capture n'existe plus car l'historique du document a été supprimé.",
"admin_limitUser": "Clé publique de l'utilisateur·ice",
@ -1249,8 +1249,8 @@
"form_makePublic": "Publier les réponses",
"form_invalidQuestion": "Questions {0}",
"form_invalidWarning": "Certaines réponses contiennent des erreurs :",
"form_input_ph_url": "https://example.net",
"form_input_ph_email": "courriel_exemple@example.net",
"form_input_ph_url": "https://exemple.fr",
"form_input_ph_email": "courriel@exemple.fr",
"form_notAnswered": "<b>{0}</b> réponses vides",
"form_answerWarning": "Identité non confirmée",
"form_answerName": "Réponse de {0} le {1}",
@ -1680,7 +1680,7 @@
"kanban_showTags": "Voir tous les mots-clés",
"kanban_hideTags": "Voir moins de mots-clés",
"admin_forcemfaTitle": "Authentification à deux facteurs obligatoire",
"admin_forcemfaHint": "Tou·tes les utilisateur·ices de l'instance devront activer l'authentification a deux facteurs (2FA) pour pouvoir se connecter à leur compte. Notez que les utilisateur·ices existant·es ne pourront pas continuer à utiliser leur compte sans mettre en place une application TOTP.",
"admin_forcemfaHint": "Tous les utilisateurs de cette instance seront obligés d'activer l'authentification à deux facteurs pour se connecter à leur compte.",
"loading_mfa_required": "L'authentification à deux facteurs est requise pour cette instance. Veuillez mettre à jour votre compte en utilisant une application d'authentification et le formulaire ci-dessous.",
"admin_cat_users": "Registre utilisateur·ices",
"admin_invitationCreate": "Créer un lien d'invitation",
@ -1706,7 +1706,7 @@
"admin_logoTitle": "Logo personnalisé",
"admin_supportAdd": "Ajouter un contact à l'équipe support",
"admin_logoHint": "SVG, PNG ou JPG, taille maximum 200 kB",
"admin_logoRemoveButton": "Réinitialiser",
"admin_logoRemoveButton": "Logo par défaut",
"admin_colorCurrent": "Couleur d'accent actuelle",
"admin_colorChange": "Changer la couleur",
"admin_colorPick": "Choisir une couleur",
@ -1763,22 +1763,5 @@
"support_openTicketHint": "Copiez les données de l'utilisateur·ices destinataire depuis leur page de profil ou depuis un ticket de support existant. Iels recevront une notification CryptPad à propos de ce message.",
"support_invalChan": "Canal de notifications invalide",
"support_legacyHint": "Voir les tickets de l'ancien système de support et les recréer dans le nouveau.",
"support_userNotification": "Nouveau ticket de support ou réponse : {0}",
"install_token": "Jeton d'installation",
"install_header": "Installation",
"admin_appSelection": "Configuration des applications",
"install_instance": "Créer le premier compte administrateur·ice, puis continuer pour personnaliser l'instance",
"install_launch": "Paramétrage de l'instance",
"admin_appsTitle": "Applications de l'instance",
"admin_appsHint": "Choisissez quelles applications sont activées sur cette instance.",
"admin_cat_apps": "Applications",
"onboarding_upload": "Sélectionner un logo",
"onboarding_save_error": "Certaines options n'ont pas pu être sauvegardées correctement. Veuillez visiter l'espace d'administration pour vérifier les valeurs indiquées.",
"admin_onboardingNameHint": "Veuillez choisir un titre, une description, une couleur de thème et un logo (tous sont optionnels)",
"admin_onboardingNameTitle": "Bienvenu sur votre instance CryptPad",
"admin_onboardingOptionsTitle": "Réglages de l'instance",
"admin_onboardingNamePlaceholder": "Nom de l'instance",
"admin_onboardingOptionsHint": "Veuillez sélectionner les options appropriées pour votre instance.<br>Ces paramètres peuvent être changés plus tard depuis l'espace d'administration.",
"admin_onboardingDescPlaceholder": "Texte de description de l'instance",
"install_notes": "<ul class=\"cp-notes-list\"><li>Créez votre premier compte administrateur·ice sur cette page. Les administrateur·ices peuvent paramétrer l'instance, ceci incluant les quotas de stockage, et ont accès aux outils de modération.</li><li>Votre mot de passe est la clé secrète qui chiffre l'ensemble de vos documents et vos privilèges d'administration sur l'instance. <span class=\"red\">Si vous le perdez il n'est pas possible de récupérer vos données.</span></li><li>Si vous utilisez un ordinateur partagé, <span class=\"red\">n'oubliez pas de vous déconnecter</span> quand vous aurez terminé. Simplement fermer la fenêtre du navigateur web laisse votre compte exposé à des risques de sécurité. </li></ul>"
"support_userNotification": "Nouveau ticket de support ou réponse : {0}"
}

View file

@ -331,95 +331,5 @@
"status": "Állapotlap",
"access_passwordUsed": "Ennek a dokumentumnak ez már volt jelszava . Nem használható többször.",
"admin_diskUsageWarning": "Figyelem! A példányon tárolt adatmennyiségtől függően ez a riport elhasználhatja akár a server teljes memóriáját és lefagyáshoz vezethet.",
"poll_comment_disabled": "A ✓ gommbal tudod a kérdőívet publikálni, ezután lehet kommentálni.",
"fm_removePermanentlyDialog": "Tuti kiakarod törtölni ezt a Driveból? Ez a fájl megmarad a többi felhasználok számára akik eltárolták.",
"fm_contextMenuError": "Nem tudtuk megnyitni a menüt ehez. Ha továbbra is fennmarad ez a probléma, frissítse az oldalt.",
"fm_removeSeveralPermanentlyDialog": "Biztosan akarod törölni ezt a {0} elemet a tárhelyedről? De továbbra is megmaradnak a többi felhasználó tárhelyén, akik szintén tárolták ezeket.",
"fm_deleteOwnedPads": "Biztos vagy benne hogy véglegesen megsemmisíted ezt a fájlt?",
"fm_restoreDialog": "Biztosan helyreállitja a/az {0}-t az eredeti helyére?",
"fm_unknownFolderError": "A kiválasztott vagy legutóbb megtekintett mappa már nem létezik. Szülő-mappa megnyitása...",
"fm_selectError": "Nem lehet kiválasztani a célzott elemet. Ha a probléma továbbra is fennáll, próbálja újratölteni az oldalt.",
"fm_categoryError": "Nem lehet megnyitni a kiválasztott kategóriát, a gyökérmappát mutatjuk.",
"fm_info_root": "Tetszőleges mélységű mapparendszert hozhatsz létre a fájljaid rendezésére.",
"fm_info_template": "Ezek a dokumentumok sablonként vannak tárolva. Új dokumentumok létrehozásához lehet őket használni.",
"fm_info_recent": "Ezelet a dokumentumokat a közelmúltban megnyitották vagy módosították (Te, vagy a közreműködők).",
"fm_info_trash": "Ürítsd ki a Kukát a CryptDrive tárhelyed felszabadításához.",
"fm_info_sharedFolder": "Ez egy megosztott mappa. Nem vagy bejelentkezve, ezért Számodra ez csak olvasható. <br><a href=\"/register/\">Regisztrálj</a>, vagy <a href=\"/login/\">Jelentkezz be</a>, hogy importálhas a CryptDrive-odra, és szerkeszthesd a tartalmát.",
"fm_info_anonymous": "Nem vagy bejelentkezve, így a dokumentumaid {0} nap múlva lejárnak. Ha törlődik a böngésződ gyorsítótára, elvesznek.<br><a href=\"/register/\">Regisztrálj</a> (nincs szükség személyes adatok megadására) vagy <a href=\"/login/\">Jelentkezz be</a>, hogy tárolhasd őket hosszabb távon. <a href=\"#docs\">Tudj meg többet a a regisztrált CryptPad-fiókokról!</a>.",
"fm_renamedPad": "Egyéni nevet állított be ehhez a dokumentumhoz. A neve: <br><b>{0}</b>",
"fm_canBeShared": "Ez a mappa megosztható",
"fm_prop_tagsList": "Címkék",
"fm_burnThisDriveButton": "Törölje a CryptPad által tárolt összes információt a böngészőből",
"fm_burnThisDrive": "Biztos, hogy el akar távolítani mindent, amit a CryptPad tárol a böngészőjében?<br>Ez eltávolítja a CryptDrive-ot és annak előzményeit a böngészőjéből, de a dokumentumai továbbra is létezni fognak (titkosítva) a szerverünkön.",
"fm_padIsOwned": "Ön ennek a dokumentumnak a tulajdonosa",
"fm_padIsOwnedOther": "Ez a dokumentum egy másik felhasználó tulajdonában van",
"fm_tags_name": "Címke neve",
"fm_tags_used": "Felhasználások száma",
"fm_restoreDrive": "A meghajtó visszaállítása egy korábbi állapotba. A legjobb eredmény elérése érdekében ne végezzen változtatásokat a meghajtón, amíg ez a folyamat be nem fejeződött.",
"fc_newfolder": "Új mappa",
"fc_rename": "Átnevezés",
"fc_color": "Szín megváltoztatása",
"fc_open": "Megnyitás",
"fc_open_ro": "Megnyitás (csak olvasás)",
"fc_expandAll": "Minden kinyitása",
"fc_delete": "Kukába helyezés",
"fc_delete_owned": "Megsemmisítés",
"fc_restore": "Visszaállítás",
"fc_remove": "Kitörlés",
"fc_remove_sharedfolder": "Eltávolitás",
"fc_empty": "Kuka kiürítése",
"fc_prop": "Tulajdonságok",
"fc_hashtag": "Címkék",
"settingsButton": "Beállítások",
"login_username": "Felhasználónév",
"login_password": "Jelszó",
"register_header": "Regisztrálás",
"register_cancel": "Mégse",
"settings_cat_account": "Fiók",
"settings_cat_drive": "Drive",
"settings_cat_code": "Kód",
"settings_cat_subscription": "Feliratkozás",
"settings_title": "Beállitások",
"settings_save": "Mentés",
"settings_restore": "Helyreállítás",
"settings_resetButton": "Eltávolitás",
"settings_resetTipsAction": "Visszaállítás",
"settings_resetTips": "Tippek",
"settings_resetThumbnailsAction": "Törlés",
"settings_autostoreYes": "Automatikus",
"settings_userFeedbackTitle": "Visszajelzés",
"upload_cancelled": "Megszakított",
"upload_size": "Méret",
"download_mt_button": "Letöltése",
"download_dl": "Letöltés",
"download_step1": "Letöltés",
"download_step2": "Visszatitkósitás",
"todo_title": "CryptTodo",
"mdToolbar_help": "Segítség",
"mdToolbar_bold": "Vastag",
"mdToolbar_italic": "Döltbető",
"mdToolbar_strikethrough": "Áthúzott",
"mdToolbar_link": "Link",
"mdToolbar_quote": "Idézés",
"mdToolbar_code": "Kód",
"about": "Rólunk",
"features_anon": "Vendég",
"features_registered": "Regisztrált",
"features_premium": "Premium",
"edit": "Szerkesztés",
"view": "Megtekintés",
"fm_deletedPads": "Ezek a dokumentumok már nem léteznek a szerveren, eltávolításra kerültek a CryptDrive-ról: {0}",
"fc_collapseAll": "Minden bezárása",
"register_warning": "Figyelmeztetés",
"mdToolbar_tutorial": "https://www.markdowntutorial.com/",
"fm_info_owned": "Ön a tulajdonosa az itt megjelenített dokumentumoknak. Ez azt jelenti, hogy bármikor véglegesen eltávolíthatja őket a szerverről. Ha ezt megteszi, más felhasználók többé nem férhetnek hozzá hozzájuk.",
"fm_moveNestedSF": "Egy megosztott mappát nem helyezhet el egy másik mappán belül. A {0} mappa nem lett áthelyezve.",
"fm_passwordProtected": "Jelszóvédett",
"fc_newsharedfolder": "Új megosztott mappa",
"settings_cat_cursor": "Egérmutató",
"settings_thumbnails": "Előnézet",
"settings_import": "Importálás",
"upload_pending": "Függöben lévő",
"upload_up": "Feltöltés",
"features_f_subscribe": "Feliratkozás"
"poll_comment_disabled": "A ✓ gommbal tudod a kérdőívet publikálni, ezután lehet kommentálni."
}

Some files were not shown because too many files have changed in this diff Show more