diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 8a1297856..000000000 --- a/.eslintignore +++ /dev/null @@ -1,40 +0,0 @@ -# SPDX-FileCopyrightText: 2023 XWiki CryptPad Team and contributors -# -# SPDX-License-Identifier: AGPL-3.0-or-later - -node_modules/ -www/components/ -www/bower_components/ -www/common/onlyoffice/dist -www/common/onlyoffice/x2t -onlyoffice-dist/ - -www/scratch -www/accounts -www/lib -www/accounts -www/worker -www/todo - -#lib/plugins/ - -www/common/hyperscript.js - -www/pad/wysiwygarea-plugin.js -www/pad/mediatag-plugin.js -www/pad/mediatag-plugin-dialog.js -www/pad/disable-base64.js -www/pad/wordcount/ - -www/kanban/jkanban.js -www/common/jscolor.js - -www/common/media-tag-nacl.min.js - -customize/ - -www/debug/chainpad.dist.js - -www/pad/mathjax/ -www/code/mermaid*.js -www/code/orgmode.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 924eddfc3..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-FileCopyrightText: 2024 XWiki CryptPad Team and contributors -// -// SPDX-License-Identifier: AGPL-3.0-or-later - -module.exports = { - 'env': { - 'browser': true, - 'es2021': true, - 'node': true - }, - 'plugins': ['compat'], - 'extends': ['eslint:recommended', 'plugin:compat/recommended'], - "globals": { - "define": "readonly", - }, - 'overrides': [ - { - 'env': { - 'node': true - }, - 'files': [ - '.eslintrc.{js,cjs}' - ], - 'parserOptions': { - 'sourceType': 'script' - } - } - ], - 'parserOptions': { - 'ecmaVersion': 'latest' - }, - 'rules': { - 'indent': [ - 'off', // TODO enable this check - 4 - ], - 'linebreak-style': [ - 'off', // git handles linebreak conversion for us - 'unix' - ], - 'quotes': [ - 'off', // TODO enable this check - 'single' - ], - 'semi': [ - 'error', - 'always' - ], - - // TODO remove these exceptions from the eslint defaults - 'no-irregular-whitespace': ['off'], - 'no-self-assign': ['off'], - 'no-empty': ['off'], - 'no-useless-escape': ['off'], - 'no-extra-boolean-cast': ['off'], - 'no-prototype-builtins': ['off'], - } -}; diff --git a/.github/ISSUE_TEMPLATE/bug_resolution.yml b/.github/ISSUE_TEMPLATE/bug_resolution.yml index b5a3b276e..474070d59 100644 --- a/.github/ISSUE_TEMPLATE/bug_resolution.yml +++ b/.github/ISSUE_TEMPLATE/bug_resolution.yml @@ -89,21 +89,13 @@ body: label: Version description: What version of CryptPad are you running? options: + - 2024.12.0 + - 2024.9.1 - 2024.9.0 - 2024.6.1 - 2024.6.0 - 2024.3.1 - 2024.3.0 - - 5.7.0 - - 5.6.0 - - 5.5.0 - - 5.4.1 - - 5.4.0 - - 5.3.0 - - 5.2.1 - - 5.2.0 - - 5.1.0 - - 5.0.0 - Other validations: required: true diff --git a/.gitignore b/.gitignore index bac376dcd..013a3e931 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ www/common/onlyoffice/v* /onlyoffice-conf/ /onlyoffice-dist/ +_build + # ---> Node # Logs logs diff --git a/customize.dist/messages.js b/customize.dist/messages.js index a583240a6..2b4ee6234 100755 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -134,7 +134,6 @@ define(req, function(AppConfig, Default, Language) { return text; } }; - return Messages; }); diff --git a/customize.dist/pages/index.js b/customize.dist/pages/index.js index b732d2558..43e2b44d5 100644 --- a/customize.dist/pages/index.js +++ b/customize.dist/pages/index.js @@ -167,13 +167,20 @@ 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)); + + Extensions.getExtensions('HOMEPAGE_POPUP').forEach(_ext => { + _ext.then(ext => { + if (ext) { + ext.getContent(utils, content => { + $(popup).append(h('div.cp-extensions-popup', content)); + }); + } + }).catch(error => { + console.error(error); }); }); + return [ h('div#cp-main', [ Pages.infopageTopbar(), diff --git a/customize.dist/src/less2/include/creation.less b/customize.dist/src/less2/include/creation.less index cd04cf858..f61f20d90 100644 --- a/customize.dist/src/less2/include/creation.less +++ b/customize.dist/src/less2/include/creation.less @@ -69,7 +69,7 @@ outline: none; width: 700px; max-width: 90vw; - height: 500px; + //height: 500px; border-radius: @variables_radius_L; max-height: ~"calc(100vh - 20px)"; margin: 0px; @@ -85,6 +85,7 @@ } .cp-creation-checkboxes { + min-width: 300px; flex-flow: column; align-items: baseline !important; max-height: 150px; @@ -156,11 +157,10 @@ flex: 1 0 auto; justify-content: space-around; & > div { - width: 300px; + //width: 300px; max-width: 100%; display: flex; align-items: center; - flex-wrap: wrap; font-size: 16px; //margin: 10px 0; min-height: 28px; @@ -293,6 +293,11 @@ } } } + .cp-creation-password-warning { + font-size: 0.75em; + line-height: 120%; + margin: 0.4rem 1rem calc(0.4rem + 6px); + } .cp-creation-settings { button { margin: 0; @@ -421,7 +426,6 @@ #cp-creation-form { & > div { width: 95%; - margin: 0 auto; } .cp-creation-expire { &.active { @@ -431,7 +435,6 @@ .cp-creation-slider { flex: none; order: 10; - width: 100%; } } } @@ -440,7 +443,7 @@ } @media screen and (max-width: 800px) { #cp-creation { - height: 550px; + //height: 550px; #cp-creation-form { div.cp-creation-template { flex-flow: column; diff --git a/customize.dist/src/less2/include/dropdown.less b/customize.dist/src/less2/include/dropdown.less index 4a5099ee3..ee63ab5bc 100644 --- a/customize.dist/src/less2/include/dropdown.less +++ b/customize.dist/src/less2/include/dropdown.less @@ -160,12 +160,12 @@ li[role="menuitem"] { border-radius: @variables_radius; white-space: nowrap; - &:hover { - background-color: @cp_dropdown-bg-hover !important; - } &:focus-visible { outline-color: @cp_dropdown-fg; } + &:hover { + background-color: @cp_dropdown-bg-hover; + } } &> span { box-sizing: border-box; diff --git a/customize.dist/src/less2/include/notifications.less b/customize.dist/src/less2/include/notifications.less index 6a69b8beb..81e5fb5f8 100644 --- a/customize.dist/src/less2/include/notifications.less +++ b/customize.dist/src/less2/include/notifications.less @@ -97,6 +97,26 @@ margin: 0; } } + .cp-dropdown-container .cp-dropdown-content { + li[role="menuitem"]{ + .cp-notification-dismiss:hover { + border-radius: @variables_radius; + background-color: @cp_dropdown-bg-hover; + } + } + li[role="menuitem"].cp-notification-avatar { + &:hover { + background-color: transparent; + } + .cp-avatar:hover { + background-color: @cp_dropdown-bg-hover; + } + .cp-notification-content:hover { + border-radius: @variables_radius; + background-color: @cp_dropdown-bg-hover; + } + } + } } diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 9d11dde7d..e61d9fbda 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -734,10 +734,6 @@ color: inherit; } } - .cp-notifications-empty { - color: @cp_dropdown-fg; - padding: 5px; - } button { position: relative; .cp-dropdown-button-title { @@ -765,6 +761,10 @@ margin: 0 -5px; padding: 0; } + .cp-notifications-empty { + color: @cp_dropdown-fg; + padding: 0.3em; + } } } .cp-toolbar-link { diff --git a/docker-compose.yml b/docker-compose.yml index 6f5a190f0..49a81a25b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ --- services: cryptpad: - image: "cryptpad/cryptpad:version-2024.6.1" + image: "cryptpad/cryptpad:version-2024.12.0" hostname: cryptpad environment: diff --git a/docs/example-advanced.nginx.conf b/docs/example-advanced.nginx.conf index 00bec9369..64e226bcc 100644 --- a/docs/example-advanced.nginx.conf +++ b/docs/example-advanced.nginx.conf @@ -100,7 +100,7 @@ server { 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 "*"; } + if ($uri ~ ^/common/onlyoffice/.*/fonts/) { set $allowed_origins "*"; } add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options nosniff; @@ -128,7 +128,7 @@ server { # We had inverted them as an optimization, but Safari 16 introduced a bug that interpreted # some important headers incorrectly when loading these files from cache. # This is why we can't have nice things :( - if ($uri ~ ^(\/|.*\/|.*\.html)$) { + if ($uri ~ ^(?:/|.*/|.*\.html)$) { set $cacheControl no-cache; } @@ -177,8 +177,8 @@ server { set $unsafe 0; # the following assets are loaded via the sandbox domain # they unfortunately still require exceptions to the sandboxing to work correctly. - if ($uri ~ ^\/(sheet|doc|presentation)\/inner.html.*$) { set $unsafe 1; } - if ($uri ~ ^\/common\/onlyoffice\/.*\/.*\.html.*$) { set $unsafe 1; } + if ($uri ~ ^/(?:sheet|doc|presentation)/inner.html) { set $unsafe 1; } + if ($uri ~ ^/common/onlyoffice/.*/.*\.html) { set $unsafe 1; } # everything except the sandbox domain is a privileged scope, as they might be used to handle keys if ($host != $sandbox_domain) { set $unsafe 0; } @@ -186,7 +186,7 @@ server { # because of bugs in Chromium-based browsers that incorrectly ignore headers that are supposed to enable # the use of some modern APIs that we require when javascript is run in a cross-origin context. # We've applied other sandboxing techniques to mitigate the risk of running WebAssembly in this privileged scope - if ($uri ~ ^\/unsafeiframe\/inner\.html.*$) { set $unsafe 1; } + if ($uri ~ ^/unsafeiframe/inner\.html) { set $unsafe 1; } # privileged contexts allow a few more rights than unprivileged contexts, though limits are still applied if ($unsafe) { @@ -235,7 +235,7 @@ server { # /api/config is loaded once per page load and is used to retrieve # the caching variable which is applied to every other resource # which is loaded during that session. - location ~ ^/api/.*$ { + location ^~ /api/ { proxy_pass http://localhost:3000; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; @@ -249,7 +249,7 @@ server { add_header Cross-Origin-Embedder-Policy require-corp; } - location ~ ^/extensions.js { + location = /extensions.js/ { proxy_pass http://localhost:3000; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; @@ -268,7 +268,7 @@ server { # or with odd unexpected permissions. Serving blobs in this manner also means that it will be possible to # enforce access control for them, though this is not yet implemented. # Access control (via TOTP 2FA) has been added to blocks, so they can be handled with the same directives. - location ~ ^/(blob|block)/.*$ { + location ~ ^/(?:blob|block)/ { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' "${allowed_origins}"; add_header 'Access-Control-Allow-Credentials' true; @@ -293,8 +293,8 @@ server { # The nodejs server has some built-in forwarding rules to prevent # URLs like /pad from resulting in a 404. This simply adds a trailing slash # to a variety of applications. - location ~ ^/(register|login|recovery|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc|form|report|convert|checkup|diagram)$ { - rewrite ^(.*)$ $1/ redirect; + location ~ ^/(?:register|login|recovery|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc|form|report|convert|checkup|diagram)$ { + return 301 https://$host$uri/; } # Finally, serve anything the above exceptions don't govern. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..eba722d94 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: 2024 XWiki CryptPad Team and contributors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +const compatPlugin = require("eslint-plugin-compat"); +const globals = require("globals"); +const js = require("@eslint/js"); +const FlatCompat = require("@eslint/eslintrc").FlatCompat; + +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +module.exports = [{ + ignores: [ + "**/node_modules/", + "www/components/", + "www/bower_components/", + "www/common/onlyoffice/dist", + "www/common/onlyoffice/x2t", + "**/onlyoffice-dist/", + "www/scratch", + "www/accounts", + "www/lib", + "www/accounts", + "www/worker", + "www/todo", + "**/*worker.bundle.js", + "**/_build", + "www/common/hyperscript.js", + "www/pad/wysiwygarea-plugin.js", + "www/pad/mediatag-plugin.js", + "www/pad/mediatag-plugin-dialog.js", + "www/pad/disable-base64.js", + "www/pad/wordcount/", + "www/kanban/jkanban.js", + "www/common/jscolor.js", + "www/common/media-tag-nacl.min.js", + "**/customize/", + "www/debug/chainpad.dist.js", + "www/pad/mathjax/", + "www/code/mermaid*.js", + "www/code/orgmode.js", + ], +}, ...compat.extends("eslint:recommended", "plugin:compat/recommended"), { + plugins: { + compatPlugin, + }, + + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + define: "readonly", + }, + + ecmaVersion: "latest", + sourceType: "commonjs", + }, + + rules: { + indent: ["off", 4], + "linebreak-style": ["off", "unix"], + quotes: ["off", "single"], + semi: ["error", "always"], + "no-irregular-whitespace": ["off"], + "no-self-assign": ["off"], + "no-empty": ["off"], + "no-useless-escape": ["off"], + "no-extra-boolean-cast": ["off"], + "no-prototype-builtins": ["off"], + "no-use-before-define": ["error"], + "no-unused-vars": [ + "error", + { + caughtErrors: "none" + } + ] + }, +}, { + files: ["**/.eslintrc.{js,cjs}"], + + languageOptions: { + globals: { + ...globals.node, + }, + + ecmaVersion: 5, + sourceType: "commonjs", + }, +}]; diff --git a/lib/api.js b/lib/api.js index bccf917f8..df3206b1e 100644 --- a/lib/api.js +++ b/lib/api.js @@ -108,7 +108,7 @@ nThen(function (w) { }; // spawn ws server and attach netflux event handlers - let Server = NetfluxSrv.create(new WebSocketServer({ server: Env.httpServer})) + let Server = Env.Server = NetfluxSrv.create(new WebSocketServer({ server: Env.httpServer})) .on('channelClose', historyKeeper.channelClose) .on('channelMessage', historyKeeper.channelMessage) .on('channelOpen', historyKeeper.channelOpen) diff --git a/lib/eviction.js b/lib/eviction.js index b747ba99f..95f430cdf 100644 --- a/lib/eviction.js +++ b/lib/eviction.js @@ -669,6 +669,7 @@ module.exports = function (Env, cb) { if (item.mtime > inactiveTime) { return void next(); } nThen(function (w) { blobs.size(item.blobId, w(function (err, size) { + if (err && err === 'ENOENT') { return; } // XXX delete the proof if (err) { w.abort(); return void Log.error("EVICT_BLOB_LIST_PROOFS_ERROR", err, next); diff --git a/lib/hk-util.js b/lib/hk-util.js index 61374d7a4..3ccc6129b 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -328,6 +328,7 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, tim // Store the message first, and update the index only once it's stored. // store.messageBin can be async so updating the index first may // result in a wrong cpIndex + Env.plugins?.MONITORING?.increment(`storeMessage`); nThen((waitFor) => { Env.store.messageBin(id, msgBin, waitFor(function (err) { if (err) { @@ -399,6 +400,8 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, tim var msgLength = msgBin.length; index.size += msgLength; + Env.plugins?.MONITORING?.increment('broadcastMessage', (channel.length-1)); + // handle the next element in the queue next(); @@ -529,6 +532,7 @@ const getHistoryAsync = (Env, channelName, lastKnownHash, beforeHash, handler, c const store = Env.store; let offset = -1; + Env.plugins?.MONITORING?.increment(`getHistoryAsync`); nThen((waitFor) => { getHistoryOffset(Env, channelName, lastKnownHash, waitFor((err, os) => { if (err) { @@ -781,6 +785,10 @@ const handleGetHistoryRange = function (Env, Server, seq, userId, parsed) { Env.getOlderHistory(channelName, oldestKnownHash, untilHash, desiredMessages, desiredCheckpoint, function (err, toSend) { if (err && err.code !== 'ENOENT') { Env.Log.error("HK_GET_OLDER_HISTORY", err); + Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, + JSON.stringify(['HISTORY_RANGE_ERROR', txid, err]) + ]); + return; } if (Array.isArray(toSend)) { diff --git a/lib/http-worker.js b/lib/http-worker.js index b93120d74..9cb88ada0 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -35,7 +35,7 @@ const guid = () => { return Util.guid(response._pending); }; -const sendMessage = (msg, cb, opt) => { +const sendMessage = Env.sendMessage = (msg, cb, opt) => { var txid = guid(); var timeout = (opt && opt.timeout) || DEFAULT_QUERY_TIMEOUT; var obj = { @@ -71,6 +71,7 @@ EVENTS.ENV_UPDATE = function (data /*, cb */) { Env = JSON.parse(data); Env.Log = Log; Env.plugins = plugins; + Env.sendMessage = sendMessage; Env.incrementBytesWritten = function () {}; } catch (err) { Log.error('HTTP_WORKER_ENV_UPDATE', Util.serializeError(err)); @@ -91,6 +92,23 @@ EVENTS.FLUSH_CACHE = function (data) { }); }; +Object.keys(plugins || {}).forEach(name => { + let plugin = plugins[name]; + if (!plugin.addHttpEvents) { return; } + try { + let events = plugin.addHttpEvents(Env); + Object.keys(events || {}).forEach(cmd => { + // Uppercase event name? + if (cmd !== cmd.toUpperCase()) { return; } + // Event is a function? + if (typeof(events[cmd]) !== "function") { return; } + // Event doesn't already exists? + if (EVENTS[cmd]) { return; } + EVENTS[cmd] = events[cmd]; + }); + } catch (e) {} +}); + process.on('message', msg => { if (!(msg && msg.txid)) { return; } if (msg.type === 'REPLY') { @@ -799,7 +817,12 @@ nThen(function (w) { })); }).nThen(function () { // TODO inform the parent process that this worker is ready - + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = plugins[name]; + if (!plugin.initialize) { return; } + try { plugin.initialize(Env, "http-worker"); } + catch (e) {} + }); }); process.on('uncaughtException', function (err) { diff --git a/lib/rpc.js b/lib/rpc.js index 571272ab1..c28c5210a 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -34,6 +34,8 @@ var isUnauthenticateMessage = function (msg) { var handleUnauthenticatedMessage = function (Env, msg, respond, Server, netfluxId) { Env.Log.silly('LOG_RPC', msg[0]); + Env.plugins?.MONITORING?.increment(`rpc_${msg[0]}`); + var method = UNAUTHENTICATED_CALLS[msg[0]]; method(Env, msg[1], function (err, value) { if (err) { @@ -170,6 +172,8 @@ var rpc = function (Env, Server, userId, data, respond) { var command = msg[1]; + Env.plugins?.MONITORING?.increment(`rpc_${command}`); + if (command === 'UPLOAD') { // UPLOAD is a special case that skips signature validation // intentional fallthrough behaviour diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 398260d61..64376236f 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -17,11 +17,18 @@ const Tasks = require("../storage/tasks"); const Nacl = require('tweetnacl/nacl-fast'); const Eviction = require("../eviction"); const CPCrypto = require('../crypto'); +const plugins = require("../plugin-manager"); const Env = { Log: {}, }; +const Monitoring = plugins && plugins.MONITORING; +const monitoringIncrement = key => { + if (!Monitoring || !Monitoring.increment) { return; } + Monitoring.increment(key); +}; + // support the usual log API but pass it to the main process Logger.levels.forEach(function (level) { Env.Log[level] = function (label, info) { @@ -33,6 +40,8 @@ Logger.levels.forEach(function (level) { }; }); +const HISTORY_SIZE_LIMIT = 1024 * 1024 * 1024; // XXX 1GB + var DETAIL = 1000; var round = function (n) { return Math.floor(n * DETAIL) / DETAIL; @@ -57,6 +66,17 @@ const init = function (config, _cb) { Env.archiveRetentionTime = config.archiveRetentionTime; Env.accountRetentionTime = config.accountRetentionTime; + Env.sendMessage = data => { + process.send(data); + }; + + Object.keys(plugins || {}).forEach(name => { + let plugin = plugins[name]; + if (!plugin.initialize) { return; } + try { plugin.initialize(Env, "db-worker"); } + catch (e) {} + }); + nThen(function (w) { Store.create(config, w(function (err, _store) { if (err) { @@ -277,6 +297,8 @@ const computeIndex = function (data, cb) { const channelName = data.channel; const CB = Util.once(cb); + monitoringIncrement('computeIndex'); + var start = 0; nThen(function (w) { store.getOffset(channelName, w(function (err, obj) { @@ -298,6 +320,7 @@ const computeIndex = function (data, cb) { }); } w.abort(); + monitoringIncrement('computeIndexFromOffset'); CB(err, index); })); }).nThen(function (w) { @@ -306,6 +329,7 @@ const computeIndex = function (data, cb) { store.clearOffset(channelName, w()); }).nThen(function () { // now get the history as though it were the first time + monitoringIncrement('computeIndexFromStart'); computeIndexFromOffset(channelName, 0, CB); }); }; @@ -313,6 +337,7 @@ const computeIndex = function (data, cb) { const computeMetadata = function (data, cb) { const ref = {}; const lineHandler = Meta.createLineHandler(ref, Env.Log.error); + monitoringIncrement('computeMetadata'); return void store.readChannelMetadata(data.channel, lineHandler, function (err) { if (err) { // stream errors? @@ -322,6 +347,31 @@ const computeMetadata = function (data, cb) { }); }; +const _getFileSize = function (channel, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); + if (!Core.isValidId(channel)) { return void cb('INVALID_CHAN'); } + if (channel.length === HK.STANDARD_CHANNEL_LENGTH || + channel.length === HK.ADMIN_CHANNEL_LENGTH) { + return void store.getChannelSize(channel, function (e, size) { + if (e) { + if (e.code === 'ENOENT') { return void cb(void 0, 0); } + return void cb(e.code); + } + cb(void 0, size); + }); + } + + // 'channel' refers to a file, so you need another API + blobStore.size(channel, function (e, size) { + if (typeof(size) === 'undefined') { return void cb(e); } + cb(void 0, size); + }); +}; + +const getFileSize = function (data, cb) { + _getFileSize(data.channel, cb); +}; + /* getOlderHistory * allows clients to query for all messages until a known hash is read * stores all messages in history as they are read @@ -339,6 +389,7 @@ const getOlderHistory = function (data, cb) { const desiredMessages = data.desiredMessages; const desiredCheckpoint = data.desiredCheckpoint; + var next = () => { var messages = []; var found = false; store.getMessages(channelName, function (msgStr) { @@ -384,6 +435,15 @@ const getOlderHistory = function (data, cb) { } cb(err, toSend); }); + }; + + _getFileSize(channelName, function (err, size) { + if (err) { return void cb(err); } + if (size > HISTORY_SIZE_LIMIT) { + return void cb('HISTORY_TOO_LARGE'); + } + next(); + }); }; const getPinState = function (data, cb) { @@ -393,6 +453,7 @@ const getPinState = function (data, cb) { var lineHandler = Pins.createLineHandler(ref, Env.Log.error); // if channels aren't in memory. load them from disk + monitoringIncrement('getPin'); pinStore.readMessagesBin(safeKey, 0, (msgObj, readMore) => { lineHandler(msgObj.buff.toString('utf8')); readMore(); @@ -401,31 +462,6 @@ const getPinState = function (data, cb) { }); }; -const _getFileSize = function (channel, _cb) { - var cb = Util.once(Util.mkAsync(_cb)); - if (!Core.isValidId(channel)) { return void cb('INVALID_CHAN'); } - if (channel.length === HK.STANDARD_CHANNEL_LENGTH || - channel.length === HK.ADMIN_CHANNEL_LENGTH) { - return void store.getChannelSize(channel, function (e, size) { - if (e) { - if (e.code === 'ENOENT') { return void cb(void 0, 0); } - return void cb(e.code); - } - cb(void 0, size); - }); - } - - // 'channel' refers to a file, so you need another API - blobStore.size(channel, function (e, size) { - if (typeof(size) === 'undefined') { return void cb(e); } - cb(void 0, size); - }); -}; - -const getFileSize = function (data, cb) { - _getFileSize(data.channel, cb); -}; - const _iterateFiles = function (channels, handler, cb) { if (!Array.isArray(channels)) { return cb('INVALID_LIST'); } var L = channels.length; @@ -449,6 +485,7 @@ const _iterateFiles = function (channels, handler, cb) { const getTotalSize = function (data, cb) { var bytes = 0; + monitoringIncrement('getTotalSize'); _iterateFiles(data.channels, function (channel, next) { _getFileSize(channel, function (err, size) { if (!err) { bytes += size; } @@ -494,6 +531,7 @@ const getHashOffset = function (data, cb) { const lastKnownHash = data.hash; if (typeof(lastKnownHash) !== 'string') { return void cb("INVALID_HASH"); } + monitoringIncrement('getHashOffset'); var offset = -1; store.readMessagesBin(channelName, 0, (msgObj, readMore, abort) => { // tryParse return a parsed message or undefined @@ -592,6 +630,8 @@ const completeUpload = function (data, cb) { var arg = data.arg; var size = data.size; + monitoringIncrement('uploadedBlob'); + var method; var label; if (owned) { @@ -671,6 +711,7 @@ const COMMANDS = { }; COMMANDS.INLINE = function (data, cb) { + monitoringIncrement('inlineValidation'); var signedMsg; try { signedMsg = Nacl.util.decodeBase64(data.msg); @@ -695,6 +736,7 @@ COMMANDS.INLINE = function (data, cb) { const checkDetachedSignature = function (signedMsg, signature, publicKey) { if (!(signedMsg && publicKey)) { return false; } + monitoringIncrement('detachedValidation'); var signedBuffer; var pubBuffer; @@ -758,13 +800,28 @@ COMMANDS.HASH_CHANNEL_LIST = function (data, cb) { }; COMMANDS.VALIDATE_ANCESTOR_PROOF = function (data, cb) { + monitoringIncrement('validateAncestorProof'); Block.validateAncestorProof(Env, data && data.proof, cb); }; COMMANDS.VALIDATE_LOGIN_BLOCK = function (data, cb) { + monitoringIncrement('validateLoginBlock'); Block.validateLoginBlock(Env, data.publicKey, data.signature, data.block, cb); }; +Object.keys(plugins || {}).forEach(name => { + let plugin = plugins[name]; + if (!plugin.addWorkerCommands) { return; } + try { + let events = plugin.addWorkerCommands(Env); + Object.keys(events || {}).forEach(cmd => { + if (typeof(events[cmd]) !== "function") { return; } + if (COMMANDS[cmd]) { return; } + COMMANDS[cmd] = events[cmd]; + }); + } catch (e) {} +}); + process.on('message', function (data) { if (!data || !data.txid || !data.pid) { return void process.send({ @@ -773,6 +830,13 @@ process.on('message', function (data) { }); } + const command = COMMANDS[data.command]; + + // Command broadcasted to all workers: no callback expected + if (data.type === 'broadcast') { + return void command(data); + } + const cb = function (err, value) { process.send({ error: Util.serializeError(err), @@ -790,7 +854,6 @@ process.on('message', function (data) { }); } - const command = COMMANDS[data.command]; if (typeof(command) !== 'function') { return void cb("E_BAD_COMMAND"); } diff --git a/lib/workers/index.js b/lib/workers/index.js index 55487c848..5bdbd5d7a 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -152,9 +152,34 @@ Workers.initialize = function (Env, config, _cb) { // default to timing out affter 180s if no explicit timeout is passed var timeout = typeof(opt.timeout) !== 'undefined'? opt.timeout: DEFAULT_QUERY_TIMEOUT; response.expect(txid, cb, timeout); + + delete msg._cb; + delete msg._opt; state.worker.send(msg); + + // Add original callback to message data in case we need + // to resend the command. setTimeout to avoid interfering + // with worker.send + setTimeout(function () { + msg._cb = _cb; + msg._opt = opt; + }); }; + const pluginsResponses = {}; + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.addWorkerResponses) { return; } + try { + let res = plugin.addWorkerResponses(Env); + Object.keys(res || {}).forEach(key => { + if (typeof(res[key]) !== "function") { return; } + if (pluginsResponses[key]) { return; } + pluginsResponses[key] = res[key]; + }); + } catch (e) {} + }); + var handleResponse = function (state, res) { if (!res) { return; } // handle log messages before checking if it was addressed to your PID @@ -162,6 +187,17 @@ Workers.initialize = function (Env, config, _cb) { if (res.log) { return void handleLog(res.log, res.label, res.info); } + + // handle plugins + if (res.plugin) { + Object.keys(pluginsResponses).some(key => { + if (res.type !== key) { return; } + pluginsResponses[key](res.data); + return true; + }); + return; + } + // but don't bother handling things addressed to other processes // since it's basically guaranteed not to work if (res.pid !== PID) { @@ -226,7 +262,15 @@ Workers.initialize = function (Env, config, _cb) { handleResponse(state, res); }); + let pid = worker.pid; var substituteWorker = Util.once(function () { + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.onWorkerClosed) { return; } + try { plugin.onWorkerClosed("db-worker", pid); } + catch (e) {} + }); + Env.Log.info("SUBSTITUTE_DB_WORKER", ''); var idx = workers.indexOf(state); if (idx !== -1) { @@ -237,26 +281,36 @@ Workers.initialize = function (Env, config, _cb) { const cb = response.expectation(txid); if (typeof(cb) !== 'function') { return; } const task = state.tasks[txid]; - if (!(task && task.msg)) { return; } + if (!task) { return; } response.clear(txid); - Log.info('DB_WORKER_RESEND', task.msg); - sendCommand(task.msg, cb); + Log.info('DB_WORKER_RESEND', task); + sendCommand(task, task._cb || cb, task._opt); }); var w = fork(DB_PATH); - initWorker(w, function (err, state) { + initWorker(w, function (err) { if (err) { throw new Error(err); } - workers.push(state); }); }); - worker.on('exit', substituteWorker); - worker.on('close', substituteWorker); + worker.on('exit', function () { + substituteWorker(); + Env.Log.error("DB_WORKER_EXIT", { + pid: state.pid, + }); + }); + worker.on('close', function () { + substituteWorker(); + Env.Log.error("DB_WORKER_CLOSE", { + pid: state.pid, + }); + }); worker.on('error', function (err) { substituteWorker(); Env.Log.error("DB_WORKER_ERROR", { + pid: state.pid, error: err, }); }); @@ -282,6 +336,18 @@ Workers.initialize = function (Env, config, _cb) { })); }); }).nThen(function () { + Env.broadcastWorkerCommand = (data) => { + workers.forEach(state => { + state.worker.send({ + type: 'broadcast', + pid: PID, + command: data.command, + txid: data.txid + }); + }); + return workers; + }; + Env.computeIndex = function (Env, channel, cb) { Env.store.getWeakLock(channel, function (next) { sendCommand({ diff --git a/package-lock.json b/package-lock.json index faa58a38e..4c6655198 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cryptpad", - "version": "2024.9.0", + "version": "2024.12.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cryptpad", - "version": "2024.9.0", + "version": "2024.12.0", "license": "AGPL-3.0+", "dependencies": { "@mcrowe/minibloom": "^0.2.0", @@ -19,23 +19,23 @@ "chainpad-crypto": "^0.2.5", "chainpad-listmap": "^1.1.0", "chainpad-netflux": "^1.2.0", - "chainpad-server": "^5.2.2", + "chainpad-server": "^5.2.4", "ckeditor": "npm:ckeditor4@~4.22.1", "codemirror": "^5.19.0", "components-font-awesome": "^4.6.3", - "cookie-parser": "^1.4.6", + "cookie-parser": "^1.4.7", "croppie": "^2.5.0", "dragula": "3.7.2", "drawio": "github:cryptpad/drawio-npm#npm-21.8.2+5", - "express": "~4.21.0", + "express": "~4.21.2", "file-saver": "1.3.1", "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", "html2canvas": "^1.4.0", - "http-proxy-middleware": "^3.0.2", + "http-proxy-middleware": "^3.0.3", "hyper-json": "~1.4.0", "jquery": "3.6.0", - "json.sortify": "~2.1.0", + "json.sortify": "github:cryptpad/JSON.sortify", "jsonwebtoken": "^9.0.0", "jszip": "3.10.1", "localforage": "^1.5.2", @@ -64,8 +64,8 @@ "x2js": "^3.4.4" }, "devDependencies": { - "eslint": "^8.57.0", - "eslint-plugin-compat": "^4.2.0", + "eslint": "^9.16.0", + "eslint-plugin-compat": "^6.0.1", "stylelint": "^16.9.0", "stylelint-config-standard-less": "^3.0.1" }, @@ -303,24 +303,70 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@eslint/core": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -328,25 +374,19 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -357,106 +397,76 @@ } } }, - "node_modules/@eslint/eslintrc/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/@eslint/eslintrc/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, "dependencies": { - "ms": "2.1.2" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", @@ -471,11 +481,18 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@mcrowe/minibloom": { "version": "0.2.0", @@ -483,9 +500,9 @@ "integrity": "sha512-hce9MTbEkVIutibAkXAQddXCU9gMP/3OfcRaNo2V0v485iEzBRlniJG0ZTKumL8RbUA/fhpIGvrURiEZc+Crrg==" }, "node_modules/@mdn/browser-compat-data": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.12.tgz", - "integrity": "sha512-/AHFqy6OeNHS2NNZGFVRgQh+pnW8iAoV3d1fiO9b2PuQ3HzZpC30MrMrHtq1uOGy1/zcK4uPQEyI31jkM0NNAA==", + "version": "5.6.21", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.6.21.tgz", + "integrity": "sha512-yFGyNC6llnRbCELh1vH5mhrdSkQCrBs+wOyFjcYa3E9K3qzz6aDKnUSlDfWx+7pMeVr/iSKIdl1P60g2Jxs5sg==", "dev": true }, "node_modules/@node-saml/node-saml": { @@ -590,6 +607,12 @@ "@types/ms": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, "node_modules/@types/express": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", @@ -625,6 +648,12 @@ "@types/node": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", @@ -705,12 +734,6 @@ "@types/node": "*" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/@xmldom/xmldom": { "version": "0.8.10", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", @@ -1133,6 +1156,12 @@ "node": ">=0.10.0" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", @@ -1294,9 +1323,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -1313,10 +1342,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -1357,9 +1386,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001660", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", - "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", + "version": "1.0.30001686", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001686.tgz", + "integrity": "sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==", "dev": true, "funding": [ { @@ -1405,6 +1434,14 @@ "json.sortify": "~2.1.0" } }, + "node_modules/chainpad-listmap/node_modules/json.sortify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json.sortify/-/json.sortify-2.1.0.tgz", + "integrity": "sha512-otSldRQcu9PaQJJDeB1qGZUIoL7C4nxZunUVHieWPUMJvvVxIUhsMQUhR+r4OUZBwA1McnbS7sqDf5dYHzJsbw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/chainpad-netflux": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/chainpad-netflux/-/chainpad-netflux-1.2.0.tgz", @@ -1414,24 +1451,9 @@ } }, "node_modules/chainpad-server": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.2.tgz", - "integrity": "sha512-fUCffhnd8PlO92A6cYH5lSIiiI6bpJymP0yC3O2KI+4NPyxFK7I2iuadMrC7RzK3eAI1w72Y1nbMN8rQImppoQ==", - "dependencies": { - "nthen": "0.1.8", - "pull-stream": "^3.6.9", - "stream-to-pull-stream": "^1.7.3", - "ws": "^3.3.1" - } - }, - "node_modules/chainpad/node_modules/json.sortify": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/json.sortify/-/json.sortify-2.2.2.tgz", - "integrity": "sha512-wwFLdDffs747s5cqLA3htIKp9wdID2rWNofJKxwDjFo+rqqt5Vg7SnYOh7mc7MW6Iw43rrOFhr6MKytOtNceSA==", - "engines": { - "node": ">=4.0.0", - "npm": "~1.0.20" - } + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.4.tgz", + "integrity": "sha512-f4eErhcmIE67vfN9Dkfh0hX/IZDWERmfjdcfPEesXIHKu441jA84H0autvTAFsMTSPimlil7eeGnx4GLBVrR5Q==" }, "node_modules/chalk": { "version": "4.1.2", @@ -1570,19 +1592,19 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", "dependencies": { - "cookie": "0.4.1", + "cookie": "0.7.2", "cookie-signature": "1.0.6" }, "engines": { @@ -1590,9 +1612,9 @@ } }, "node_modules/cookie-parser/node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "engines": { "node": ">= 0.6" } @@ -1621,9 +1643,9 @@ "integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ==" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -1774,18 +1796,6 @@ "defined": "^1.0.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dragula": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/dragula/-/dragula-3.7.2.tgz", @@ -1813,9 +1823,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.687", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.687.tgz", - "integrity": "sha512-Ic85cOuXSP6h7KM0AIJ2hpJ98Bo4hyTUjc4yjMbkvD+8yTxEhfK9+8exT2KKYsSjnCn2tGsKVSZwE7ZgTORQCw==", + "version": "1.5.68", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.68.tgz", + "integrity": "sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==", "dev": true }, "node_modules/emoji-regex": { @@ -1878,9 +1888,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "engines": { "node": ">=6" @@ -1904,92 +1914,109 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.16.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.5", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-compat": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.2.0.tgz", - "integrity": "sha512-RDKSYD0maWy5r7zb5cWQS+uSPc26mgOzdORJ8hxILmWM7S/Ncwky7BcAtXVY5iRbKjBdHsWU8Yg7hfoZjtkv7w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.1.tgz", + "integrity": "sha512-0MeIEuoy8kWkOhW38kK8hU4vkb6l/VvyjpuYDymYOXmUY9NvTgyErF16lYuX+HPS5hkmym7lfA+XpYZiWYWmYA==", "dev": true, "dependencies": { - "@mdn/browser-compat-data": "^5.3.13", + "@mdn/browser-compat-data": "^5.5.35", "ast-metadata-inferer": "^0.8.0", - "browserslist": "^4.21.10", - "caniuse-lite": "^1.0.30001524", + "browserslist": "^4.23.1", + "caniuse-lite": "^1.0.30001639", "find-up": "^5.0.0", + "globals": "^15.7.0", "lodash.memoize": "^4.1.2", - "semver": "^7.5.4" + "semver": "^7.6.2" }, "engines": { - "node": ">=14.x" + "node": ">=18.x" }, "peerDependencies": { - "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-compat/node_modules/globals": { + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", + "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2007,21 +2034,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/eslint/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2039,6 +2051,18 @@ } } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2051,57 +2075,33 @@ "node": ">=10.13.0" } }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/espree/node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2119,6 +2119,18 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", @@ -2187,16 +2199,16 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -2210,7 +2222,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -2225,6 +2237,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/encodeurl": { @@ -2288,15 +2304,15 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/file-saver": { @@ -2357,17 +2373,16 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -2443,12 +2458,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2492,26 +2501,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -2572,15 +2561,12 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2635,12 +2621,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2747,9 +2727,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.2.tgz", - "integrity": "sha512-fBLFpmvDzlxdckwZRjM0wWtwDZ4KBtQ8NFqhrFKoEtK4myzuiumBuNTxD+F4cVbXfOZljIbrynmvByofDzT7Ag==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz", + "integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==", "dependencies": { "@types/http-proxy": "^1.17.15", "debug": "^4.3.6", @@ -2821,6 +2801,22 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2830,16 +2826,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/info-symbol": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/info-symbol/-/info-symbol-0.1.0.tgz", @@ -2955,15 +2941,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -3021,6 +2998,18 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -3046,11 +3035,12 @@ "dev": true }, "node_modules/json.sortify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json.sortify/-/json.sortify-2.1.0.tgz", - "integrity": "sha512-otSldRQcu9PaQJJDeB1qGZUIoL7C4nxZunUVHieWPUMJvvVxIUhsMQUhR+r4OUZBwA1McnbS7sqDf5dYHzJsbw==", + "version": "2.2.2", + "resolved": "git+ssh://git@github.com/cryptpad/JSON.sortify.git#0a96f91c3f3b127c3040bbc2d3eb6ae803cb2dfd", + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0", + "npm": ">=1.0.20" } }, "node_modules/jsonfile": { @@ -3574,9 +3564,9 @@ "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true, "funding": [ { @@ -3611,9 +3601,9 @@ "integrity": "sha512-8oQOyEyh0MCnifNIfyvkNXpEELlVRzDleRivRgsDGh+5ZDG109axweVZ0RIOIpkQmTZk4/xVsBk/oLXpMSWEOw==" }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "node_modules/normalize-path": { @@ -3731,15 +3721,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/open-sans-fontface": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/open-sans-fontface/-/open-sans-fontface-1.4.0.tgz", @@ -3858,15 +3839,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -3877,9 +3849,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/picocolors": { "version": "1.1.0", @@ -4398,6 +4370,15 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", "integrity": "sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==" }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -4408,21 +4389,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4486,12 +4452,9 @@ "integrity": "sha512-BtT7+xPLdoeXsh6wOblaq6sRy/AsffFXgcwBNGtQJXeNgm9UD3HM3nWEmAERjdCNfE6jWglAtRbAPZ7rc2WtsQ==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -4793,6 +4756,18 @@ "node": ">=0.10.0" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stylelint": { "version": "16.9.0", "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.9.0.tgz", @@ -4967,12 +4942,6 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/stylelint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/stylelint/node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -5104,31 +5073,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stylelint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/stylelint/node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/stylelint/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5147,18 +5091,6 @@ "node": ">=0.10.0" } }, - "node_modules/stylelint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/stylelint/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5405,12 +5337,6 @@ "utrie": "^1.0.2" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, "node_modules/thirty-two": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", @@ -5514,18 +5440,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -5568,9 +5482,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -5587,8 +5501,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -5703,12 +5617,6 @@ "node": ">=0.4.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", diff --git a/package.json b/package.json index c7cc84e99..9ddd23123 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "a collaborative office suite that is end-to-end encrypted and open-source", - "version": "2024.9.0", + "version": "2024.12.0", "license": "AGPL-3.0+", "repository": { "type": "git", @@ -22,23 +22,23 @@ "chainpad-crypto": "^0.2.5", "chainpad-listmap": "^1.1.0", "chainpad-netflux": "^1.2.0", - "chainpad-server": "^5.2.2", + "chainpad-server": "^5.2.4", "ckeditor": "npm:ckeditor4@~4.22.1", "codemirror": "^5.19.0", "components-font-awesome": "^4.6.3", - "cookie-parser": "^1.4.6", + "cookie-parser": "^1.4.7", "croppie": "^2.5.0", "dragula": "3.7.2", "drawio": "github:cryptpad/drawio-npm#npm-21.8.2+5", - "express": "~4.21.0", + "express": "~4.21.2", "file-saver": "1.3.1", "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", "html2canvas": "^1.4.0", - "http-proxy-middleware": "^3.0.2", + "http-proxy-middleware": "^3.0.3", "hyper-json": "~1.4.0", "jquery": "3.6.0", - "json.sortify": "~2.1.0", + "json.sortify": "github:cryptpad/JSON.sortify", "jsonwebtoken": "^9.0.0", "jszip": "3.10.1", "localforage": "^1.5.2", @@ -67,8 +67,8 @@ "x2js": "^3.4.4" }, "devDependencies": { - "eslint": "^8.57.0", - "eslint-plugin-compat": "^4.2.0", + "eslint": "^9.16.0", + "eslint-plugin-compat": "^6.0.1", "stylelint": "^16.9.0", "stylelint-config-standard-less": "^3.0.1" }, diff --git a/readme.md b/readme.md index f24355c3d..a37e767ab 100644 --- a/readme.md +++ b/readme.md @@ -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 don’t 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 designed to facilitate collaboration by synchronizing changes to documents in real time. Since all the user data is encrypted, in the event of a breach, attackers have no way of accessing the stored content. Furthermore, if the administrators do not modify the code, they and the service also cannot access any information about the users' content. ![Drive screenshot](screenshot.png "preview of the CryptDrive") @@ -20,7 +20,7 @@ Our [developer guide](https://docs.cryptpad.org/en/dev_guide/setup.html) provide ## For production -Configuring CryptPad for production requires a little more work, but the process is described in our [admin installation guide](https://docs.cryptpad.org/en/admin_guide/installation.html). From there you can find more information about customization and maintenance. +Configuring CryptPad for production requires additional steps. Refer to our [admin installation guide](https://docs.cryptpad.org/en/admin_guide/installation.html) for production-related instructions, customization, and maintenance details. ## Current version diff --git a/server.js b/server.js index f240b1cd9..407f10f43 100644 --- a/server.js +++ b/server.js @@ -25,6 +25,13 @@ var app = Express(); } }()); +Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.initialize) { return; } + try { plugin.initialize(Env, "main"); } + catch (e) {} +}); + var COMMANDS = {}; COMMANDS.LOG = function (msg, cb) { @@ -49,6 +56,25 @@ COMMANDS.GET_PROFILING_DATA = function (msg, cb) { cb(void 0, Env.bytesWritten); }; +Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.addMainCommands) { return; } + try { + let commands = plugin.addMainCommands(Env); + Object.keys(commands || {}).forEach(cmd => { + // Uppercase command name? + if (cmd !== cmd.toUpperCase()) { return; } + // Command is a function? + if (typeof(commands[cmd]) !== "function") { return; } + // Command doesn't already exists? + if (COMMANDS[cmd]) { return; } + + COMMANDS[cmd] = commands[cmd]; + }); + } catch (e) {} +}); + + nThen(function (w) { require("./lib/log").create(config, w(function (_log) { Env.Log = _log; @@ -93,6 +119,7 @@ nThen(function (w) { var launchWorker = (online) => { var worker = Cluster.fork(workerState); + var pid = worker.process.pid; worker.on('online', () => { online(); }); @@ -122,6 +149,13 @@ nThen(function (w) { }); worker.on('exit', (code, signal) => { + Object.keys(Env.plugins || {}).forEach(name => { + let plugin = Env.plugins[name]; + if (!plugin.onWorkerClosed) { return; } + try { plugin.onWorkerClosed("http-worker", pid); } + catch (e) {} + }); + if (!signal && code === 0) { return; } // relaunch http workers if they crash Env.Log.error('HTTP_WORKER_EXIT', { @@ -147,10 +181,11 @@ nThen(function (w) { }); }; - var broadcast = (command, data/*, cb*/) => { + var broadcast = Env.broadcast = (command, data/*, cb*/) => { for (const worker of Object.values(Cluster.workers)) { sendCommand(worker, command, data /*, cb */); } + return Object.values(Cluster.workers); }; var throttledEnvChange = Util.throttle(function () { diff --git a/www/admin/inner.js b/www/admin/inner.js index a7b587266..9153436e5 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -172,7 +172,7 @@ define([ const blocks = sidebar.blocks; // EXTENSION_POINT:ADMIN_CATEGORY - common.getExtensions('ADMIN_CATEGORY').forEach(ext => { + common.getExtensionsSync('ADMIN_CATEGORY').forEach(ext => { if (!ext || !ext.id || !ext.name || !ext.content) { return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext); } @@ -187,6 +187,7 @@ define([ }; }); + const flushCache = (cb) => { cb = cb || function () {}; sFrameChan.query('Q_ADMIN_RPC', { @@ -967,12 +968,7 @@ define([ }); }; - let btn = blocks.activeButton('primary', '', - Messages.admin_colorChange, (done) => { - let color = $input.val(); - setColor(color, done); - }); - + let $input = $(); let onColorPicked = () => { require(['/lib/less.min.js'], (Less) => { let color = $input.val(); @@ -994,7 +990,14 @@ define([ $preview.find('.cp-admin-color-preview-light a').attr('style', `color: ${color} !important`); }); }; - let $input = $(input).on('change', onColorPicked).addClass('cp-admin-color-picker'); + $input = $(input).on('change', onColorPicked).addClass('cp-admin-color-picker'); + + let btn = blocks.activeButton('primary', '', + Messages.admin_colorChange, (done) => { + let color = $input.val(); + setColor(color, done); + }); + UI.confirmButton($remove, { classes: 'btn-danger', @@ -3184,6 +3187,7 @@ define([ labelEnd, ], blocks.nav([button])); + let send = function () {}; var refresh = getApi(function (Broadcast) { $active.empty(); var removeButton = blocks.button('danger', '', Messages.admin_maintenanceCancel); @@ -3245,7 +3249,7 @@ define([ }; }; - var send = function (data) { + send = function (data) { disable($button); sFrameChan.query('Q_ADMIN_RPC', { cmd: 'ADMIN_DECREE', @@ -3924,16 +3928,15 @@ define([ // EXTENSION_POINT:ADMIN_ITEM let utils = { - h, Util, Hash + h, Util, Hash, UIElements }; - common.getExtensions('ADMIN_ITEM').forEach(ext => { + common.getExtensionsSync('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); @@ -3946,12 +3949,8 @@ define([ }); }); - - sidebar.makeLeftside(categories); }; - - var updateStatus = APP.updateStatus = function (cb) { sFrameChan.query('Q_ADMIN_RPC', { cmd: 'INSTANCE_STATUS', diff --git a/www/calendar/app-calendar.less b/www/calendar/app-calendar.less index 2b5db6ca5..65424d200 100644 --- a/www/calendar/app-calendar.less +++ b/www/calendar/app-calendar.less @@ -599,6 +599,18 @@ margin-top: 30px; } } + @media screen and (max-width: @browser_media-medium-screen) { + .cp-calendar-entries { + display: none; + } + + .cp-calendar-entries.visible { + display: block; + } + } + .cp-calendar-entries { + margin-bottom: 10px; + } .cp-calendar-entry { display: flex; align-items: center; @@ -628,6 +640,7 @@ } &.cp-ghost { padding: 0; + margin-top: 1rem; button { .tools_unselectable(); cursor: pointer; diff --git a/www/calendar/inner.js b/www/calendar/inner.js index 267b69958..0994dbb6a 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -775,7 +775,7 @@ define([ var data = APP.calendars[id]; var edit; if (data.loading) { - edit = h('i.fa.fa-spinner.fa-spin'); + edit = h('i.fa.fa-spinner.fa-spin', {'aria-hidden': 'true'}); } else { edit = makeEditDropdown(id, teamId); } @@ -796,8 +796,8 @@ define([ h('i.cp-calendar-inactive.fa.fa-calendar-o') ]), h('span.cp-calendar-title', md.title), - data.restricted ? h('i.fa.fa-ban', {title: Messages.fm_restricted}) : - (isReadOnly(id, teamId) ? h('i.fa.fa-eye', {title: Messages.readonly}) : undefined), + data.restricted ? h('i.fa.fa-ban', {title: Messages.fm_restricted, 'aria-hidden': 'true'}) : + (isReadOnly(id, teamId) ? h('i.fa.fa-eye', {title: Messages.readonly, 'aria-hidden': 'true'}) : undefined), edit ]); var $calendar = $(calendar).click(function () { @@ -820,10 +820,14 @@ define([ if (APP.$calendars) { APP.$calendars.append(calendar); } return calendar; }; + var makeLeftside = function (calendar, $container) { // Show calendars var calendars = h('div.cp-calendar-list'); var $calendars = APP.$calendars = $(calendars).appendTo($container); + var isMobileView = window.innerWidth <= 600; + var visible = !isMobileView; // Initialize 'visible' state: true for large screens, false for mobile + onCalendarsUpdate.reg(function () { $calendars.empty(); var privateData = metadataMgr.getPrivateData(); @@ -831,7 +835,7 @@ define([ var LOOKUP = {}; return Object.keys(APP.calendars || {}).filter(function (id) { var cal = APP.calendars[id] || {}; - var teams = (cal.teams || []).map(function (tId) { return Number(tId); }); + var teams = (cal.teams || []).map(function (tId) { return Number(tId); }); return teams.indexOf(typeof(teamId) !== "undefined" ? Number(teamId) : 1) !== -1; }).map(function (k) { // nearly constant-time pre-sort @@ -872,26 +876,33 @@ define([ } return; } + var myCalendars = filter(1); + var totalCalendars = myCalendars.length + Object.keys(privateData.teams).reduce((sum, teamId) => { + return sum + filter(teamId).length; + }, 0); + + var $contentContainer = $(h('div.cp-calendar-content')).appendTo($calendars); + if (myCalendars.length) { var user = metadataMgr.getUserData(); var avatar = h('span.cp-avatar'); var uid = user.uid; var name = user.name || Messages.anonymous; common.displayAvatar($(avatar), user.avatar, name, function(){}, uid); - APP.$calendars.append(h('div.cp-calendar-team', [ + $contentContainer.append(h('div.cp-calendar-team', [ avatar, h('span.cp-name', {title: name}, name) ])); + myCalendars.forEach((id) => { + var calendarEntry = makeCalendarEntry(id, 1); + $contentContainer.append(calendarEntry); + }); } - myCalendars.forEach(function (id) { - makeCalendarEntry(id, 1); - }); - - // Add new button - var $newContainer = $(h('div.cp-calendar-entry.cp-ghost')).appendTo($calendars); + // Add the new calendar button + var $newContainer = $(h('div.cp-calendar-entry.cp-ghost')).appendTo($contentContainer); var newButton = h('button', [ - h('i.fa.fa-calendar-plus-o'), + h('i.fa.fa-calendar-plus-o', {'aria-hidden': 'true'}), h('span', Messages.calendar_new), h('span') ]); @@ -905,19 +916,61 @@ define([ var team = privateData.teams[teamId]; var avatar = h('span.cp-avatar'); common.displayAvatar($(avatar), team.avatar, team.displayName || team.name); - APP.$calendars.append(h('div.cp-calendar-team', [ + var $teamContainer = h('div.cp-calendar-team', [ avatar, - h('span.cp-name', {title: team.name}, team.name) - ])); - calendars.forEach(function (id) { - makeCalendarEntry(id, teamId); + h('span.cp-name', {title: team.name}, team.name), + h('span') + ]); + $contentContainer.append($teamContainer); + calendars.forEach((id) => { + var calendarEntry = makeCalendarEntry(id, teamId); + $contentContainer.append(calendarEntry); }); }); + if(isMobileView) { + // If initial number of calendars or current number > 2, + // hide the calendars list and display a "show" button + if (APP.numberCalendars > 2 || totalCalendars > 2) { + var $showContainer = $(h('div.cp-calendar-entry.cp-ghost')).appendTo($calendars); + var iconClass = visible ? 'fa-eye-slash' : 'fa-eye'; + var buttonText = visible ? Messages.calendar_hide : Messages.calendar_show; + var showCalendarsBtn = h('button', [ + h('i.fa.' + iconClass, {'aria-hidden': "true"}), + h('span.cp-calendar-title', buttonText), + h('span') + ]); + + $(showCalendarsBtn).click(() => { + visible = !visible; + $contentContainer.toggle(visible); + iconClass = visible ? 'fa-eye-slash' : 'fa-eye'; + buttonText = visible ? Messages.calendar_hide : Messages.calendar_show; + $(showCalendarsBtn).find('i').attr('class', 'fa ' + iconClass).attr('aria-hidden', "true"); + $(showCalendarsBtn).find('span').first().text(visible ? Messages.calendar_hide : Messages.calendar_show); + }).appendTo($showContainer); + } + else {visible = true;} + } + + $contentContainer.toggle(visible); + $(window).resize(function () { + var newIsMobileView = window.innerWidth <= 600; + if (!newIsMobileView) { + visible = true; + $contentContainer.show(); + } + if (newIsMobileView !== isMobileView) { + isMobileView = newIsMobileView; + if (isMobileView) { + visible = false; + $contentContainer.hide(); + } + onCalendarsUpdate.fire(); + } + }); }); onCalendarsUpdate.fire(); - }; - var _updateRecurring = function () { var cal = APP.calendar; if (!cal) { return; } @@ -1275,17 +1328,15 @@ ICS ==> create a new event with the same UID and a RECURRENCE-ID field (with a v store.put('calendarView', mode, function () {}); }); APP.toolbar.$bottomR.append($block); - // New event button var newEventBtn = h('button.cp-calendar-newevent', [ - h('i.fa.fa-plus'), + h('i.fa.fa-plus', {'aria-hidden': 'true'}), h('span', Messages.calendar_newEvent) ]); $(newEventBtn).click(function (e) { e.preventDefault(); cal.openCreationPopup({isAllDay:false}); }).appendTo(APP.toolbar.$bottomL); - // Change page var goLeft = h('button.fa.fa-chevron-left',{'aria-label': Messages.goLeft}); var goRight = h('button.fa.fa-chevron-right', {'aria-label': Messages.goRight}); @@ -2152,7 +2203,7 @@ APP.recurrenceRule = { // Customize creation/update popup var onCalendarPopup = function (el) { var $el = $(el); - $el.find('.tui-full-calendar-confirm').addClass('btn btn-primary').prepend(h('i.fa.fa-floppy-o')); + $el.find('.tui-full-calendar-confirm').addClass('btn btn-primary').prepend(h('i.fa.fa-floppy-o', {'aria-hidden': 'true'})); $el.find('input').attr('autocomplete', 'off'); $el.find('.tui-full-calendar-dropdown-button').addClass('btn btn-secondary'); $el.find('.tui-full-calendar-popup-close').addClass('btn btn-cancel fa fa-times cp-calendar-close').empty(); @@ -2234,7 +2285,7 @@ APP.recurrenceRule = { $el.find('.tui-full-calendar-content').removeClass('tui-full-calendar-content'); var delButton = h('button.btn.btn-danger', [ - h('i.fa.fa-trash'), + h('i.fa.fa-trash', {'aria-hidden': 'true'}), h('span', Messages.kanban_delete) ]); var $del = $el.find('.tui-full-calendar-popup-delete').hide(); @@ -2267,7 +2318,7 @@ APP.recurrenceRule = { // This is a recurring event, add button to stop recurrence now var $b = $(h('button.btn.btn-default', [ - h('i.fa.fa-times'), + h('i.fa.fa-times', {'aria-hidden': 'true'}), h('span', Messages.calendar_rec_stop) ])).insertBefore($section); UI.confirmButton($b[0], { classes: 'btn-default' }, function () { @@ -2340,7 +2391,9 @@ APP.recurrenceRule = { }); var store = window.cryptpadStore; APP.module.execCommand('SUBSCRIBE', null, function (obj) { - if (obj.empty && !privateData.calendarHash) { + let empty = !obj.length; + APP.numberCalendars = obj.length; + if (empty && !privateData.calendarHash) { if (!privateData.loggedIn) { return void UI.errorLoadingScreen(Messages.mustLogin, false, function () { common.setLoginRedirect('login'); diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 662db522c..07a7c2f80 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -132,7 +132,7 @@ define(function() { // en: "Hello world", // fr: "Bonjour le monde", // de: "Hallo Welt", - // "pt-br": "Olá Mundo"< + // "pt-br": "Olá Mundo" }; /* Cryptpad apps use a common API to display notifications to users diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index ae0dea302..378ccdb98 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2525,6 +2525,7 @@ define([ window.setTimeout(function () { modal.show(); $modal.focus(); + next(); }); }; @@ -2770,7 +2771,11 @@ define([ ]); // Password - var password = h('div.cp-creation-password', [ + let text; + if (type === 'form') { + text = h('div.cp-creation-password-warning.alert.alert-info.dismissable', h('span.cp-inline-alert-text', Messages.form_passwordWarning)); + } + var password = h('div.cp-creation-password', [ UI.createCheckbox('cp-creation-password', Messages.properties_addPassword, false), h('span.cp-creation-password-picker.cp-creation-slider', [ UI.passwordInput({id: 'cp-creation-password-val'}) @@ -2808,6 +2813,7 @@ define([ expire, password, ]), + text, templates, createDiv ])).appendTo($creation); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index e2d6a3746..d4bc03a93 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -928,13 +928,15 @@ define([ delete meta.cursor; if (meta.type === "form") { - // Keep anonymous and makeAnonymous values from templates + // Keep anonymous, makeAnonymous and submit message values from templates var anonymous = parsed.answers.anonymous || false; var makeAnonymous = parsed.answers.makeAnonymous || false; + var msg = parsed.answers.msg || undefined; delete parsed.answers; parsed.answers = { anonymous: anonymous, - makeAnonymous: makeAnonymous + makeAnonymous: makeAnonymous, + msg: msg }; } } @@ -2713,7 +2715,7 @@ define([ window.addEventListener('unload', function () { postMsg('CLOSE'); }); - // eslint-disable-next-line no-constant-condition + // eslint-disable-next-line no-constant-condition,no-constant-binary-expression } else if (false && !noWorker && !noSharedWorker && 'serviceWorker' in navigator) { var initializing = true; var stopWaiting = waitFor2(); // Call this function when we're ready diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 135b0eae0..d7577c78b 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -314,20 +314,29 @@ define([ }; APP.selectedFiles = []; - + var findElementId = function ($element) { + var isTrashed = $element.data("path")[0] === TRASH; + let elementId; + if (isTrashed) { + elementId = $element.data("path").join(','); + } else { + elementId = $element.data("path").slice(-1)[0]; + } + return elementId; + }; var isElementSelected = function ($element) { - var elementId = $element.data("path").slice(-1)[0]; + var elementId = findElementId($element); return APP.selectedFiles.indexOf(elementId) !== -1; }; var selectElement = function ($element) { - var elementId = $element.data("path").slice(-1)[0]; + var elementId = findElementId($element); if (APP.selectedFiles.indexOf(elementId) === -1) { APP.selectedFiles.push(elementId); } $element.addClass("cp-app-drive-element-selected"); }; var unselectElement = function ($element) { - var elementId = $element.data("path").slice(-1)[0]; + var elementId = findElementId($element); var index = APP.selectedFiles.indexOf(elementId); if (index !== -1) { APP.selectedFiles.splice(index, 1); @@ -990,6 +999,9 @@ define([ // Arrow keys to modify the selection var onWindowKeydown = function (e) { if (!$content.is(':visible')) { return; } + if ($('.cp-modal').is(':visible')) { + return; + } var $searchBar = $tree.find('#cp-app-drive-tree-search-input'); if (document.activeElement && document.activeElement.nodeName === 'INPUT') { return; } if ($searchBar.is(':focus') && $searchBar.val()) { return; } @@ -1459,7 +1471,6 @@ define([ } }); if (paths.length > 1) { - hide.push('restore'); hide.push('properties', 'access'); hide.push('rename'); hide.push('openparent'); @@ -2968,6 +2979,16 @@ define([ }); UI.openCustomModal(m); }; + + var triggerEnter = function (selector, $context) { + $context.find(selector).on('keypress', function (event) { + if (event.which === 13) { // enter + event.preventDefault(); + $(this).trigger('click'); // the keypress event triggers the click event + } + }); + }; + var addNewPadHandlers = function ($block, isInRoot) { // Handlers if (isInRoot) { @@ -2983,56 +3004,51 @@ define([ refresh(); }; $block.find('a.cp-app-drive-new-folder, li.cp-app-drive-new-folder') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - manager.addFolder(currentPath, null, onCreated); - } + .on('click', function (event) { + event.preventDefault(); + manager.addFolder(currentPath, null, onCreated); }); + triggerEnter('a.cp-app-drive-new-folder, li.cp-app-drive-new-folder', $block); if (!APP.disableSF && !manager.isInSharedFolder(currentPath)) { $block.find('a.cp-app-drive-new-shared-folder, li.cp-app-drive-new-shared-folder') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - addSharedFolderModal(function (obj) { - if (!obj) { return; } - manager.addSharedFolder(currentPath, obj, refresh); - }); - } + .on('click', function (event) { + event.preventDefault(); + addSharedFolderModal(function (obj) { + if (!obj) { return; } + manager.addSharedFolder(currentPath, obj, refresh); + }); }); + triggerEnter('a.cp-app-drive-new-shared-folder, li.cp-app-drive-new-shared-folder', $block); } $block.find('a.cp-app-drive-new-fileupload, li.cp-app-drive-new-fileupload') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - showUploadFilesModal(); - } + .on('click', function (event) { + event.preventDefault(); + showUploadFilesModal(); }); + triggerEnter('a.cp-app-drive-new-fileupload, li.cp-app-drive-new-fileupload', $block); $block.find('a.cp-app-drive-new-folderupload, li.cp-app-drive-new-folderupload') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - showUploadFolderModal(); - } + .on('click', function (event) { + event.preventDefault(); + showUploadFolderModal(); }); + triggerEnter('a.cp-app-drive-new-folderupload, li.cp-app-drive-new-folderupload', $block); $block.find('a.cp-app-drive-new-link, li.cp-app-drive-new-link') - .on('click keypress', function (event) { - if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { - event.preventDefault(); - showLinkModal(); - } + .on('click', function (event) { + event.preventDefault(); + showLinkModal(); }); + triggerEnter('a.cp-app-drive-new-link, li.cp-app-drive-new-link', $block); } $block.find('a.cp-app-drive-new-doc, li.cp-app-drive-new-doc') - .on('click auxclick keypress', function (event) { - if (event.type === 'click' || event.type === 'auxclick' || (event.type === 'keypress' && event.which === 13)) - { + .on('click auxclick', function (event) { + if (event.type === 'click' || event.type === 'auxclick') { event.preventDefault(); var type = $(this).attr('data-type') || 'pad'; var path = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath; openIn(type, path, APP.team); } }); + triggerEnter('a.cp-app-drive-new-doc, li.cp-app-drive-new-doc', $block); }; var getNewPadOptions = function (isInRoot) { var options = []; @@ -5181,24 +5197,45 @@ define([ return void deletePaths(paths); } else if ($this.hasClass("cp-app-drive-context-restore")) { - if (paths.length !== 1) { return; } - var restorePath = paths[0].path; - var restoreName = paths[0].path[paths[0].path.length - 1]; - if (restorePath.length === 4) { - var rEl = manager.find(restorePath); - if (manager.isFile(rEl)) { - restoreName = manager.getTitle(rEl); - } else if (manager.isSharedFolder(rEl)) { - var sfData = manager.getSharedFolderData(rEl); - restoreName = sfData.title || sfData.lastTitle || Messages.fm_deletedFolder; - } else { - restoreName = restorePath[1]; + let getRestoreProperties = (path) => { + let restorePath = path; + let restoreName = path.at(-1); + if (restorePath.length === 4) { + let rEl = manager.find(restorePath); + if (manager.isFile(rEl)) { + restoreName = manager.getTitle(rEl); + } else if (manager.isSharedFolder(rEl)) { + let sfData = manager.getSharedFolderData(rEl); + restoreName = sfData.title || sfData.lastTitle || Messages.fm_deletedFolder; + } else { + restoreName = restorePath[1]; + } } + return [restorePath, restoreName]; + }; + let restoreNumber = paths.length; + if (restoreNumber === 0) { return; } + if (restoreNumber === 1) { // single file restoration + let [restorePath, restoreName] = getRestoreProperties(paths[0].path); + UI.confirm(Messages._getKey("fm_restoreDialog", [restoreName]), res => { + if (!res) { return; } + manager.restore(restorePath, refresh); + }); + } else { // multiple files restoration + UI.confirm(Messages._getKey("fm_restoreMultipleDialog", [restoreNumber]), res => { + if (!res) { return; } + nThen(waitFor => { + paths.forEach(path => { + if (!path) { // We met an error + console.error("Error while restoring files: no path"); + return; + } + let restorePath = getRestoreProperties(path.path)[0]; + setTimeout(manager.restore(restorePath, waitFor()), 10); + }); + }).nThen(refresh); + }); } - UI.confirm(Messages._getKey("fm_restoreDialog", [restoreName]), function(res) { - if (!res) { return; } - manager.restore(restorePath, refresh); - }); } else if ($this.hasClass("cp-app-drive-context-openparent")) { if (paths.length !== 1) { return; } diff --git a/www/common/extensions.js b/www/common/extensions.js index 1a0a7d040..dd7e9b97f 100644 --- a/www/common/extensions.js +++ b/www/common/extensions.js @@ -10,9 +10,51 @@ define([ ext.getExtensions = id => { let e = ext[id]; if (!Array.isArray(e)) { e = []; } - return e; + return e.map(_ext => { + return new Promise((resolve, reject) => { + // If there's no check function, resolve immediately + if (typeof _ext.check !== "function") { + return resolve(_ext); + } + const checkResult = _ext.check(); + + checkResult + .then((extPassed) => { + if (!extPassed) { + // Reject if the check didn't pass + undefined (resolve()); + } else { + // Extension passed the check + resolve(_ext); + } + }) + .catch((error) => { + reject(error); + }); + }); + }); }; + ext.getExtensionsSync = id => { + let e = ext[id]; + if (!Array.isArray(e)) { e = []; } + + return e.map(_ext => { + if (typeof _ext.check !== "function") { + return _ext; + } + + const extPassed = _ext.check(); + + if (extPassed) { + return _ext; + } else { + return null; + } + }).filter(ext => ext !== null); + }; + + if (!Array.isArray(Extensions) || !Extensions.length) { return ext; } let all = Extensions.slice(); diff --git a/www/common/inner/access.js b/www/common/inner/access.js index 9159aac93..389311642 100644 --- a/www/common/inner/access.js +++ b/www/common/inner/access.js @@ -1108,7 +1108,7 @@ define([ var owned = Modal.isOwned(Env, data); // Request edit access - if (common.isLoggedIn() && data.roHref && !owned && !opts.calendar && priv.app !== 'form') { + if (common.isLoggedIn() && data.roHref && !owned && !opts.calendar && priv.app !== 'form' && !data.href) { var requestButton = h('button.btn.btn-secondary.no-margin.cp-access-margin-right', Messages.requestEdit_button); var requestBlock = h('p', requestButton); diff --git a/www/common/inner/common-modal.js b/www/common/inner/common-modal.js index a7a3de0c0..4fe7d6bef 100644 --- a/www/common/inner/common-modal.js +++ b/www/common/inner/common-modal.js @@ -49,7 +49,13 @@ define([ // Access modal and the pad is not stored: get the hashes from outer var hashes = priv.hashes || {}; // For calendars, individual href is passed via opts - data.href = ((priv.app === 'calendar') && opts.href) || Hash.hashToHref(hashes.editHash || hashes.fileHash, priv.app); + if (priv.app === 'calendar') { + data.href = opts.href; + } else if (hashes.editHash || hashes.fileHash) { + data.href = Hash.hashToHref(hashes.editHash || hashes.fileHash, priv.app); + } else { + data.href = undefined; + } if (hashes.viewHash) { data.roHref = Hash.hashToHref(hashes.viewHash, priv.app); } diff --git a/www/common/make-backup.js b/www/common/make-backup.js index 4e1d2b205..75bd19b78 100644 --- a/www/common/make-backup.js +++ b/www/common/make-backup.js @@ -169,10 +169,17 @@ define([ data: fData }); } - - var href = (fData.href && fData.href.indexOf('#') !== -1) ? fData.href : fData.roHref; - var parsed = Hash.parsePadUrl(href); - if (['pad', 'file'].indexOf(parsed.hashData.type) === -1) { return; } + var href; + var parsed; + if (!fData.channel) { + href = fData.href; + parsed = {}; + parsed['hashData'] = {type: 'link'}; + } else { + href = (fData.href && fData.href.indexOf('#') !== -1) ? fData.href : fData.roHref; + parsed = Hash.parsePadUrl(href); + } + if (['pad', 'file', 'link'].indexOf(parsed.hashData.type) === -1) { return; } // waitFor is used to make sure all the pads and files are process before downloading the zip. var w = ctx.waitFor(); @@ -220,7 +227,7 @@ define([ var opts = { password: fData.password }; - var rawName = fData.filename || fData.title || 'File'; + var rawName = fData.filename || fData.title || fData.name || 'File'; console.log(rawName); // Pads (pad,code,slide,kanban,poll,...) @@ -276,8 +283,21 @@ define([ } }, 50); }; + var todoLink = function () { + var opts = { + binary: true, + }; + var fileName = getUnique(sanitize(rawName), '.txt', existingNames); + existingNames.push(fileName.toLowerCase()); + var content = new Blob([fData.href, '\n'], { type: "text/plain;charset=utf-8" }); + zip.file(fileName, content, opts); + console.log('DONE ---- ' + fileName); + setTimeout(done, 1000); + }; if (parsed.hashData.type === 'file') { return void todoFile(); + } else if (parsed.hashData.type === 'link') { + return void todoLink(); } todoPad(); }); @@ -286,7 +306,7 @@ define([ }; // Add folders and their content recursively in the zip - var makeFolder = function (ctx, root, zip, fd) { + var makeFolder = function (ctx, root, zip, fd, sd) { if (typeof (root) !== "object") { return; } var existingNames = []; Object.keys(root).forEach(function (k) { @@ -294,19 +314,20 @@ define([ if (typeof el === "object" && el.metadata !== true) { // if folder var fName = getUnique(sanitize(k), '', existingNames); existingNames.push(fName.toLowerCase()); - return void makeFolder(ctx, el, zip.folder(fName), fd); + return void makeFolder(ctx, el, zip.folder(fName), fd, sd); } if (ctx.data.sharedFolders[el]) { // if shared folder + let staticData = ctx.sf[el].static; var sfData = ctx.sf[el].metadata; var sfName = getUnique(sanitize((sfData && sfData.title) || 'Folder'), '', existingNames); existingNames.push(sfName.toLowerCase()); - return void makeFolder(ctx, ctx.sf[el].root, zip.folder(sfName), ctx.sf[el].filesData); + return void makeFolder(ctx, ctx.sf[el].root, zip.folder(sfName), ctx.sf[el].filesData, staticData); } - var fData = fd[el]; + var fData = fd[el] || (sd && sd[el]); if (fData) { addFile(ctx, zip, fData, existingNames); return; - } + } }); }; @@ -330,11 +351,13 @@ define([ sframeChan: sframeChan }; var filesData = data.sharedFolderId && ctx.sf[data.sharedFolderId] ? ctx.sf[data.sharedFolderId].filesData : ctx.data.filesData; + var links = ctx.sf[data.sharedFolderId] && ctx.sf[data.sharedFolderId].static ? ctx.data.static && ctx.sf[data.sharedFolderId].static : ctx.data.static; + progress('reading', -1); // Msg.settings_export_reading nThen(function (waitFor) { ctx.waitFor = waitFor; var zipRoot = ctx.zip.folder(data.name || Messages.fm_rootName); - makeFolder(ctx, ctx.folder || ctx.data.root, zipRoot, filesData); + makeFolder(ctx, ctx.folder || ctx.data.root, zipRoot, filesData, links); progress('download', {}); // Msg.settings_export_download }).nThen(function () { console.log(ctx.zip); diff --git a/www/common/onlyoffice/inner.js b/www/common/onlyoffice/inner.js index 4e878005b..64a7af21b 100644 --- a/www/common/onlyoffice/inner.js +++ b/www/common/onlyoffice/inner.js @@ -68,6 +68,8 @@ define([ var NEW_VERSION = 7; // version of the .bin, patches and ChainPad formats var PENDING_TIMEOUT = 30000; var CURRENT_VERSION = X2T.CURRENT_VERSION; + const HISTORY_KEEPER_INDEX_USER = 1; + const READ_ONLY_INDEX_USER = 2; //var READONLY_REFRESH_TO = 15000; @@ -181,17 +183,17 @@ 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; + const getNextUserIndex = function () { + let nextUserIndex; + do { + nextUserIndex = Util.createRandomInteger(); + } while (nextUserIndex === HISTORY_KEEPER_INDEX_USER || nextUserIndex === READ_ONLY_INDEX_USER); + return nextUserIndex; }; var setMyId = function () { - // Remove ids for users that have left the channel - deleteOffline(); - var ids = content.ids; + deleteOffline(); // Remove ids for users that have left the channel + const ids = content.ids; if (!myOOId) { myOOId = Util.createRandomInteger(); // f: function used in .some(f) but defined outside of the while @@ -202,13 +204,21 @@ define([ myOOId = Util.createRandomInteger(); } } - var myId = getId(); + + const myId = getId(); + const myIndex = getNextUserIndex(); + ids[myId] = { ooid: myOOId, - index: getNewUserIndex(), + index: myIndex, netflux: metadataMgr.getNetfluxId() }; - oldIds = JSON.parse(JSON.stringify(ids)); + + if (!myUniqueOOId) { + myUniqueOOId = String(myOOId) + myIndex; + } + + oldIds = structuredClone(ids); APP.onLocal(); }; @@ -924,56 +934,42 @@ define([ const getMyOOIndex = function() { const user = findUserByOOId(myOOId); - return user - ? user.index - : content.ids.length; // Assign an unused id to read-only users + return user ? user.index : READ_ONLY_INDEX_USER; }; - var getParticipants = function () { - var users = metadataMgr.getMetadata().users; - var i = 1; - var p = Object.keys(content.ids || {}).map(function (id) { - var nId = id.slice(0,32); - if (!users[nId]) { return; } - var ooId = content.ids[id].ooid; - var idx = content.ids[id].index; - if (!ooId || ooId === myOOId) { return; } - if (idx >= i) { i = idx + 1; } - return { - id: String(ooId) + idx, - idOriginal: String(ooId), - username: (users[nId] || {}).name || Messages.anonymous, - indexUser: idx, - connectionId: content.ids[id].netflux || Hash.createChannelId(), - isCloseCoAuthoring:false, - view: false - }; - }); + const getParticipants = function () { + const users = metadataMgr.getMetadata().users; // Add an history keeper user to show that we're never alone var hkId = Util.createRandomInteger(); - p.push({ - id: hkId, + const historyKeeper = [{ + id: String(hkId), idOriginal: String(hkId), username: "History", - indexUser: i, + indexUser: HISTORY_KEEPER_INDEX_USER, connectionId: Hash.createChannelId(), isCloseCoAuthoring:false, view: false + }]; + + const realParticipants = Object.entries(content.ids).map(([id, user]) => { + const nId = id.slice(0,32); + const username = (users[nId] || {}).name || Messages.anonymous; + return { + id: String(user.ooid) + user.index, + idOriginal: String(user.ooid), + username, + indexUser: user.index, + connectionId: user.netflux || Hash.createChannelId(), + isCloseCoAuthoring: false, + view: false + }; }); - const myOOIndex = getMyOOIndex(); - if (!myUniqueOOId) { myUniqueOOId = String(myOOId) + myOOIndex; } - p.push({ - id: String(myOOId), - idOriginal: String(myOOId), - username: metadataMgr.getUserData().name || Messages.anonymous, - indexUser: myOOIndex, - connectionId: metadataMgr.getNetfluxId() || Hash.createChannelId(), - isCloseCoAuthoring:false, - view: false - }); + + const participants = historyKeeper.concat(realParticipants); + return { - index: myOOIndex, - list: p.filter(Boolean) + index: getMyOOIndex(), + list: participants, }; }; @@ -3428,7 +3424,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null if (content.ids) { handleNewIds(oldIds, content.ids); - oldIds = JSON.parse(JSON.stringify(content.ids)); + oldIds = structuredClone(content.ids); } if (content.locks) { handleNewLocks(oldLocks, content.locks); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 6e37a97c2..8439af38f 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2356,6 +2356,12 @@ define([ if (completed) { return; } var parsed = parse(msg); if (parsed[1] !== txid) { console.log('bad txid'); return; } + if (parsed[0] === 'HISTORY_RANGE_ERROR') { + cb({ + error: parsed[2] + }); + return; + } if (parsed[0] === 'HISTORY_RANGE_END') { cb({ messages: msgs, diff --git a/www/common/outer/calendar.js b/www/common/outer/calendar.js index 21bff21ff..4d9d88aea 100644 --- a/www/common/outer/calendar.js +++ b/www/common/outer/calendar.js @@ -599,7 +599,7 @@ define([ ctx.clients.push(cId); } cb({ - empty: !Object.keys(ctx.calendars).length + length: Object.keys(ctx.calendars).length }); Object.keys(ctx.calendars).forEach(function (channel) { var c = ctx.calendars[channel] || {}; diff --git a/www/common/outer/messenger.js b/www/common/outer/messenger.js index 1aec3d51d..ac3c756cd 100644 --- a/www/common/outer/messenger.js +++ b/www/common/outer/messenger.js @@ -382,7 +382,8 @@ define([ } // History cleared while we were offline // ==> we asked for an invalid last known hash - if (parsed.error && parsed.error === "EINVAL") { + if (parsed.error && (parsed.error === "EINVAL" + || parsed.error === "EUNKNOWN")) { setChannelHead(ctx, parsed.channel, '', function () { getChannelMessagesSince(ctx, channel, {}, {}); }); diff --git a/www/common/outer/support.js b/www/common/outer/support.js index 1e18c6442..912fa5d23 100644 --- a/www/common/outer/support.js +++ b/www/common/outer/support.js @@ -531,6 +531,11 @@ define([ if (last.sender) { entry.lastAdmin = !last.sender.blockLocation; } + if (last.close) { + doc.tickets.closed[data.channel] = entry; + delete doc.tickets.active[data.channel]; + notifyClient(ctx, true, 'UPDATE_TICKET', data.channel); + } /* let senderKey = last.sender && last.sender.edPublic; if (senderKey) { @@ -589,7 +594,9 @@ define([ doc.tickets.closed[data.channel] = entry; delete doc.tickets.active[data.channel]; delete doc.tickets.pending[data.channel]; - cb({closed: true}); + Realtime.whenRealtimeSyncs(ctx.adminDoc.realtime, function () { + cb({closed: true}); + }); }); }); }; diff --git a/www/common/outer/userObject.js b/www/common/outer/userObject.js index 72ae77681..272b9a391 100644 --- a/www/common/outer/userObject.js +++ b/www/common/outer/userObject.js @@ -698,7 +698,7 @@ define([ } if (exp.isFolder(obj.element)) { fixRoot(obj.element); } if (typeof obj.element === "number") { - var data = files[FILES_DATA][obj.element]; + var data = files[FILES_DATA][obj.element] || files[STATIC_DATA][obj.element]; if (!data) { debug("An element in TRASH doesn't have associated data", obj.element, el); toClean.push(idx); diff --git a/www/common/sframe-common-history.js b/www/common/sframe-common-history.js index 943e3f225..e711d5265 100644 --- a/www/common/sframe-common-history.js +++ b/www/common/sframe-common-history.js @@ -212,6 +212,9 @@ define([ sharedFolder: config.sharedFolder }, function (err, data) { if (err) { return void console.error(err); } + if (data && data.error) { + return void cb(data.error); + } if (!Array.isArray(data.messages)) { return void console.error('Not an array!'); } lastKnownHash = data.lastKnownHash; isComplete = data.isFull; @@ -288,6 +291,14 @@ define([ UI.spinner($hist).get().show(); + let closeAll = () => { + History.state = false; + $hist.hide(); + $bottom.show(); + $cke.show(); + $(window).trigger('resize'); + }; + var update = function (newRt) { realtime = newRt; if (!realtime) { return []; } @@ -567,11 +578,7 @@ define([ var onKeyDown, onKeyUp; var closeUI = function () { - History.state = false; - $hist.hide(); - $bottom.show(); - $cke.show(); - $(window).trigger('resize'); + closeAll(); $(window).off('keydown', onKeyDown); $(window).off('keyup', onKeyUp); }; @@ -681,7 +688,12 @@ define([ loadMoreHistory(config, common, function (err, newRt, isFull) { History.readOnly = common.getMetadataMgr().getPrivateData().readOnly; History.loading = false; - if (err) { throw new Error(err); } + if (err) { + console.error(err); + UI.warn(`${Messages.error}: ${err}`); + closeAll(); + return; + } update(newRt); display(); if (isFull) { diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index 857b46bbe..bf05bdd18 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -105,7 +105,9 @@ define([ h('p', data.content.msg.type + ' - ' +formatData(data)) ]) ]); - + if ($(notif).find('.cp-avatar').length) { + $(notif).addClass('cp-notification-avatar'); + } if (typeof(data.content.getFormatText) === "function") { $(notif).find('.cp-notification-content p').html(data.content.getFormatText()); if (data.content.autorefresh) { diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index b4031d155..8138aec2d 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -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 @@ -1322,6 +1321,9 @@ define([ toHash: data.toHash, lastKnownHash: data.lastKnownHash }, function (data) { + if (data && data.error) { + return void cb(data); + } cb({ isFull: data.isFull, messages: data.messages.map(function (obj) { diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index c297b5273..8310deb27 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -778,6 +778,7 @@ define([ }; funcs.getExtensions = Ext.getExtensions; + funcs.getExtensionsSync = Ext.getExtensionsSync; funcs.mailbox = {}; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 2b0d2f648..c56b2809d 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -1198,7 +1198,9 @@ MessengerUI, Messages, Pages, PadTypes) { $('body').find('.cp-dropdown-content li').first().focus(); return $(el).find('.cp-notification-dismiss').click(); } - $(el).find('.cp-notification-content').click(); + setTimeout(function () { + $(el).find('.cp-notification-content').click(); + }, 0); }); refresh(); }, @@ -1416,7 +1418,7 @@ MessengerUI, Messages, Pages, PadTypes) { tb['pad'] = function () { toolbar.$file.show(); - addElement([ + toolbar.addElement([ 'chat', 'collapse', 'userlist', 'title', 'useradmin', 'spinner', diff --git a/www/common/translations/messages.bg.json b/www/common/translations/messages.bg.json index 43804428d..56ac012e0 100644 --- a/www/common/translations/messages.bg.json +++ b/www/common/translations/messages.bg.json @@ -467,5 +467,137 @@ "upload_modal_title": "Опции за качване на файлове", "upload_tooLarge": "Този файл надвишава максималния разрешен размер на качване за вашия акаунт.", "upload_serverError": "Грешка в сървъра: файлът ви не може да бъде качен в момента.", - "upload_success": "Вашият файл ({0}) бе успешно качен и е добавен към устройството ви." + "upload_success": "Вашият файл ({0}) бе успешно качен и е добавен към устройството ви.", + "todo_markAsCompleteTitle": "Маркирайте тази задача като завършена", + "todo_markAsIncompleteTitle": "Маркирайте тази задача като незавършена", + "upload_tooLargeBrief": "Файлът надвишава ограничението от {0}MB за това устройство", + "upload_choose": "Избиране на файл", + "upload_pending": "Изчакване", + "upload_cancelled": "Отменено", + "upload_size": "Размер", + "upload_mustLogin": "Трябва да сте влезли, за да качвате файлове", + "upload_up": "Качване", + "download_mt_button": "Изтегляне", + "download_dl": "Изтегляне", + "download_step1": "Изтегля се", + "download_step2": "Декриптиране", + "todo_title": "Crypt Todo", + "todo_removeTaskTitle": "Премахнете тази задача от вашия списък със задачи", + "pad_base64": "Този документ съдържа изображения, съхранени по неефективен начин. Тези изображения значително ще увеличат размера на документа във вашия CryptDrive и ще направят зареждането му по-бавно. Можете да промените тези файлове в нов формат, който ще се съхранява отделно във вашия CryptDrive. Искате ли да промените тези изображения сега?", + "mdToolbar_button": "Показване или скриване на лентата с инструменти Markdown", + "mdToolbar_defaultText": "Вашият текст тук", + "mdToolbar_help": "Помощ", + "mdToolbar_tutorial": "https://www.markdowntutorial.com/", + "mdToolbar_bold": "Удебелен", + "mdToolbar_italic": "Курсив", + "mdToolbar_strikethrough": "Зачертано", + "mdToolbar_heading": "Заглавие", + "mdToolbar_nlist": "Подреден списък", + "mdToolbar_list": "Неподреден списък", + "mdToolbar_check": "Списък със задачи", + "mdToolbar_code": "Код", + "home_host": "Това е отделен екземпляр от общността на CryptPad.", + "about": "Относно", + "privacy": "Политика за поверителност", + "contact": "Контакт", + "terms": "Условия за ползване", + "features": "Характеристики", + "features_title": "Характеристики", + "features_anon": "Гост", + "features_registered": "Регистриран", + "features_premium": "Премиум", + "features_f_core": "Общи характеристики", + "features_f_file0": "Отваряне на документи", + "mdToolbar_quote": "Цитат", + "features_f_apps": "Достъп до всички приложения", + "features_f_core_note": "Редактиране, импортиране и експортиране, история, потребителски списък, чат", + "mdToolbar_toc": "Съдържание", + "mdToolbar_link": "Връзка", + "main_catch_phrase": "Пакет за сътрудничество
криптиран от край до край и с отворен код", + "features_f_file0_note": "Преглеждане и изтегляне на документи, споделени от другите потребители", + "features_f_cryptdrive0": "Ограничен достъп до CryptDrive", + "features_f_cryptdrive0_note": "Възможност за съхраняване на последно използваните документи във вашия браузър, за да можете да ги отворите по-късно", + "features_f_storage0": "Ограничено време за съхранение", + "features_f_storage0_note": "Документите се изтриват след {0} дни неактивност", + "features_f_anon": "Всички потребителски функции за гости", + "features_f_anon_note": "С допълнителна функционалност", + "features_f_cryptdrive1": "Пълна функционалност на CryptDrive", + "features_f_cryptdrive1_note": "Папки, споделени папки, шаблони, тагове", + "features_f_devices": "Вашите документи във всичките ви устройства", + "features_f_devices_note": "Достъп до вашия CryptDrive отвсякъде чрез акаунта ви", + "features_f_social": "Социални характеристики", + "features_f_social_note": "Добавете контакти за сигурно сътрудничество, създайте профил, прецизни контроли за достъп", + "features_f_file1": "Качване и споделяне на файлове", + "features_f_file1_note": "Съхранявайте файлове във вашия CryptDrive: изображения, PDF файлове, видеоклипове и др. Споделете ги с вашите контакти или ги вградете във вашите документи. (до {0}MB)", + "features_f_storage1": "Лично хранилище ({0})", + "features_f_storage1_note": "Документите, съхранявани във вашия CryptDrive, не се изтриват при неактивност", + "features_f_register": "Безплатно регистриране", + "features_f_reg": "Всички регистрирани потребителски функции", + "features_f_reg_note": "С допълнителни предимства", + "features_f_storage2": "Допълнително място за съхранение", + "features_f_storage2_note": "От 5 GB на 50 GB в зависимост от плана, увеличен лимит от {0} MB за качване на файлове", + "features_f_support": "По-бърза поддръжка", + "features_f_support_note": "Приоритетен отговор от административния екип чрез имейл и вградена билетна система", + "features_f_supporter": "Поверителност при поддръжка", + "features_f_supporter_note": "Помогнете на CryptPad да стане финансово устойчив и покажете, че софтуерът за подобряване на поверителността, доброволно финансиран от потребителите, трябва да бъде норма", + "four04_pageNotFound": "Не успяхме да намерим страницата, която търсите.", + "help_genericMore": "Научете повече за това как CryptPad може да работи за вас, като прочетете нашата Документация", + "feedback_about": "Ако четете това, вероятно сте били любопитни защо CryptPad търси уеб страници, когато извършвате определени действия.", + "creation_owned1": "Притежаван документ може да бъде унищожен, когато собственикът поиска. Унищожаването на притежаван документ го прави недостъпен чрез CryptDrives за другите потребители.", + "feedback_privacy": "Грижим се за вашата поверителност и в същото време искаме CryptPad да бъде много лесен за използване. Използваме този файл, за да разберем кои функции на потребителския интерфейс имат значение за нашите потребители, като го изискваме заедно с параметър, указващ кое действие е предприето.", + "creation_newPadModalDescription": "Кликнете върху приложението, за да създадете нов документ. Можете също да натиснете Tab, за да изберете приложението, и да натиснете Enter, за да потвърдите.", + "features_f_subscribe": "Абониране", + "features_f_subscribe_note": "За абониране е необходим акаунт", + "header_logoTitle": "Към вашия CryptDrive", + "header_homeTitle": "Към началната страница на CryptPad", + "edit": "редактиране", + "view": "преглед", + "feedback_optout": "Ако искате да се откажете, посетете страницата си с потребителски настройки, където ще намерите отметка, за да активирате или деактивирате обратната връзка с потребителя.", + "creation_404": "Този документ вече не съществува. Използвайте следната форма, за да създадете нов документ.", + "creation_owned": "Собственост на документа", + "creation_expire": "Изтичащ документ", + "creation_expireFalse": "Неограничен", + "creation_expireHours": "Час(ове)", + "creation_expireDays": "Ден(дни)", + "creation_expireMonths": "Месец(и)", + "creation_password": "Парола\n", + "creation_noTemplate": "Празен документ", + "creation_newTemplate": "Нов шаблон", + "creation_create": "Създаване", + "creation_owners": "Собственици", + "creation_noOwner": "Без собственик", + "creation_expiration": "Дата на унищожаване", + "creation_passwordValue": "Парола", + "password_info": "Документът, който се опитвате да отворите, вече не съществува или е защитен с нова парола. Въведете правилната парола за достъп до съдържанието.", + "properties_changePasswordButton": "Изпращане", + "sharedFolders_forget": "Този документ се съхранява само в споделена папка, не можете да го преместите в кошчето. Можете да използвате своя CryptDrive, ако искате да го изтриете.", + "share_linkEmbed": "Режим на вграждане (скриване на лентата с инструментите и потребителския списък)", + "share_mediatagCopy": "Копиране на медийния маркер в клипборда", + "sharedFolders_share": "Споделете тази връзка с други регистрирани потребители, за да им дадете достъп до споделената папка. След като отворят тази връзка, споделената папка ще бъде добавена към техния CryptDrive.", + "convertFolderToSF_SFChildren": "Тази папка не може да бъде преобразувана в споделена папка, защото вече съдържа споделени папки. Преместете тези споделени папки другаде, за да продължите.", + "password_error": "Документът не е намерен
Тази грешка може да бъде причинена от две причини: или паролата е невалидна, или документът е унищожен.", + "password_placeholder": "Въведете паролата тук...", + "password_submit": "Изпращане", + "properties_addPassword": "Добавяне на парола", + "properties_changePassword": "Промяна на паролата", + "properties_confirmNew": "Сигурен ли си? Добавянето на парола ще промени адреса на този документ и ще премахне неговата история. Потребителите без паролата ще загубят достъпа до този документ", + "properties_confirmChange": "Сигурен ли си? Промяната на паролата ще премахне нейната история. Потребителите без новата парола ще загубят достъпа до този документ", + "properties_passwordSame": "Новите пароли трябва да се различават от текущата.", + "properties_passwordError": "Възникна грешка при опит за промяна на паролата. Моля, опитайте отново.", + "properties_passwordWarning": "Паролата беше променена успешно, но не успяхме да актуализираме вашия CryptDrive с новите данни. Може да се наложи да премахнете старата версия на документа ръчно.
Натиснете OK, за да презаредите и актуализирате правата си за достъп.", + "properties_passwordSuccess": "Паролата бе променена успешно.
Натиснете OK, за да презаредите и актуализирате правата си за достъп.", + "share_linkCategory": "Връзка", + "share_linkAccess": "Права за достъп", + "share_linkEdit": "Редактиране", + "share_linkView": "Преглед", + "share_linkPresent": "Текущ", + "share_linkOpen": "Отваряне на връзка", + "share_linkCopy": "Копиране на връзка", + "share_contactCategory": "Контакти", + "share_embedCategory": "Вграждане", + "sharedFolders_duplicate": "Някои от документите, които се опитвахте да преместите, вече бяха споделени в целевата папка.", + "sharedFolders_create": "Създаване на споделена папка", + "sharedFolders_create_name": "Име на папка", + "sharedFolders_create_owned": "Собствена папка", + "convertFolderToSF_SFParent": "Тази папка не може да бъде преобразувана в споделена папка в текущото си местоположение. Преместете го извън споделената папка, за да продължите." } diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index 81b14ccc1..d5efe86a3 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1783,5 +1783,9 @@ "admin_onboardingNameHint": "Bitte wähle einen Namen, eine Beschreibung, eine Akzentfarbe und ein Logo (alle Angaben sind optional)", "team_autoTrim": "Verlauf des Team-Drives wird gelöscht... Bitte warten.", "admin_mfa_confirm_enable": "Bist du sicher, dass du die Multi-Faktor-Authentifizierung aktivieren möchtest?", - "admin_mfa_confirm_disable": "Bist du sicher, dass du die Multi-Faktor-Authentifizierung deaktivieren möchtest?" + "admin_mfa_confirm_disable": "Bist du sicher, dass du die Multi-Faktor-Authentifizierung deaktivieren möchtest?", + "fm_restoreMultipleDialog": "Bist du sicher, dass du {0} Dateien/Ordner zurück in den ursprünglichen Ordner verschieben möchtest?", + "calendar_show": "Kalender anzeigen", + "form_passwordWarning": "Bitte beachte, dass ein Formularpasswort nur zum Zeitpunkt der Erstellung festgelegt und später nicht mehr geändert werden kann.", + "calendar_hide": "Kalender verbergen" } diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 2bcf34bf7..7b809d426 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1442,8 +1442,8 @@ "admin_uptimeHint": "Date et heure auxquelles le serveur a été démarré", "admin_cat_database": "Base de données", "admin_generatedAt": "Horodatage du rapport", - "ui_true": "activé", - "ui_false": "désactivé", + "ui_true": "vrai", + "ui_false": "faux", "ui_none": "aucun", "ui_generateReport": "Générer un rapport", "ui_success": "Succès", @@ -1783,5 +1783,9 @@ "install_notes": "
  • 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.
  • 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. Si vous le perdez il n'est pas possible de récupérer vos données.
  • Si vous utilisez un ordinateur partagé, n'oubliez pas de vous déconnecter quand vous aurez terminé. Simplement fermer la fenêtre du navigateur web laisse votre compte exposé à des risques de sécurité.
", "team_autoTrim": "Suppression de l'historique du drive d'équipe... Veuillez patienter.", "admin_mfa_confirm_disable": "Êtes-vous sûr de vouloir désactiver l'authentification multi-facteur ?", - "admin_mfa_confirm_enable": "Êtes-vous sûr de vouloir activer l'authentification multi-facteur ?" + "admin_mfa_confirm_enable": "Êtes-vous sûr de vouloir activer l'authentification multi-facteur ?", + "fm_restoreMultipleDialog": "Êtes-vous sûr·e de vouloir restaurer {0} fichiers et/ou dossiers à leurs emplacements précédents ?", + "calendar_hide": "Cacher les calendriers", + "calendar_show": "Afficher les calendriers", + "form_passwordWarning": "Veuillez noter qu'un mot de passe pour Formulaire peut uniquement être spécifié lors de la création du document et ne peut pas être changé plus tard." } diff --git a/www/common/translations/messages.hu.json b/www/common/translations/messages.hu.json index a6957d7e4..9056314dc 100644 --- a/www/common/translations/messages.hu.json +++ b/www/common/translations/messages.hu.json @@ -421,5 +421,35 @@ "settings_import": "Importálás", "upload_pending": "Függöben lévő", "upload_up": "Feltöltés", - "features_f_subscribe": "Feliratkozás" + "features_f_subscribe": "Feliratkozás", + "toolbar_savetodrive": "Mentés képként", + "comments_comment": "Hozzászólás", + "drive_treeButton": "Fájlok", + "fm_noResult": "Keresés eredménytelen", + "settings_cat_style": "Megjelenés", + "logoutButton": "Kijelentkezés", + "login_noSuchUser": "Hibás felhasználónév vagy jelszó", + "login_invalUser": "Felhasználónév szükséges", + "login_unhandledError": "Váratlan hiba történt :(", + "register_passwordsDontMatch": "A jelszavak nem egyeznek!", + "register_alreadyRegistered": "Ez a felhasználónév már létezik! Szeretnél bejelentkezni?", + "settings_changePasswordNew": "Új jelszó", + "settings_changePasswordCurrent": "Aktuális jelszó", + "settings_codeSpellcheckTitle": "Helyesírás-ellenőrzés", + "comments_submit": "Beküldés", + "toolbar_insert": "Beszúrás", + "toolbar_tools": "Eszközök", + "slide_backCol": "Háttérszín", + "slide_textCol": "Szövegszín", + "toolbar_file": "Fájl", + "support_cat_bug": "Hibajelentés", + "support_attachments": "Csatolmányok", + "settings_kanbanTagsOr": "VAGY", + "history_close": "Bezár", + "history_restore": "Visszaállít", + "fm_restricted": "Nincs hozzáférése", + "support_cat_all": "Összes", + "support_addAttachment": "Csatolmány hozzáadása", + "oo_refresh": "Frissítés", + "support_formCategoryError": "Hiba: üres kategória" } diff --git a/www/common/translations/messages.it.json b/www/common/translations/messages.it.json index a50327151..9aab3c535 100644 --- a/www/common/translations/messages.it.json +++ b/www/common/translations/messages.it.json @@ -648,7 +648,7 @@ "contact_dev": "Contatta la quadra di sviluppo", "contact_admin": "Contatta gli amministratori e le amministratrici per: {0}", "footer_donate": "Dona", - "admin_registeredTitle": "Utenti registrati", + "admin_registeredTitle": "Drive di utenti e gruppi", "admin_activePadsTitle": "Documenti attivi", "admin_activeSessionsTitle": "Connessioni attive", "adminPage": "Amministrazione", @@ -843,7 +843,7 @@ "support_disabledHint": "Questa istanza di CryptPad non è ancora configurata per utilizzare un modulo di assistenza.", "sharedFolders_share": "Condividi questo link con altri utenti registrati o altre utenti registrate per dare loro accesso alla cartella condivisa. Una volta che aprono questo link, la cartella condivisa sarà aggiunta al loro CryptDrive.", "autostore_notAvailable": "Devi salvare questo documento nel tuo CryptDrive prima di poter utilizzare questa funzionalità.", - "admin_registeredHint": "Numero di utenti registrati/e nella tua istanza", + "admin_registeredHint": "Numero di drive attivi sulla tua istanza", "admin_updateLimitDone": "Aggiornamento completato con successo", "requestEdit_button": "Richiedi i diritti di modifica", "requestEdit_accepted": "{1} ti ha permesso di modificare il documento {0}", @@ -1768,5 +1768,8 @@ "admin_appsHint": "Scegli le app da abilitare su questa istanza.", "admin_cat_apps": "ApplicazIoni", "admin_onboardingOptionsTitle": "Opzioni dell’istanza", - "admin_onboardingOptionsHint": "Scegli l’opzione appropriata per la tua istanza.
Queste configurazioni possono essere cambiate successivamente nel pannello di amministrazione." + "admin_onboardingOptionsHint": "Scegli l’opzione appropriata per la tua istanza.
Queste configurazioni possono essere cambiate successivamente nel pannello di amministrazione.", + "team_autoTrim": "Eliminazione della cronologia del drive del gruppo... Si prega di attendere.", + "admin_mfa_confirm_enable": "Sei sicuro/a di voler attivare l'autenticazione a più fattori?", + "admin_mfa_confirm_disable": "Sei sicuro/a di voler disattivare l'autenticazione a più fattori?" } diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 548ce9200..fa940fb1f 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1783,5 +1783,9 @@ "admin_onboardingDescPlaceholder": "Instance description text", "team_autoTrim": "Trimming team drive history... Please wait.", "admin_mfa_confirm_enable": "Are you sure you want to enable Multi-Factor Authentication?", - "admin_mfa_confirm_disable": "Are you sure you want to disable Multi-Factor Authentication?" + "admin_mfa_confirm_disable": "Are you sure you want to disable Multi-Factor Authentication?", + "form_passwordWarning": "Please note that a Form password can only be set now at creation time and cannot be changed later.", + "fm_restoreMultipleDialog": "Are you sure you want to restore {0} files and/or folders to their previous locations?", + "calendar_show": "Show calendars", + "calendar_hide": "Hide calendars" } diff --git a/www/common/translations/messages.nl.json b/www/common/translations/messages.nl.json index 022193059..400941007 100644 --- a/www/common/translations/messages.nl.json +++ b/www/common/translations/messages.nl.json @@ -663,5 +663,9 @@ "admin_broadcastTitle": "Broadcast bericht", "pad_settings_hide": "Verbergen", "importError": "Importeren mislukt (verkeerd formaat)", - "terms": "Servicevoorwaarden" + "terms": "Servicevoorwaarden", + "creation_404": "Dit document bestaat niet meer. Gebruik het volgende formulier om een nieuw document te maken.", + "feedback_about": "Als je dit leest was je waarschijnlijk nieuwsgierig waarom CryptPad om webpagina's vraagt wanneer je bepaalde acties uitvoert.", + "features_f_social_note": "Voeg contacten toe voor veilige samenwerking, creëer een profiel, fijnmazige toegangscontroles", + "feedback_optout": "Als u zich wilt afmelden, ga dan naar uw gebruikersinstellingenpagina, waar u een selectievakje vindt om gebruikersfeedback in of uit te schakelen." } diff --git a/www/common/translations/messages.pl.json b/www/common/translations/messages.pl.json index 705f6a363..910973218 100644 --- a/www/common/translations/messages.pl.json +++ b/www/common/translations/messages.pl.json @@ -1,16 +1,16 @@ { - "main_title": "CryptPad: Wspólne edytowanie w czasie rzeczywistym, bez wiedzy specjalistycznej", + "main_title": "CryptPad: Współpraca w czasie rzeczywistym, szyfrowana z wiedzą zerową", "type": { - "pad": "Pad", + "pad": "Tekst sformatowany", "code": "Kod", - "poll": "Balot", + "poll": "Ankieta", "slide": "Slajdy Markdown", "contacts": "Kontakty", "file": "Plik", "kanban": "Kanban", "presentation": "Prezentacja", "doc": "Dokument", - "form": "Formularz", + "form": "Ankieta", "teams": "Zespoły", "sheet": "Arkusz", "todo": "Do zrobienia", @@ -32,7 +32,7 @@ "exportButtonTitle": "Eksportuj ten dokument do lokalnego pliku", "exportPrompt": "Jak chciałbyś nazwać swój plik?", "clickToEdit": "Naciśnij by edytować", - "forgetPrompt": "Kliknięcie OK przeniesie ten dokument do kosza. Jesteś pewien/pewna?", + "forgetPrompt": "Kliknięcie OK przeniesie ten dokument do kosza. Jesteś pewien?", "shareButton": "Udostępnij", "shareSuccess": "Pomyślnie skopiowano URL", "presentButtonTitle": "Otwórz tryb prezentacji", @@ -49,7 +49,7 @@ "poll_userPlaceholder": "Twoje imię", "poll_removeOption": "Jesteś pewien, że chcesz usunąć tę opcję?", "poll_removeUser": "Jesteś pewien, że chcesz usunąć tego użytkownika?", - "poll_descriptionHint": "Opisz swoją ankietę i użyj przycisku ✓ (opublikuj), gdy skończysz.\nW opisie możesz użyć składni markdown oraz osadzać elementy multimedialne z dysku CryptDrive.\nKażda osoba posiadająca link może zmienić opis, co jednak nie jest zalecane.", + "poll_descriptionHint": "Opisz swoją ankietę i użyj przycisku ✓ (opublikuj), gdy skończysz.\nW opisie możesz użyć składni Markdown oraz osadzać elementy multimedialne z dysku CryptDrive.\nKażda osoba posiadająca link może zmienić opis, co jednak nie jest zalecane.", "header_logoTitle": "Przejdź na stronę główną", "storageStatus": "Pamięć:
Wykorzystałeś {0} z {1}", "upgradeAccount": "Ulepsz swoje konto", @@ -60,25 +60,25 @@ "forgotten": "Przeniesiono do kosza", "initializing": "Inicjalizacja...", "typing": "Edytowanie", - "realtime_unrecoverableError": "Wystąpił nieodwracalny błąd. Wciśnij OK, aby odświeżyć stronę.", - "disabledApp": "Ta aplikacja nie jest dostępna. Skontaktuj się z administratorem, aby uzyskać więcej informacji.", - "mustLogin": "Musisz być zalogowany/a aby otrzymać dostęp do tej strony", + "realtime_unrecoverableError": "Wystąpił nieodwracalny błąd. Kliknij OK, aby załadować ponownie.", + "disabledApp": "Ta aplikacja nie jest dostępna. Skontaktuj się z administratorem, aby uzyskać więcej informacji.", + "mustLogin": "Musisz być zalogowany/a, aby otrzymać dostęp do tej strony", "deletedFromServer": "Dokument został zniszczony", "deleted": "Usunięto", "saved": "Zapisano", "error": "Błąd", "loading": "Ładowanie...", - "newVersionError": "Nowa wersja CryptPad jest dostępna.
Odśwież aby korzystać z nowej wersji lub wciśnij klawisz Esc aby pracować w trybie offline.", - "errorRedirectToHome": "Wciśnij Esc, by zostać przekierowanym do własnego dysku CryptDrive.", - "errorCopy": " Możesz korzystać z aktualnej wersji w trybie tylko do odczytu, klikając Esc.", - "invalidHashError": "Dokument, który chcesz zobaczyć ma błędny adres URL.", - "chainpadError": "Podczas aktualizacji zawartości wystąpił krytyczny błąd. Dokument wyświetlany jest w trybie tylko do odczytu, aby umożliwić zachowanie wyników pracy.
Wciśnij klawisz Esc aby wyświetlić dokument lub odśwież stronę, by spróbować wrócić do trybu edycji.", - "inactiveError": "Ten dokument został usunięty z powodu braku aktywności. Wciśnij klawisz Esc, aby stworzyć nowy dokument.", + "newVersionError": "Nowa wersja CryptPad jest dostępna.
Odśwież aby korzystać z nowej wersji, lub wciśnij klawisz Esc, aby pracować w trybie offline.", + "errorRedirectToHome": "Wciśnij Esc, by zostać przekierowanym do Twojego dysku CryptDrive.", + "errorCopy": " Możesz korzystać z aktualnej wersji w trybie tylko do odczytu wciskając Esc.", + "invalidHashError": "Dokument, który próbujesz wyświetlić, ma nieprawidłowy adres URL.", + "chainpadError": "Podczas aktualizacji zawartości wystąpił krytyczny błąd. Dokument wyświetlany jest w trybie tylko do odczytu, aby umożliwić zachowanie wyników pracy.
Wciśnij klawisz ESC aby wyświetlić dokument lub załaduj ponownie, by spróbować dalszej edycji.", + "inactiveError": "Ten dokument został usunięty z powodu nieaktywności. Kliknij klawisz ESC, aby stworzyć nowy dokument.", "deletedError": "Dokument został usunięty i nie jest już dostępny.", "expiredError": "Dokument wygasł i nie jest już dostępny.", "anonymousStoreDisabled": "Administrator tej instancji CryptPad wyłączył zapisywanie danych dla niezalogowanych użytkowników. Zaloguj się, aby korzystać z własnego dysku CryptDrive.", - "padNotPinnedVariable": "Dokument zostanie usunięty po {4} dniach braku aktywności, {0}zaloguj się{1} lub {2}zarejestruj{3} aby go zachować.", - "padNotPinned": "Ten dokument zostanie usunięty po 3 miesiącach braku aktywności, {0}zaloguj się{1} lub {2}zarejestruj{3} aby go zachować.", + "padNotPinnedVariable": "Dokument zostanie usunięty po {4} dniach braku aktywności, {0}zaloguj się{1} lub {2}zarejestruj{3}, aby go zachować.", + "padNotPinned": "Ten dokument zostanie usunięty po 3 miesiącach braku aktywności, {0}zaloguj się{1} lub {2}zarejestruj{3}, aby go zachować.", "onLogout": "Jesteś wylogowany, {0}kliknij tutaj{1} aby się zalogować
lub użyj klawisza Esc aby wyświetlić swój dokument (tryb tylko do odczytu).", "typeError": "Dokument nie jest kompatybilny z wybraną aplikacją", "template_empty": "Brak szablonów", @@ -90,9 +90,9 @@ "templateSaved": "Szablon zapisany!", "saveTemplatePrompt": "Wybierz nazwę dla szablonu", "saveTemplateButton": "Zapisz jako szablon", - "uploadButtonTitle": "Prześlij nowy plik na swój dysk CryptDrive", - "uploadFolderButton": "Wgraj folder", - "uploadButton": "Prześlij pliki", + "uploadButtonTitle": "Wrzuć nowy plik na swój dysk CryptDrive", + "uploadFolderButton": "Wrzuć folder", + "uploadButton": "Wrzuć pliki", "newButtonTitle": "Utwórz nowy dokument", "newButton": "Nowy", "userAccountButton": "Menu użytkownika", @@ -109,7 +109,7 @@ "pinLimitDrive": "Osiągnięto limit przestrzeni dyskowej.
Nie możesz tworzyć nowych dokumentów.", "pinLimitNotPinned": "Osiągnięto limit przestrzeni dyskowej.
Dokument nie będzie zapisany na Twoim CryptDrive.", "pinLimitReachedAlertNoAccounts": "Osiągnięto limit przestrzeni dyskowej", - "pinLimitReachedAlert": "Osiągnięto limit przestrzeni dyskowej. Nowe dokumenty nie będą przechowywane na Twoim dysku CryptDrive.
Możesz usunąć dokumenty ze swojego CryptDrive lub skorzystać z oferty premium aby zwiększyć jego pojemność.", + "pinLimitReachedAlert": "Osiągnięto limit przestrzeni dyskowej. Nowe dokumenty nie będą przechowywane na Twoim dysku CryptDrive.
Możesz usunąć dokumenty ze swojego CryptDrive lub skorzystać z oferty premium, aby zwiększyć jego pojemność.", "pinLimitReached": "Osiągnięto limit przestrzeni dyskowej", "formattedKB": "{0} kB", "formattedGB": "{0} GB", @@ -118,9 +118,9 @@ "GB": "GB", "MB": "MB", "fm_viewListButton": "Widok listy", - "fm_error_cantPin": "Wewnętrzny błąd serwera. Proszę przeładować stronę i spróbować ponownie.", + "fm_error_cantPin": "Wewnętrzny błąd serwera. Proszę załadować stronę ponownie i spróbować jeszcze raz.", "fm_info_owned": "Jesteś właścicielem wyświetlanych tu dokumentów. Oznacza to, że możesz je trwale usunąć z serwera, kiedy tylko zechcesz. Jeśli to zrobisz, inni użytkownicy nie będą mieli już do nich dostępu.", - "fm_info_sharedFolder": "To jest folder współdzielony. Nie jesteś zalogowany, więc masz do niego dostęp tylko w trybie do odczytu.
Zarejestruj się lub zaloguj aby móc zaimportować go na swój dysk CryptDrive i modyfikować.", + "fm_info_sharedFolder": "To jest folder współdzielony. Nie jesteś zalogowany, więc masz do niego dostęp wyłącznie w trybie tylko do odczytu.
Zarejestruj się lub zaloguj aby móc zaimportować go na swój dysk CryptDrive i modyfikować.", "fm_info_anonymous": "Nie jesteś zalogowany, więc Twoje dokumenty wygasną po {0} dniach. Wyczyszczenie historii przeglądarki może spowodować ich zniknięcie.
Zarejestruj się (dane osobowe nie są wymagane) lubZaloguj się, aby przechowywać je na dysku przez czas nieokreślony.Dowiedz się więcej o zarejestrowanych kontach.", "fm_info_trash": "Opróżnij swój kosz, aby zwolnić miejsce na swoim dysku CryptDrive.", "fm_info_recent": "Dokumenty te były ostatnio otwierane lub modyfikowane przez Ciebie lub osoby, z którymi współpracujesz.", @@ -128,7 +128,7 @@ "fm_info_root": "Utwórz tutaj tyle zagnieżdżonych folderów, ile chcesz, aby uporządkować swoje pliki.", "fm_categoryError": "Nie można otworzyć wybranej kategorii, wyświetlany jest folder główny.", "fm_selectError": "Nie można wybrać elementu docelowego. Jeśli problem nadal występuje, spróbuj ponownie załadować stronę.", - "fm_contextMenuError": "Nie można otworzyć menu kontekstowego dla tego elementu. Jeśli problem nadal występuje, spróbuj przeładować stronę.", + "fm_contextMenuError": "Nie można otworzyć menu kontekstowego dla tego elementu. Jeśli problem nadal występuje, spróbuj ponownie załadować stronę.", "fm_unknownFolderError": "Wybrany lub ostatnio odwiedzany folder już nie istnieje. Otwieranie folderu nadrzędnego...", "fm_restoreDialog": "Czy na pewno chcesz przywrócić {0} do poprzedniej lokalizacji?", "fm_deleteOwnedPads": "Czy jesteś pewien, że chcesz trwale zniszczyć te dokumenty?", @@ -189,9 +189,9 @@ "profile_viewMyProfile": "Wyświetl mój profil", "profile_register": "Musisz się zarejestrować, aby stworzyć profil!", "profile_error": "Błąd podczas tworzenia profilu: {0}", - "profile_uploadTypeError": "Błąd: typ Twojego avatara jest niedozwolony. Dozwolone typy to: {0}", + "profile_uploadTypeError": "Błąd: typ Twojego awatara jest niedozwolony. Dozwolone typy to: {0}", "profile_uploadSizeError": "Błąd: Twój awatar musi być mniejszy niż {0}", - "profile_upload": " Prześlij nowy awatar", + "profile_upload": " Wrzuć nowy awatar", "profileButton": "Profil", "canvas_imageEmbed": "Dołącz obraz z komputera", "canvas_currentBrush": "Aktualny pędzel", @@ -202,9 +202,9 @@ "canvas_width": "Szerokość", "canvas_delete": "Usuń zaznaczenie", "canvas_clear": "Wyczyść", - "oo_cantUpload": "Przesyłanie danych nie jest dozwolone, gdy inni użytkownicy są aktywni.", - "oo_uploaded": "Przesyłanie danych zostało zakończone. Kliknij OK, aby ponownie załadować stronę lub Anuluj, aby kontynuować w trybie tylko do odczytu.", - "oo_reconnect": "Połączenie z serwerem zostało przywrócone. Kliknij OK, aby przeładować i kontynuować edycję.", + "oo_cantUpload": "Wrzucanie plików nie jest dozwolone, gdy inni użytkownicy są aktywni.", + "oo_uploaded": "Wrzucanie plików zostało zakończone. Kliknij OK, aby ponownie załadować stronę lub anuluj, aby kontynuować w trybie tylko do odczytu.", + "oo_reconnect": "Połączenie z serwerem zostało przywrócone. Kliknij OK, aby załadować ponownie i kontynuować edycję.", "poll_comment_disabled": "Opublikuj tę ankietę używając przycisku ✓, aby włączyć komentarze.", "poll_comment_placeholder": "Twój komentarz", "poll_comment_remove": "Usuń ten komentarz", @@ -218,7 +218,7 @@ "poll_locked": "Zablokowane", "poll_edit": "Edytuj", "poll_remove": "Usuń", - "poll_commit": "Wyślij", + "poll_commit": "Prześlij", "poll_create_option": "Dodaj nową opcję", "poll_create_user": "Dodaj nowego użytkownika", "poll_publish_button": "Opublikuj", @@ -232,10 +232,10 @@ "pad_mediatagImport": "Zapisz na swoim CryptDrive", "pad_mediatagPreview": "Podgląd", "pad_mediatagBorder": "Szerokość ramki (w pikselach)", - "pad_mediatagRatio": "Zachowuj proporcje", + "pad_mediatagRatio": "Zachowaj proporcje", "pad_mediatagHeight": "Wysokość (w pikselach)", "pad_mediatagWidth": "Szerokość (w pikselach)", - "pad_mediatagTitle": "Ustawienia Tagów Medialnych", + "pad_mediatagTitle": "Ustawienia Tagów Mediów", "openLinkInNewTab": "Otwórz link w nowej karcie", "history_restoreDone": "Dokument przywrócony", "history_restorePrompt": "Czy na pewno chcesz zastąpić aktualną wersję dokumentu wyświetlaną wersją?", @@ -255,10 +255,10 @@ "viewEmbedTag": "Aby osadzić ten dokument, umieść tę ramkę na swojej stronie, gdziekolwiek chcesz. Możesz ją stylizować za pomocą CSS lub atrybutów HTML.", "themeButtonTitle": "Wybierz motyw kolorystyczny, który ma być używany dla edytorów kodu i slajdów", "themeButton": "Motyw", - "languageButtonTitle": "Wybierz język, który ma być używany do kolorowania składni", + "languageButtonTitle": "Wybierz język, który ma być używany do podświetlenia składni", "languageButton": "Język", "slide_invalidLess": "Nieprawidłowy styl własny", - "slideOptionsTitle": "Dostosuj swoje slajdy", + "slideOptionsTitle": "Personalizuj swoje slajdy", "slideOptionsText": "Opcje", "tags_noentry": "Nie możesz oznaczyć usuniętego dokumentu", "tags_duplicate": "Duplikat tagu: {0}", @@ -266,12 +266,12 @@ "tags_add": "Aktualizuj tagi dla wybranych dokumentów", "tags_title": "Tagi (tylko dla Ciebie)", "filePicker_filter": "Filtruj pliki według nazwy", - "filePicker_description": "Wybierz plik ze swojego CryptDrive który chcesz osadzić, lub załaduj nowy", + "filePicker_description": "Wybierz plik który chcesz osadzić ze swojego CryptDrive, lub załaduj nowy", "filePicker_close": "Zamknij", "filePickerButton": "Osadź plik przechowywany na dysku CryptDrive", "printBackgroundRemove": "Usuń ten obraz tła", "printBackgroundNoValue": "Nie wyświetlono żadnego obrazu tła", - "printBackgroundValue": "Aktualny obraz tła: {0}", + "printBackgroundValue": "Obecne tło: {0}", "printBackgroundButton": "Wybierz obraz", "printBackground": "Użyj obrazu tła", "printTransition": "Włącz animacje przejść", @@ -283,7 +283,7 @@ "printButtonTitle2": "Drukuj dokument lub zapisz go jako plik PDF", "printButton": "Drukuj (Enter)", "printText": "Drukuj", - "propertiesButtonTitle": "Pobierz właściwości dokumentu", + "propertiesButtonTitle": "Wyświetl właściwości dokumentu", "propertiesButton": "Właściwości", "previewButtonTitle": "Wyświetl lub ukryj tryb podglądu Markdown", "settings_codeIndentation": "Wcięcie w edytorze kodu (spacje)", @@ -308,7 +308,7 @@ "settings_autostoreMaybe": "Ręcznie (zawsze pytaj)", "settings_autostoreNo": "Ręcznie (nigdy nie pytaj)", "settings_autostoreYes": "Automatycznie", - "settings_autostoreHint": "Automatycznie Wszystkie odwiedzane przez Ciebie dokumenty są przechowywane w Twoim CryptDrive.
Manual (zawsze pytaj) Jeśli nie zapisałeś jeszcze żadnego dokumentu, zostaniesz zapytany czy chcesz go zapisać w swoim CryptDrive.
Ręcznie (nigdy nie pytaj) Dokumenty nie są przechowywane automatycznie w Twoim CryptDrive. Opcja przechowywania ich będzie ukryta.", + "settings_autostoreHint": "Automatycznie Wszystkie odwiedzane przez Ciebie dokumenty są przechowywane w Twoim CryptDrive.
Ręcznie (zawsze pytaj) Jeśli nie zapisałeś jeszcze żadnego dokumentu, zostaniesz zapytany czy chcesz go zapisać w swoim CryptDrive.
Ręcznie (nigdy nie pytaj) Dokumenty nie są przechowywane automatycznie w Twoim CryptDrive. Opcja przechowywania ich będzie ukryta.", "settings_autostoreTitle": "Przechowywanie dokumentów w CryptDrive", "settings_importDone": "Import zakończony", "settings_importConfirm": "Czy na pewno chcesz zaimportować ostatnie dokumenty z tej przeglądarki do CryptDrive Twojego konta użytkownika?", @@ -340,7 +340,7 @@ "settings_export_compressing": "Kompresja danych...", "settings_export_download": "Pobieranie i odszyfrowywanie dokumentów...", "settings_exportCancel": "Czy na pewno chcesz anulować eksport? Następnym razem będziesz musiał zacząć od początku.", - "settings_exportWarning": "Uwaga: to narzędzie jest wciąż w wersji beta i może mieć problemy ze skalowalnością. Aby uzyskać lepszą wydajność, zaleca się pozostawienie tej zakładki aktywnej.", + "settings_exportWarning": "Uwaga: narzędzie jest wciąż w wersji beta i może mieć problemy ze skalowalnością. W celu uzyskania lepszej wydajności, zaleca się pozostawienie tej karty aktywnej.", "settings_exportFailed": "Jeśli pobranie dokumentu wymaga więcej niż 1 minutę, nie zostanie on wyeksportowany. Zostanie wyświetlony link do każdego dokumentu, który nie został wyeksportowany.", "settings_exportDescription": "Zaczekaj, aż pobierzemy i odszyfrujemy Twoje dokumenty. Może to potrwać kilka minut. Zamknięcie karty spowoduje przerwanie tego procesu.", "settings_exportTitle": "Eksportuj swój CryptDrive", @@ -359,10 +359,10 @@ "settings_cat_cursor": "Kursor", "settings_cat_drive": "Dysk CryptDrive", "settings_cat_account": "Konto", - "register_emailWarning3": "Jeśli to rozumiesz i chcesz używać swojego adresu e-mail jako nazwy użytkownika, kliknij OK.", - "register_emailWarning2": "Nie będziesz mógł zresetować swojego hasła za pomocą swojego e-maila, tak jak można to zrobić w przypadku innych usług.", - "register_emailWarning1": "Możesz to zrobić, jeśli chcesz, ale nie zostanie to wysłane na nasz serwer.", - "register_emailWarning0": "Wygląda na to, że podałeś swój e-mail jako nazwę użytkownika.", + "register_emailWarning3": "Jeśli rozumiesz i nadal chcesz użyć swojego adresu email jako nazwy użytkownika, kliknij OK.", + "register_emailWarning2": "Nie będziesz mógł zresetować swojego hasła drogą mailową, tak jak można to zrobić w przypadku wielu innych usług.", + "register_emailWarning1": "Możesz tak zrobić, jeśli chcesz, ale nie zostanie to przesłane na nasz serwer.", + "register_emailWarning0": "Wygląda na to, że próbujesz użyć swojego maila jako nazwy użytkownika.", "register_alreadyRegistered": "Ten użytkownik już istnieje, czy chcesz się zalogować?", "register_warning": "Ostrzeżenie", "register_cancel": "Anuluj", @@ -386,7 +386,7 @@ "logoutButton": "Wyloguj się", "login_register": "Zarejestruj się", "login_login": "Zaloguj się", - "fo_unavailableName": "W nowej lokalizacji istnieje już plik lub folder o tej samej nazwie. Zmień nazwę elementu i spróbuj ponownie.", + "fo_unavailableName": "W nowej lokalizacji istnieje już plik lub folder o tej samej nazwie. Zmień nazwę elementu i spróbuj jeszcze raz.", "fo_moveFolderToChildError": "Nie można przenieść folderu do folderu podrzędnego", "fo_existingNameError": "Nazwa jest już używana w tym folderze. Proszę wybrać inną.", "fo_moveUnsortedError": "Nie można przenieść folderu do listy szablonów", @@ -403,7 +403,7 @@ "fc_delete": "Przenieś do kosza", "fc_expandAll": "Rozwiń Wszystkie", "fc_collapseAll": "Zwiń Wszystkie", - "fc_open_ro": "Otwó©z (tylko do odczytu)", + "fc_open_ro": "Otwórz (tylko do odczytu)", "fc_open": "Otwórz", "fc_color": "Zmień kolor", "fc_rename": "Zmień nazwę", @@ -421,11 +421,11 @@ "fm_renamedPad": "Nadano nazwę własną dla tego dokumentu. Jego udostępniony tytuł to:
{0}", "fm_viewGridButton": "Widok siatki", "requestEdit_confirm": "{1} poprosił o możliwość edycji dokumentu {0}. Czy chcesz przyznać mu dostęp?", - "requestEdit_button": "Poproś o prawa do edycji", + "requestEdit_button": "Poproś o zezwolenie edycji", "support_notification": "Administrator odpowiedział na Twoje zgłoszenie", "notifications_dismissAll": "Odrzuć wszystkie", "notifications_cat_archived": "Historia", - "notifications_cat_pads": "Udostępnione Tobie", + "notifications_cat_pads": "Udostępnione dla Ciebie", "notifications_cat_friends": "Prośby o kontakt", "notifications_cat_all": "Wszystkie", "openNotificationsApp": "Otwórz panel powiadomień", @@ -438,8 +438,8 @@ "support_close": "Zamknij zgłoszenie", "support_answer": "Odpowiedz", "support_listHint": "Oto lista zgłoszeń wysłanych do administratorów i ich odpowiedzi. Zamknięte zgłoszenie nie może być ponownie otwarte, ale możesz utworzyć nowe. Możesz ukryć zgłoszenia, które zostały zamknięte.", - "support_listTitle": "Zgłoszenia pomocy technicznej", - "support_cat_tickets": "Aktualne zgłoszenia", + "support_listTitle": "Zgłoszenia wsparcia technicznego", + "support_cat_tickets": "Istniejące zgłoszenia", "support_formMessage": "Wpisz swoją wiadomość…", "support_formContentError": "Błąd: treść jest pusta", "support_formTitleError": "Błąd: tytuł jest pusty", @@ -449,14 +449,14 @@ "support_cat_new": "Nowe zgłoszenie", "support_disabledHint": "Ta instancja CryptPad nie jest jeszcze skonfigurowana do korzystania z formularza pomocy technicznej.", "support_disabledTitle": "Wsparcie nie jest włączone", - "admin_supportListHint": "Tutaj znajduje się lista zgłoszeń wysłanych przez użytkowników na skrzynkę wsparcia. Wszyscy administratorzy mogą zobaczyć te wiadomości i odpowiedzi na nie. Zamkniętego zgłoszenia nie można ponownie otworzyć. Możesz jedynie usunąć (ukryć) zamknięte zgłoszenia, a usunięte zgłoszenia są nadal widoczne dla innych administratorów.", + "admin_supportListHint": "Tutaj znajduje się lista zgłoszeń wysłanych przez użytkowników na skrzynkę pomocy technicznej. Wszyscy administratorzy mogą zobaczyć te wiadomości i odpowiedzi na nie. Zamkniętego zgłoszenia nie można ponownie otworzyć. Możesz jedynie usunąć (ukryć) zamknięte zgłoszenia, a usunięte zgłoszenia są nadal widoczne dla innych administratorów.", "admin_supportListTitle": "Skrzynka pocztowa wsparcia technicznego", "admin_supportInitHint": "Możesz skonfigurować skrzynkę mailową która posłuży jako adres wsparcia technicznego, w celu zapewnienia użytkownikom Twojej instancji CryptPad sposobu na bezpieczny kontakt w razie problemów z kontem.", - "admin_supportInitTitle": "Wsparcie inicjalizacji skrzynki pocztowej", - "admin_supportAddError": "Niepoprawny klucz prywatny", + "admin_supportInitTitle": "Inicjalizacja skrzynki pocztowej wsparcia technicznego", + "admin_supportAddError": "Nieprawidłowy klucz prywatny", "admin_supportAddKey": "Dodaj klucz prywatny", - "admin_supportInitPrivate": "Twoja instancja CryptPad ma skonfigurowany adres wsparcia technicznego, ale Twoje konto nie ma poprawnego klucza prywatnego, aby uzyskać do niej dostęp. Użyj poniższego formularza, aby dodać lub zaktualizować klucz prywatny do swojego konta.", - "admin_supportInitHelp": "Twój serwer nie jest jeszcze skonfigurowany do używania skrzynki pocztowej służącej do udzielania pomocy technicznej. Jeśli chcesz, aby skrzynka pocztowa służąca do udzielania pomocy technicznej otrzymywała wiadomości od Twoich użytkowników, powinieneś poprosić administratora serwera o uruchomienie skryptu znajdującego się w \"./scripts/generate-admin-keys.js\", a następnie zapisanie klucza publicznego w pliku \"config.js\" i przesłanie Ci klucza prywatnego.", + "admin_supportInitPrivate": "Twoja instancja CryptPad ma skonfigurowaną skrzynkę mailową do wsparcia technicznego, ale Twoje konto nie ma poprawnego klucza prywatnego, aby uzyskać do niej dostęp. Użyj poniższego formularza, aby dodać lub zaktualizować klucz prywatny do swojego konta.", + "admin_supportInitHelp": "Twój serwer nie jest jeszcze skonfigurowany do używania skrzynki mailowej służącej do udzielania pomocy technicznej. Jeśli chcesz, aby skrzynka mailowa służąca do udzielania pomocy technicznej otrzymywała wiadomości od Twoich użytkowników, powinieneś poprosić administratora serwera o uruchomienie skryptu znajdującego się w \"./scripts/generate-admin-keys.js\", a następnie zapisanie klucza publicznego w pliku \"config.js\" i przesłanie Ci klucza prywatnego.", "admin_cat_support": "Wsparcie", "supportPage": "Wsparcie", "fm_info_sharedFolderHistory": "Historia należy tylko do Twojego folderu współdzielonego: {0}
Twój CryptDrive pozostanie w trybie tylko do odczytu podczas nawigacji.", @@ -467,7 +467,7 @@ "notification_folderShared": "{0} udostępnił Ci folder: {1}", "notification_fileShared": "{0} udostępnił Ci plik: {1}", "notification_padShared": "{0} udostępnił Ci dokument: {1}", - "isNotContact": "{0} jest nie jednym z Twoich kontaktów", + "isNotContact": "{0} nie jest jednym z Twoich kontaktów", "isContact": "{0} jest jednym z Twoich kontaktów", "profile_friendRequestSent": "Prośba o kontakt w toku...", "profile_info": "Inni użytkownicy mogą znaleźć Twój profil za pomocą Twojego awataru na listach użytkowników dokumentów.", @@ -491,8 +491,8 @@ "admin_diskUsageButton": "Wygeneruj raport", "admin_diskUsageHint": "Ilość przestrzeni dyskowej zużywanej przez różne zasoby CryptPada", "admin_diskUsageTitle": "Wykorzystanie dysku", - "timeoutError": "Wystąpił błąd, który przerwał połączenie z serwerem.
Naciśnij Esc, aby przeładować stronę.", - "contact_email": "E-mail", + "timeoutError": "Wystąpił błąd, który przerwał połączenie z serwerem.
Naciśnij Esc, aby ponownie załadować stronę.", + "contact_email": "Email", "team_cat_chat": "Czat", "contact_chat": "Czat", "contact_bug": "Zgłoszenie błędu", @@ -518,25 +518,25 @@ "adminPage": "Administracja", "admin_cat_stats": "Statystyki", "admin_cat_general": "Ogólne", - "admin_authError": "Tylko administratorzy mogą mieć dostęp do tej strony", + "admin_authError": "Tylko administratorzy mają dostęp do tej strony", "fm_expirablePad": "Traci ważność: {0}", "markdown_toc": "Zawartość", - "survey": "Ankieta CryptPada", + "survey": "Ankieta CryptPad", "crowdfunding_popup_no": "Nie teraz", - "crowdfunding_popup_text": "

Potrzebujemy Twojej pomocy!

Aby zapewnić, że CryptPad jest aktywnie rozwijany, rozważ wsparcie projektu poprzez stronę OpenCollective, gdzie możesz zobaczyć nasze nasz Plan działania i Cele Finansowania.", - "crowdfunding_button2": "Wspomóż", + "crowdfunding_popup_text": "

Potrzebujemy Twojej pomocy!

Aby zapewnić aktywny rozwój pakietu CryptPad, rozważ wsparcie projektu poprzez stronę OpenCollective, gdzie możesz zobaczyć nasz Plan działania i Cele Finansowania.", + "crowdfunding_button2": "Przekaż darowiznę", "crowdfunding_button": "Wspieraj CryptPad", "autostore_notAvailable": "Aby móc korzystać z tej funkcji, dokument musi znajdować się na Twoim CryptDrive.", "autostore_hide": "Nie zapisuj", "autostore_store": "Zapisz", "autostore_forceSave": "Przechowaj plik na swoim CryptDrive", "autostore_saved": "Dokument został pomyślnie zapisany na Twoim CryptDrive!", - "autostore_error": "Nieoczekiwany błąd: nie udało się zapisać tego dokumentu, proszę spróbować ponownie.", + "autostore_error": "Nieoczekiwany błąd: nie udało się zapisać tego dokumentu, spróbuj jeszcze raz.", "autostore_settings": "Możesz włączyć automatyczne przechowywanie dokumentów na stronie Ustawienia.", "autostore_notstored": "Tego {0} nie ma na Twoim CryptDrive. Czy chcesz go teraz zapisać?", - "autostore_pad": "pad", - "autostore_sf": "folder", - "autostore_file": "plik", + "autostore_pad": "dokumentu", + "autostore_sf": "folderu", + "autostore_file": "pliku", "chrome68": "Wygląda na to, że używasz przeglądarki Chrome lub Chromium w wersji 68. Zawiera ona błąd powodujący, że po kilku sekundach strona staje się całkowicie biała lub nie reaguje na kliknięcia. Aby naprawić ten problem, możesz przełączyć się na inną kartę i wrócić do niej lub spróbować przewinąć stronę. Ten błąd powinien zostać naprawiony w następnej wersji przeglądarki.", "convertFolderToSF_confirm": "Ten folder musi zostać przekształcony w folder współdzielony, aby inni mogli go przeglądać. Kontynuować?", "convertFolderToSF_SFChildren": "Ten folder nie może zostać przekształcony na folder współdzielony, ponieważ zawiera już foldery współdzielone. Aby kontynuować, przenieś te foldery współdzielone w inne miejsce.", @@ -557,15 +557,15 @@ "share_contactCategory": "Kontakty", "share_linkCopy": "Kopiuj link", "share_linkOpen": "Otwórz link", - "share_linkPresent": "Obecny", + "share_linkPresent": "Prezentuj", "share_linkView": "Podgląd", "share_linkEdit": "Edytuj", - "share_linkAccess": "Prawa dostępu do danych", + "share_linkAccess": "Prawa dostępu", "share_linkCategory": "Link", "properties_changePasswordButton": "Prześlij", - "properties_passwordSuccess": "Hasło zostało pomyślnie zmienione.
Naciśnij OK, aby przeładować i zaktualizować swoje prawa dostępu.", - "properties_passwordWarning": "Hasło zostało pomyślnie zmienione, ale nie udało nam się zaktualizować danych na Twoim dysku CryptDrive. Konieczne może być manualne usunięcie starej wersji dokumentu.
Naciśnij OK, aby ponownie załadować stronę i zaktualizować dane dostępowe.", - "properties_passwordError": "Wystąpił błąd podczas próby zmiany hasła. Proszę spróbować ponownie.", + "properties_passwordSuccess": "Hasło zostało pomyślnie zmienione.
Naciśnij OK, aby załadować ponownie i zaktualizować swoje zezwolenia dostępu.", + "properties_passwordWarning": "Hasło zostało pomyślnie zmienione, ale nie udało nam się zaktualizować danych na Twoim dysku CryptDrive. Konieczne może być manualne usunięcie starej wersji dokumentu.
Naciśnij OK, aby ponownie załadować stronę i zaktualizować zezwolenia dostępu.", + "properties_passwordError": "Wystąpił błąd podczas próby zmiany hasła. Spróbuj jeszcze raz.", "properties_passwordSame": "Nowe hasła muszą się różnić od dotychczasowych.", "properties_confirmChange": "Czy jesteś pewien? Zmiana hasła spowoduje usunięcie jego historii. Użytkownicy bez nowego hasła stracą dostęp do tego dokumentu", "properties_confirmNew": "Czy jesteś pewien? Dodanie hasła spowoduje zmianę adresu URL tego dokumentu i usunięcie jego historii. Użytkownicy bez hasła stracą dostęp do tego dokumentu", @@ -592,8 +592,8 @@ "creation_owned1": "Dokument własny może zostać zniszczony, kiedy tylko właściciel tego chce. Zniszczenie dokumentu sprawia, że jest on niedostępny w CryptDrivach innych użytkowników.", "creation_owned": "Dokument własny", "creation_404": "Ten dokument już nie istnieje. Użyj poniższego formularza, aby utworzyć nowy dokument.", - "feedback_optout": "Jeśli chcesz zrezygnować, odwiedź swoją stronę ustawień użytkownika, gdzie znajdziesz pole wyboru pozwalające włączyć lub wyłączyć opinie użytkowników.", - "feedback_privacy": "Dbamy o Twoją prywatność, a jednocześnie chcemy, aby CryptPad był bardzo łatwy w użyciu. Używamy tego pliku, aby dowiedzieć się, które cechy interfejsu użytkownika mają znaczenie dla naszych użytkowników, pytając ich o to oraz rejestrując parametr określający, jaka akcja została podjęta.", + "feedback_optout": "Jeśli chcesz z tego zrezygnować, odwiedź swoją stronę ustawień użytkownika, gdzie znajdziesz pole wyboru pozwalające włączyć lub wyłączyć opinie użytkowników.", + "feedback_privacy": "Dbamy o Twoją prywatność, a jednocześnie chcemy, aby CryptPad był bardzo łatwy w użyciu. Używamy tego pliku, aby dowiedzieć się, które cechy interfejsu mają znaczenie dla naszych użytkowników, dlatego pobieramy go wraz z parametrem określającym, jaka czynność została wykonana.", "feedback_about": "Jeśli to czytasz, prawdopodobnie byłeś ciekaw, dlaczego CryptPad żąda stron internetowych, gdy wykonujesz pewne czynności.", "view": "pokaż", "edit": "edytuj", @@ -603,8 +603,8 @@ "features_f_subscribe_note": "Zarejestrowane konto jest wymagane do subskrypcji", "features_f_subscribe": "Subskrybuj", "features_f_supporter_note": "Pomóż CryptPad osiągnąć stabilność finansową i udowodnić, że oprogramowanie zwiększające prywatność, dobrowolnie finansowane przez użytkowników, powinno być normą", - "features_f_supporter": "Wsparcie prywatności", - "features_f_support_note": "Priorytetowa odpowiedź od zespołu administracyjnego poprzez e-mail i wbudowany system zgłoszeń", + "features_f_supporter": "Wspieraj prywatność", + "features_f_support_note": "Priorytetowa odpowiedź od zespołu administracyjnego drogą mailową i przez wbudowany system zgłoszeń", "features_f_support": "Szybsze wsparcie", "features_f_storage2_note": "Zwiększony limit {0}MB na wysyłanie plików, od 5GB do 50GB, w zależności od planu", "features_f_storage2": "Dodatkowe miejsce do przechowywania danych", @@ -640,7 +640,7 @@ "contact": "Kontakt", "privacy": "Polityka prywatności", "about": "O stronie", - "main_catch_phrase": "Pakiet do współpracy
end-to-end szyfrowany i oparty na otwartym kodzie źródłowym", + "main_catch_phrase": "Pakiet do współpracy
kompleksowo szyfrowany i oparty na otwartym kodzie źródłowym", "home_host": "Niezależna społecznościowa instancja CryptPada.", "mdToolbar_toc": "Spis Treści", "mdToolbar_code": "Kod", @@ -666,7 +666,7 @@ "download_step1": "Pobieranie", "download_dl": "Pobierz", "download_mt_button": "Pobierz", - "upload_up": "Prześlij", + "upload_up": "Wrzuć", "upload_mustLogin": "Musisz być zalogowany, aby przesyłać pliki", "upload_size": "Rozmiar", "upload_cancelled": "Anulowane", @@ -678,22 +678,22 @@ "upload_notEnoughSpace": "Nie ma wystarczającej ilości miejsca na ten plik w Twoim CryptDrive.", "upload_success": "Twój plik ({0}) został pomyślnie przesłany i dodany do Twojego dysku.", "upload_uploadPending": "Przesyłanie pliku jest już w toku. Anulować je i przesłać nowy plik?", - "upload_serverError": "Błąd serwera: nie można w tej chwili przesłać pliku.", + "upload_serverError": "Błąd serwera: nie można w tej chwili wrzucić pliku.", "uploadFolder_modal_forceSave": "Przechowuj pliki w swoim CryptDrive", "uploadFolder_modal_owner": "Pliki własne", "uploadFolder_modal_filesPassword": "Hasło do plików", - "uploadFolder_modal_title": "Opcje przesyłania folderów", + "uploadFolder_modal_title": "Opcje wrzucania folderów", "upload_modal_owner": "Plik własny", "upload_modal_filename": "Nazwa pliku (rozszerzenie {0} dodane automatycznie)", - "upload_modal_title": "Opcje wysyłania plików", - "upload_title": "Prześlij plik", + "upload_modal_title": "Opcje wrzucania plików", + "upload_title": "Wrzucanie plików", "settings_cursorShowLabel": "Pokaż kursory", "settings_cursorShowTitle": "Wyświetlanie pozycji kursora innych użytkowników", "settings_cursorShareLabel": "Udostępnij swoją pozycję", "settings_cursorShareTitle": "Udostępnij moją pozycję kursora", "settings_cursorColorTitle": "Kolor kursora", "settings_changePasswordNewPasswordSameAsOld": "Twoje nowe hasło musi być inne niż obecne hasło.", - "settings_changePasswordPending": "Twoje hasło jest w trakcie aktualizacji. Prosimy nie zamykać ani nie przeładowywać tej strony do czasu zakończenia procesu.", + "settings_changePasswordPending": "Twoje hasło jest w trakcie aktualizacji. Prosimy nie zamykać ani nie ładować tej strony ponownie do czasu zakończenia procesu.", "settings_changePasswordError": "Wystąpił nieoczekiwany błąd. Jeśli nie możesz się zalogować lub zmienić swojego hasła, skontaktuj się z administratorami CryptPad.", "settings_changePasswordConfirm": "Czy na pewno chcesz zmienić swoje hasło? Będziesz musiał ponownie zalogować się na wszystkich swoich urządzeniach.", "settings_changePasswordNewConfirm": "Potwierdź nowe hasło", @@ -702,16 +702,16 @@ "settings_changePasswordButton": "Zmień hasło", "settings_changePasswordHint": "Zmień hasło do swojego konta. Wpisz swoje aktualne hasło i potwierdź nowe hasło wpisując je dwukrotnie.
Nie możemy zresetować Twojego hasła, jeśli je zapomnisz, więc bądź bardzo ostrożny!", "settings_changePasswordTitle": "Zmień swoje hasło", - "settings_ownDrivePending": "Twoje konto jest w trakcie aktualizacji. Prosimy nie zamykać ani nie przeładowywać tej strony do czasu zakończenia procesu.", + "settings_ownDrivePending": "Twoje konto jest w trakcie aktualizacji. Prosimy nie zamykać ani nie ładować tej strony ponownie do czasu zakończenia procesu.", "settings_ownDriveConfirm": "Aktualizacja konta może zająć trochę czasu. Będziesz musiał ponownie zalogować się na wszystkich swoich urządzeniach. Czy jesteś pewien?", - "settings_ownDriveButton": "Aktualizuj swoje konto", + "settings_ownDriveButton": "Ulepsz swoje konto", "settings_ownDriveHint": "Starsze konta nie mają dostępu do najnowszych funkcji z powodów technicznych. Darmowa aktualizacja umożliwi korzystanie z aktualnych funkcji i przygotuje Twój CryptDrive na przyszłe aktualizacje.", "settings_ownDriveTitle": "Aktualizuj konto", "settings_padOpenLinkLabel": "Włącz bezpośrednie otwieranie linków", "settings_padOpenLinkHint": "Dzięki tej opcji możesz otwierać osadzone linki po kliknięciu bez otwierania okienka podglądu", "settings_padOpenLinkTitle": "Otwieranie linków przy pierwszym kliknięciu", "settings_padSpellcheckLabel": "Włączanie sprawdzania pisowni w dokumentach tekstowych", - "settings_padSpellcheckHint": "Ta opcja pozwala na włączenie sprawdzania pisowni w dokumentach tekstowych. Błędy ortograficzne będą podkreślone na czerwono i będziesz musiał przytrzymać klawisz Ctrl lub Meta podczas klikania prawym przyciskiem myszy, aby zobaczyć odpowiednie opcje.", + "settings_padSpellcheckHint": "Ta opcja pozwala na włączenie sprawdzania pisowni w dokumentach sformatowanych. Błędy ortograficzne będą podkreślone na czerwono i będą wymagały przytrzymania klawisza Ctrl lub Meta podczas klikania prawym przyciskiem myszy, aby zobaczyć poprawne opcje.", "settings_padSpellcheckTitle": "Sprawdzanie pisowni", "settings_padWidthLabel": "Zmniejsz szerokość edytora", "settings_padWidthHint": "Przełączanie pomiędzy trybem strony (domyślnym), który ogranicza szerokość edytora tekstu, a wykorzystaniem pełnej szerokości ekranu.", @@ -721,7 +721,7 @@ "pad_goToAnchor": "Przejdź do kotwicy", "bounce_danger": "Link, który kliknąłeś nie prowadzi do strony internetowej, ale do jakiegoś kodu lub danych, które mogą być złośliwe.\n\n(\"{0}\")\n\nCryptPad blokuje je ze względów bezpieczeństwa. Kliknięcie OK spowoduje zamknięcie tej zakładki.", "bounce_confirm": "Właśnie wychodzisz z: {0}\n\nCzy na pewno chcesz odwiedzić \"{1}\"?", - "form_answerChoice": "Proszę wybrać, w jaki sposób chcesz odpowiedzieć na ten formularz:", + "form_answerChoice": "Proszę wybrać, w jaki sposób chcesz odpowiedzieć na tą ankietę:", "form_exportSheet": "Eksportuj do Arkusza", "premiumAccess": "Jako subskrybent {0}, możesz tworzyć nowe dokumenty w tej aplikacji wczesnego dostępu. Należy pamiętać, że jest ona eksperymentalna i nie należy jej jeszcze powierzać ważnych danych.", "earlyAccessBlocked": "Ta aplikacja nie jest jeszcze dostępna w tej instancji", @@ -742,25 +742,25 @@ "form_condition_v": "Wybierz odpowiednią wartość", "form_condition_q": "Wybierz pytanie", "form_type_section": "Sekcja warunkowa", - "form_editable": "Edycja po przesłaniu", - "form_makeAnon": "Zanonimizuj odpowiedzi", - "form_responseMsg": "Ta wiadomość zostanie wyświetlona po wysłaniu formularza przez uczestników.", - "form_addMsg": "Dodaj wiadomość o wysłaniu", + "form_editable": "Późniejsza edycja odpowiedzi", + "form_makeAnon": "Anonimowe odpowiedzi", + "form_responseMsg": "Komunikat, który zostanie wyświetlony po wypełnianiu ankiety przez uczestnika.", + "form_addMsg": "Dodaj komunikat końcowy", "toolbar_preview": "Podgląd", "form_geturl": "Skopiuj publiczny link", "form_changeTypeConfirm": "Wybierz rodzaj nowego pytania.", - "form_corruptAnswers": "Ten formularz zawiera już odpowiedzi. Zmiana tego rodzaju pytania może unieważnić poprzednie dane odpowiedzi.", - "form_preview": "Zobacz ten formularz", + "form_corruptAnswers": "Ta ankieta zawiera już odpowiedzi. Zmiana typu dla tego pytania może spowodować, że dane dla przesłanych już odpowiedzi będą nieprawidłowe.", + "form_preview": "Zobacz tą ankietę", "form_required_off": "Opcjonalne", "form_required_on": "Wymagane", "form_required_answer": "Odpowiedź: ", "form_requiredWarning": "Na poniższe pytania należy udzielić odpowiedzi:", - "form_authAnswer": "Ten formularz nie może być przesłany anonimowo", - "form_anonAnswer": "Odpowiedzi na ten formularz są anonimowe", + "form_authAnswer": "Ta ankieta nie może być wypełniona anonimowo", + "form_anonAnswer": "Odpowiedzi na tą ankietę są anonimowe", "form_viewAllAnswers": "Wyświetl wszystkie odpowiedzi ({0})", "form_viewAnswer": "Wyświetl moje odpowiedzi", "form_editAnswer": "Edytuj moje odpowiedzi", - "form_alreadyAnswered": "Odpowiedziałeś na ten formularz w dniu {0}", + "form_alreadyAnswered": "Odpowiedziałeś ną ankietę w dniu {0}", "form_preview_button": "Podgląd", "form_template_poll": "Szybka ankieta dotycząca harmonogramu", "upload_addOptionalAlt": "Dodaj tekst opisowy (opcjonalnie)", @@ -789,8 +789,8 @@ "admin_instancePurposeHint": "Do czego wykorzystujesz tę instancję? Twoja odpowiedź zostanie użyta do opracowania planu rozwoju, jeśli telemetria jest włączona.", "admin_purpose_business": "Dla firmy lub organizacji komercyjnej", "admin_purpose_public": "W celu świadczenia bezpłatnych usług na rzecz społeczeństwa", - "admin_purpose_education": "Dla szkoły, kolegium lub uniwersytetu", - "admin_purpose_org": "Dla organizacji non-profit lub grupy wspierającej", + "admin_purpose_education": "Dla szkoły, uczelni, lub uniwersytetu", + "admin_purpose_org": "Dla organizacji non-profit lub grupy rzeczniczej", "admin_purpose_personal": "Dla siebie, rodziny lub przyjaciół", "admin_purpose_experiment": "Aby przetestować platformę lub opracować nowe funkcje", "admin_purpose_noanswer": "Wolę nie mówić", @@ -798,9 +798,9 @@ "resources_learnWhy": "Dowiedz się, dlaczego został zablokowany", "resources_openInNewTab": "Otwórz w nowej karcie", "resources_imageBlocked": "CryptPad zablokował zdalny obraz", - "fc_open_formro": "Otwarte (jako uczestnik)", + "fc_open_formro": "Otwórz (jako uczestnik)", "form_poll_hint": ": Tak, : Nie, : Akceptowalne", - "admin_provideAggregateStatisticsLabel": "Przedstawiaj łączne dane statystyczne", + "admin_provideAggregateStatisticsLabel": "Przedstawiaj zagregowane dane statystyczne", "admin_provideAggregateStatisticsHint": "Możesz zdecydować się na udostępnienie deweloperom dodatkowych danych dotyczących użytkowania, takich jak przybliżona liczba zarejestrowanych i aktywnych codziennie użytkowników Twojej instancji.", "admin_provideAggregateStatisticsTitle": "Agregacja statystyczna", "admin_blockDailyCheckLabel": "Wyłączenie telemetrii serwera", @@ -813,17 +813,17 @@ "admin_listMyInstanceHint": "Jeśli Twoja instancja nadaje się do użytku publicznego, możesz wyrazić zgodę na umieszczenie jej w katalogach internetowych. Telemetria serwera musi być włączona, aby miało to jakikolwiek efekt.", "admin_listMyInstanceTitle": "Umieść tę instancję w katalogach publicznych", "admin_consentToContactLabel": "Zgadzam się", - "admin_consentToContactHint": "Telemetria serwera zawiera e-mail kontaktowy administratora, aby programiści mogli powiadomić Cię o poważnych problemach z oprogramowaniem lub Twoją konfiguracją. Nigdy nie będą one udostępniane, sprzedawane lub wykorzystywane w celach marketingowych. Wyraź zgodę na kontakt, jeśli chcesz być informowany o krytycznych problemach z Twoim serwerem.", + "admin_consentToContactHint": "Telemetria serwera zawiera email kontaktowy administratora, aby programiści mogli powiadomić Cię o poważnych problemach z oprogramowaniem lub Twoją konfiguracją. Nigdy nie będą one udostępniane, sprzedawane lub wykorzystywane w celach marketingowych. Wyraź zgodę na kontakt, jeśli chcesz być informowany o krytycznych problemach z Twoim serwerem.", "admin_consentToContactTitle": "Zgoda na kontakt", "admin_checkupButton": "Uruchom diagnostykę", "admin_checkupHint": "CryptPad zawiera stronę, która automatycznie diagnozuje typowe problemy z konfiguracją i sugeruje, jak je poprawić, jeśli to konieczne.", "admin_checkupTitle": "Zweryfikuj konfigurację tej instancji", - "admin_updateAvailableButton": "Zobacz informacje o wydaniu", - "admin_updateAvailableHint": "Nowa wersja CryptPada jest dostępna", + "admin_updateAvailableButton": "Zobacz informacje o wersji", + "admin_updateAvailableHint": "Nowa wersja CryptPad jest dostępna", "admin_updateAvailableTitle": "Nowe wersje", "admin_cat_network": "Sieć", "mdToolbar_embed": "Osadź plik", - "restrictedLoginPrompt": "Nie jesteś upoważniony do dostępu do tego dokumentu.Zaloguj się, jeśli uważasz, że Twoje konto powinno być w stanie uzyskać dostęp do niego.", + "restrictedLoginPrompt": "Nie jesteś upoważniony do dostępu do tego dokumentu.Zaloguj się, jeśli uważasz, że Twoje konto powinno być w stanie uzyskać do niego dostęp.", "copyToClipboard": "Skopiuj do schowka", "settings_driveRedirect": "Przekieruj mnie automatycznie", "settings_driveRedirectHint": "Automatyczne przekierowanie ze strony głównej na dysk po zalogowaniu nie jest już domyślnie włączone. Starsze ustawienie może być włączone poniżej.", @@ -831,7 +831,7 @@ "form_anonymousBox": "Odpowiedz anonimowo", "form_page": "Strona {0}/{1}", "form_clear": "Wyczyść", - "form_submitWarning": "Przekaż mimo wszystko", + "form_submitWarning": "Prześlij mimo to", "form_delete": "Usuń", "form_reset": "Zresetuj", "form_update": "Zaktualizuj", @@ -852,30 +852,30 @@ "form_type_input": "Tekst", "form_default": "Twoje pytanie?", "form_text_number": "Liczba", - "form_text_email": "E-mail", + "form_text_email": "Email", "form_text_url": "Link", "form_text_text": "Tekst", "form_textType": "Typ tekstu", "form_pollYourAnswers": "Twoje odpowiedzi", "form_pollTotal": "Razem", "form_poll_switch": "Zamień osie", - "form_poll_time": "Czas", + "form_poll_time": "Godzina", "form_poll_day": "Dzień", "form_poll_text": "Tekst", "form_editType": "Rodzaj opcji", "form_editMaxLength": "Maksymalna liczba znaków", "form_editMax": "Maksymalna liczba możliwych do wyboru opcji", "form_editBlock": "Edytuj", - "form_invalid": "Nieprawidłowy formularz", + "form_invalid": "Nieprawidłowa ankieta", "share_formView": "Uczestnik", "share_formAuditor": "Audytor", "share_formEdit": "Autor", "admin_supportPrivButton": "Pokaż klucz", "admin_supportPrivHint": "Wyświetl klucz prywatny, który będzie potrzebny innym administratorom do przeglądania zgłoszeń. Formularz do wprowadzenia tego klucza będzie wyświetlany w ich panelu administracyjnym.", - "admin_supportInitGenerate": "Generowanie kluczy wsparcia", - "admin_supportPrivTitle": "Obsługa klucza prywatnego skrzynki pocztowej", - "admin_emailHint": "Wprowadź e-mail kontaktowy dla Twojej instancji", - "admin_emailTitle": "E-mail kontaktowy administratora", + "admin_supportInitGenerate": "Generowanie kluczy pomocy technicznej", + "admin_supportPrivTitle": "Klucz prywatny skrzynki pocztowej pomocy technicznej", + "admin_emailHint": "Wprowadź email kontaktowy dla Twojej instancji", + "admin_emailTitle": "Email kontaktowy administratora", "oo_importBin": "Kliknij OK, aby zaimportować wewnętrzny format .bin programu CryptPad.", "oo_conversionSupport": "Twoja przeglądarka nie radzi sobie z konwersją do i z formatów biurowych. Zalecamy korzystanie z najnowszej wersji Firefoxa lub Chrome.", "register_registrationIsClosed": "Rejestracja została zamknięta.", @@ -893,7 +893,7 @@ "reminder_minutes": "{0} rozpocznie się za {1} minut(y)", "reminder_inProgressAllDay": "Dzisiaj: {0}", "reminder_inProgress": "{0} rozpoczął się w {1}", - "reminder_now": "{0} miało miejsce w dniu", + "reminder_now": "{0} rozpoczął się", "reminder_missed": "{0} miało miejsce w dniu {1}", "calendar_more": "{0} więcej", "calendar_days": "Dni", @@ -921,19 +921,19 @@ "calendar_before": "przed", "calendar_weekNumber": "Tydzień {0}", "calendar_import_temp": "Importuj ten kalendarz", - "oo_cantMigrate": "Ten arkusz przekracza maksymalny rozmiar wysyłania i jest zbyt duży, aby mógł zostać przeniesiony.", + "oo_cantMigrate": "Arkusz przekracza maksymalny rozmiar wrzutu i jest zbyt duży, aby mógł zostać przemigrowany.", "footer_roadmap": "Plan działania", "settings_deleteSubscription": "Zarządzaj moją subskrypcją", "settings_deleteContinue": "Usuń moje konto", "settings_deleteWarning": "Ostrzeżenie: jesteś obecnie zapisany na plan premium (płatny lub przekazany przez innego użytkownika). Proszę anulować swój plan przed usunięciem konta, ponieważ nie będzie to możliwe bez kontaktu z obsługą po usunięciu konta.", "broadcast_newCustom": "Wiadomość od administratorów", - "broadcast_preview": "Przeglądaj powiadomienia", + "broadcast_preview": "Podgląd powiadomienia", "broadcast_defaultLanguage": "Powrót do tego języka", "broadcast_translations": "Tłumaczenia", "admin_broadcastCancel": "Usuń wiadomość", "admin_broadcastActive": "Aktywna wiadomość", "admin_broadcastButton": "Wyślij", - "admin_broadcastHint": "Wyślij wiadomość do wszystkich użytkowników tej instancji. Wszyscy istniejący i nowi użytkownicy otrzymają ją jako powiadomienie. Podgląd wiadomości przed wysłaniem jest możliwy dzięki opcji \"Podgląd powiadomienia\". Powiadomienia z podglądem mają czerwoną ikonę i są widoczne tylko dla Ciebie.", + "admin_broadcastHint": "Wyślij wiadomość do wszystkich użytkowników tej instancji. Wszyscy istniejący i nowi użytkownicy otrzymają ją jako powiadomienie. Podgląd wiadomości przed jej wysłaniem jest możliwy dzięki opcji \"Podgląd powiadomienia\". Podgląd ma czerwoną ikonę i jest widoczny tylko dla Ciebie.", "admin_cat_broadcast": "Rozsyłanie", "admin_broadcastTitle": "Roześlij wiadomość", "broadcast_surveyURL": "Link do ankiety", @@ -951,14 +951,14 @@ "broadcast_end": "Koniec", "broadcast_start": "Początek", "toolbar_degraded": "Ponad {0} redaktorów jest obecnie obecnych w tym dokumencie. Lista użytkowników i czat są wyłączone, aby poprawić wydajność.", - "oo_lostEdits": "Niestety po zsynchronizowaniu nowej zawartości nie można odzyskać ostatnio niezapisanych edycji.", + "oo_lostEdits": "Niestety po zsynchronizowaniu nowej zawartości nie można odzyskać Twoich ostatnich niezapisanych zmian.", "fm_cantUploadHere": "Nie można tutaj przesłać pliku", "importError": "Nie udało się zaimportować (niewłaściwy format)", "addOptionalPassword": "Dodaj hasło (opcjonalnie)", - "settings_colortheme_custom": "Własny", + "settings_colortheme_custom": "Niestandardowy", "pad_settings_show": "Pokaż", "pad_settings_hide": "Ukryj", - "pad_settings_comments": "Określ, czy Komentarz ma być domyślnie widoczny czy ukryty.", + "pad_settings_comments": "Określ, czy Komentarze mają być domyślnie widoczne czy ukryte.", "pad_settings_outline": "Określ, czy spis treści ma być domyślnie widoczny czy ukryty.", "pad_settings_width_large": "Pełna szerokość", "pad_settings_width_small": "Tryb strony", @@ -984,11 +984,11 @@ "settings_cacheTitle": "Pamięć podręczna", "docs_link": "Dokumentacja", "creation_helperText": "Otwórz w dokumentacji", - "creation_expiresIn": "Zniszcz w", + "creation_expiresIn": "Zniszcz za", "register_warning_note": "Ze względu na szyfrowany charakter CryptPada, administratorzy serwisu nie będą w stanie odzyskać danych w przypadku, gdy zapomnisz swoją nazwę użytkownika i/lub hasło. Prosimy o zapisanie ich w bezpiecznym miejscu.", "register_notes": "
  • Twoje hasło jest prywatnym kluczem, który szyfruje wszystkie Twoje dokumenty. W przypadku jego utraty nie ma możliwości odzyskania danych.
  • Jeśli korzystasz z udostępnionego komputera, pamiętaj o wylogowaniu po zakończeniu pracy. Tylko zamknięcie okna przeglądarki powoduje, że Twoje konto nadal pozostaje narażone.
  • Aby zachować dokumenty, które utworzyłeś i/lub zapisałeś bez logowania, zaznacz \"Importuj dokumenty z sesji gościa\".
", "register_notes_title": "Ważne uwagi", - "admin_getlimitsHint": "Lista wszystkich własnych limitów przestrzeni zastosowanych w Twojej instancji.", + "admin_getlimitsHint": "Lista wszystkich niestandardowych limitów przestrzeni zastosowanych w Twojej instancji.", "info_imprintFlavour": "Informacje prawne o administratorach tej instancji", "offlineError": "Nie można zsynchronizować najnowszych danych, ta strona nie może zostać wyświetlona w tej chwili. Ładowanie będzie kontynuowane po przywróceniu połączenia z serwisem.", "share_noContactsOffline": "Jesteś obecnie w trybie offline. Kontakty nie są dostępne.", @@ -1002,7 +1002,7 @@ "admin_support_normal": "Zgłoszenia bez odpowiedzi:", "admin_support_premium": "Zgłoszenia premium:", "contacts_confirmCancel": "Czy na pewno chcesz anulować prośbę o kontakt z {0}?", - "history_trimPrompt": "Ten dokument ma zapisaną {0} historię, która może spowolnić czas ładowania. Rozważ usunięcie historii, jeśli nie jest ona potrzebna.", + "history_trimPrompt": "Ten dokument zgromadził {0} historii, która może spowolnić czas ładowania. Rozważ usunięcie historii, jeśli nie jest ona potrzebna.", "mediatag_loadButton": "Wczytaj załącznik", "settings_mediatagSizeHint": "Maksymalny rozmiar w megabajtach (MB) dla automatycznie ładowanych elementów multimedialnych (obrazy, wideo, pdf) osadzonych w dokumentach. Elementy większe niż podany rozmiar mogą zostać załadowane ręcznie. Użyj \"-1\", aby zawsze ładować elementy multimedialne automatycznie.", "settings_mediatagSizeTitle": "Automatyczny limit pobrań", @@ -1014,12 +1014,12 @@ "download_zip_file": "Plik {0}/{1}", "download_zip": "Tworzenie pliku ZIP…", "fileTableHeader": "Pobrane i przesłane dane", - "allowNotifications": "Wszystkie powiadomienia", + "allowNotifications": "Zezwól na powiadomienia", "archivedFromServer": "Dokument zarchiwizowany", "restoredFromServer": "Przywrócony dokument", "admin_archiveInput2": "Hasło dokumentu", "admin_archiveInput": "URL dokumentu", - "admin_unarchiveButton": "Przywróc", + "admin_unarchiveButton": "Przywróć", "admin_unarchiveHint": "Przywróć dokument, który został wcześniej zarchiwizowany", "admin_archiveButton": "Archiwizuj", "admin_archiveHint": "Oznacz dokument jako niedostępny bez usuwania go na stałe. Zostanie on umieszczony w katalogu 'archiwum' i usunięty po kilku dniach (można tę opcję zmienić w pliku konfiguracyjnym serwera).", @@ -1029,14 +1029,14 @@ "error_unhelpfulScriptError": "Błąd skryptu: Sprawdź konsolę przeglądarki, aby uzyskać szczegółowe informacje", "tag_edit": "Edytuj", "tag_add": "Dodaj", - "loading_state_5": "Przekształć dokument", + "loading_state_5": "Zrekonstruuj dokument", "loading_state_4": "Wczytaj zespoły", "loading_state_1": "Wczytaj dysk", "loading_state_3": "Wczytaj foldery współdzielone", "loading_state_2": "Aktualizuj zawartość", "loading_state_0": "Zbuduj interfejs", "fm_shareFolderPassword": "Chroń ten folder hasłem (opcjonalnie)", - "access_destroyPad": "Zniszcz ten dokument lub folder na trwałe", + "access_destroyPad": "Trwale zniszcz ten dokument lub folder", "fm_deletedFolder": "Usunięty folder", "admin_limitUser": "Klucz publiczny użytkownika", "team_exportButton": "Pobierz", @@ -1048,13 +1048,13 @@ "admin_limitNote": "Notatka: {0}", "admin_limitSetNote": "Notatka", "admin_limitMB": "Limit (w MB)", - "admin_setlimitTitle": "Zastosuj limit własny", - "admin_setlimitHint": "Ustaw własne limity dla użytkowników za pomocą ich klucza publicznego. Możesz zaktualizować lub usunąć istniejący limit.", + "admin_setlimitTitle": "Zastosuj limit niestandardowy", + "admin_setlimitHint": "Ustaw niestandardowe limity dla użytkowników za pomocą ich klucza publicznego. Możesz zaktualizować lub usunąć istniejący limit.", "admin_limitPlan": "Plan: {0}", - "admin_getlimitsTitle": "Własne limity", + "admin_getlimitsTitle": "Niestandardowe limity", "admin_limit": "Obecny limit: {0}", "admin_setlimitButton": "Ustaw limit", - "admin_defaultlimitHint": "Maksymalny limit przestrzeni na dyskach CryptDrive (użytkownicy i zespoły), gdy nie nadano żadnych reguły niestandardowych", + "admin_defaultlimitHint": "Maksymalny limit przestrzeni na dyskach CryptDrive (użytkownicy i zespoły), gdy nie nadano żadnych reguł niestandardowych", "admin_defaultlimitTitle": "Maksymalny limit przechowywania danych (MB)", "admin_registrationTitle": "Zamknij rejestrację", "admin_registrationHint": "Goście odwiedzający instancję nie mają możliwości stworzenia konta. Zaproszenia mogą być tworzone przez administratorów.", @@ -1092,7 +1092,7 @@ "settings_kanbanTagsAnd": "ORAZ", "settings_kanbanTagsHint": "Wybierz, w jaki sposób filtr tagów ma działać przy wyborze wielu tagów: pokazywać tylko karty zawierające wszystkie wybrane tagi (ORAZ) lub pokazywać karty zawierające dowolny z wybranych tagów (LUB)", "settings_kanbanTagsTitle": "Filtr tagów", - "pad_tocHide": "Konspekt", + "pad_tocHide": "Zarys", "fm_noResult": "Nie znaleziono żadnych wyników", "fm_restricted": "Nie masz dostępu", "fm_emptyTrashOwned": "Twój kosz zawiera dokumenty, których jesteś właścicielem. Możesz je usunąć tylko z Twojego dysku lub zniszczyć dla wszystkich użytkowników.", @@ -1109,9 +1109,9 @@ "support_cat_bug": "Zgłoszenie błędu", "support_cat_data": "Utrata zawartości", "support_cat_account": "Konto użytkownika", - "info_privacyFlavour": "polityka prywatności w tym przypadku", + "info_privacyFlavour": "Polityka prywatności tej instancji", "user_about": "O CryptPad", - "settings_safeLinkDefault": "Bezpieczne łącza są teraz domyślnie włączone. Do kopiowania linków proszę używać menu Udostępnij , a nie paska adresu przeglądarki.", + "settings_safeLinkDefault": "Bezpieczne linki są teraz domyślnie włączone. Do kopiowania linków proszę używać menu Udostępnij , a nie paska adresu przeglądarki.", "support_languagesPreamble": "Zespół wsparcia technicznego posługuje się następującymi językami:", "slide_textCol": "Kolor tekstu", "slide_backCol": "Kolor tła", @@ -1165,12 +1165,12 @@ "teams": "Zespoły", "allow_text": "Użycie listy dostępu oznacza, że tylko wybrani użytkownicy i właściciele będą mogli uzyskać dostęp do tego dokumentu.", "logoutEverywhere": "Wyloguj się wszędzie", - "owner_text": "Właściciel(e) dokumentu są jedynymi użytkownikami uprawnionymi do: dodawania/usuwania właścicieli, ograniczania dostępu do dokumentu za pomocą listy dostępu lub usuwania dokumentu.", - "access_muteRequests": "Ignorowanie próśb o dostęp do tego dokumentu", + "owner_text": "Właściciel(e) dokumentu są jedynymi użytkownikami uprawnionymi do: dodawania/usuwania właścicieli, ograniczania dostępu do dokumentu za pomocą listy dostępu, lub usuwania dokumentu.", + "access_muteRequests": "Ignoruj prośby o dostęp do tego dokumentu", "allow_label": "Lista dostępu: {0}", "form_addMultipleHint": "Dodaj wiele dat i godzin", "form_addMultiple": "Dodaj wszystkie", - "form_anonymous_blocked": "Odpowiedzi gości są zablokowane dla tego formularza. Musisz zalogować się lub zarejestrować się, aby przesyłać odpowiedzi.", + "form_anonymous_blocked": "Odpowiedzi gości są zablokowane dla tego formularza. Musisz zalogować się lub zarejestrować się, aby przesłać odpowiedzi.", "form_add_item": "Dodaj element", "form_add_option": "Dodaj opcję", "form_newItem": "Nowy element", @@ -1180,21 +1180,21 @@ "form_anonymous_off": "Zablokowane", "form_anonymous_on": "Dozwolone", "form_anonymous": "Dostęp dla gości (niezalogowanych)", - "form_willClose": "Ten formularz zostanie zamknięty w dniu {0}", - "form_isClosed": "Ten formularz został zamknięty w dniu {0}", - "form_isOpen": "Ten formularz jest aktywny", + "form_willClose": "Ta ankieta zostanie zamknięta w dniu {0}", + "form_isClosed": "Ta ankieta została zamknięta w dniu {0}", + "form_isOpen": "Ta ankieta jest aktywna", "form_setEnd": "Ustal datę zamknięcia", "form_removeEnd": "Usuń datę zamknięcia", "form_open": "Otwórz", "form_isPrivate": "Odpowiedzi są poufne", "form_isPublic": "Odpowiedzi są publiczne", - "form_makePublicWarning": "Czy na pewno chcesz upublicznić odpowiedzi na ten formularz? Poprzednie i przyszłe odpowiedzi będą widoczne dla uczestników. Nie można tego cofnąć.", + "form_makePublicWarning": "Czy na pewno chcesz upublicznić odpowiedzi na tą ankietę? Poprzednie i przyszłe odpowiedzi będą widoczne dla uczestników. Nie można tego cofnąć.", "form_makePublic": "Opublikuj odpowiedzi", "form_invalidQuestion": "Pytanie {0}", "form_invalidWarning": "W niektórych odpowiedziach są błędy:", - "form_input_ph_url": "https://example.com", - "form_input_ph_email": "email@example.com", - "form_notAnswered": "{0} odpowiedzi puste", + "form_input_ph_url": "https://przyklad.pl", + "form_input_ph_email": "email@przyklad.pl", + "form_notAnswered": "{0} pustych odpowiedzi", "form_answerWarning": "Niepotwierdzona tożsamość", "form_answerName": "Odpowiedź od {0} na {1}", "form_backButton": "Wstecz", @@ -1205,8 +1205,8 @@ "form_editor": "Edytor", "form_results_empty": "Nie ma żadnych odpowiedzi", "form_results": "Odpowiedzi ({0})", - "form_answered": "Odpowiedziałeś już na ten formularz", - "form_cantFindAnswers": "Nie można pobrać istniejących odpowiedzi dla tego formularza.", + "form_answered": "Odpowiedziałeś już na tą ankietę", + "form_cantFindAnswers": "Nie można pobrać istniejących odpowiedzi dla tej ankiety.", "form_updateWarning": "Zaktualizuj mimo wszystko", "allow_disabled": "wyłączony", "allow_enabled": "włączony", @@ -1234,7 +1234,7 @@ "settings_safeLinksHint": "CryptPad zawiera klucze do odszyfrowania Twoich dokumentów w swoich linkach. Każdy, kto ma dostęp do historii przeglądania, może potencjalnie odczytać Twoje dane. Obejmuje to natrętne rozszerzenia przeglądarki oraz przeglądarki, które synchronizują historię na różnych urządzeniach. Włączenie funkcji \"bezpieczne łącza\" zapobiega wprowadzaniu kluczy do historii przeglądania lub wyświetlaniu ich w pasku adresu, jeśli jest to możliwe. Zdecydowanie zalecamy włączenie tej funkcji i korzystanie z menu {0} Udostępnij, aby generować linki, które można udostępniać.", "profile_login": "Musisz się zalogować, aby dodać tego użytkownika do swoich kontaktów", "dontShowAgain": "Nie pokazuj więcej", - "safeLinks_error": "Ten link został skopiowany z paska adresu przeglądarki i nie zapewnia dostępu do dokumentu. Proszę skorzystać z menu Udostępnij , aby udostępniać bezpośrednio kontaktom lub skopiować link. Przeczytaj więcej o funkcji bezpiecznych linków.", + "safeLinks_error": "Ten link został skopiowany z paska adresu przeglądarki i nie zapewnia dostępu do dokumentu. Proszę skorzystać z menu Udostępnij , aby udostępniać kontaktom bezpośrednio lub skopiować link. Przeczytaj więcej o funkcji bezpiecznych linków.", "settings_safeLinksCheckbox": "Włącz bezpieczne linki", "settings_safeLinksTitle": "Bezpieczne linki", "settings_cat_security": "Bezpieczeństwo & Ochrona prywatności", @@ -1247,26 +1247,26 @@ "oo_invalidFormat": "Ten plik nie może być zaimportowany", "burnAfterReading_warningDeleted": "Ten dokument został trwale usunięty, po zamknięciu tego okna nie będzie można się do niego ponownie dostać.", "burnAfterReading_proceed": "wyświetl i usuń", - "burnAfterReading_warningAccess": "Ten dokument ulegnie samozniszczeniu. Po kliknięciu przycisku poniżej zobaczysz zawartość tylko raz, zanim zostanie trwale usunięta. Po zamknięciu tego okna nie będzie można ponownie uzyskać do niego dostępu. Jeśli nie jesteś gotowy, aby kontynuować, możesz zamknąć to okno i wrócić do niego później.", + "burnAfterReading_warningAccess": "Ten dokument ulegnie samozniszczeniu. Po kliknięciu przycisku poniżej zobaczysz jego zawartość tylko raz, zanim zostanie trwale usunięta. Po zamknięciu tego okna nie będzie można ponownie uzyskać do niego dostępu. Jeśli nie jesteś gotowy, aby kontynuować, możesz zamknąć to okno i wrócić do niego później.", "burnAfterReading_generateLink": "Kliknij na poniższy przycisk, aby wygenerować link.", "burnAfterReading_warningLink": "Ustawiłeś ten dokument na samozniszczenie. Gdy odbiorca odwiedzi ten link, będzie mógł zobaczyć dokument tylko raz, zanim zostanie on trwale usunięty.", "burnAfterReading_linkBurnAfterReading": "Wyświetl raz i dokonaj samozniszczenia", "team_inviteLinkError": "Wystąpił błąd podczas tworzenia linku.", - "team_inviteInvalidLinkError": "Ten link do zaproszenia jest nieważny.", + "team_inviteInvalidLinkError": "To zaproszenie nie jest prawidłowe.", "team_cat_link": "Link do zaproszenia", "team_links": "Linki do zaproszeń", "team_inviteGetData": "Uzyskiwanie danych zespołu", - "team_inviteTitle": "Zaproszenie zespołu", + "team_inviteTitle": "Zaproszenie do zespołu", "team_inviteJoin": "Dołącz do zespołu", "team_invitePasswordLoading": "Odszyfrowywanie zaproszenia", "team_inviteEnterPassword": "Aby kontynuować, wprowadź hasło do zaproszenia.", "team_invitePleaseLogin": "Proszę się zalogować lub zarejestrować, aby zaakceptować to zaproszenie.", - "team_inviteFromMsg": "{0} zaprosił cię do dołączenia do zespołu {1}", + "team_inviteFromMsg": "{0} zaprosił Cię do dołączenia do zespołu {1}", "team_inviteFrom": "Od:", "team_inviteLinkCopy": "Skopiuj link", "team_inviteLinkCreate": "Utwórz link", "team_inviteLinkErrorName": "Proszę dodać nazwę dla osoby, którą zapraszasz. Osoba ta może je później zmienić. ", - "team_inviteLinkWarning": "Osoby, które uzyskają dostęp do tego linku, będą mogły dołączyć do tego zespołu i przeglądać jego zawartość. Udostępniaj go ostrożnie.", + "team_inviteLinkWarning": "Osoby, które uzyskają dostęp do tego linku, będą mogły dołączyć do tego zespołu i przeglądać jego zawartość. Uważaj, gdzie go udostępniasz.", "team_inviteLinkLoading": "Generowanie linku", "team_inviteLinkNoteMsg": "Ta wiadomość zostanie wyświetlona zanim odbiorca zdecyduje, czy chce dołączyć do zespołu.", "team_inviteLinkNote": "Dodaj prywatną wiadomość", @@ -1292,13 +1292,13 @@ "teams_table_admins": "Zarządzaj członkami", "teams_table_specificHint": "Są to stare foldery współdzielone, w których przeglądający nadal mają uprawnienia do edycji istniejących dokumentów. Dokumenty utworzone lub skopiowane do tych folderów będą miały standardowe uprawnienia.", "teams_table_specific": "Wyjątki", - "teams_table_generic_own": "Zarządzaj zespołem: zmień nazwę zespołu i awatar, dodaj lub usuń właścicieli, zmień subskrypcję zespołu, usuń zespół.", - "teams_table_generic_admin": "Zarządzaj członkami: zapraszaj i odwołuj członków, zmieniaj role członków aż do Administratora.", - "teams_table_generic_edit": "Edytuj: tworzenie, modyfikowanie i usuwanie folderów i dokumentów.", - "teams_table_generic_view": "Przeglądaj: dostęp do folderów i dokumentów (tylko do odczytu).", + "teams_table_generic_own": "Zarządzanie zespołem: zmień nazwę zespołu i awatar, dodaj lub usuń właścicieli, zmień subskrypcję zespołu, usuń zespół.", + "teams_table_generic_admin": "Zarządzanie członkami: zapraszaj i odwołuj członków, zmieniaj role członków aż do Administratora.", + "teams_table_generic_edit": "Edycja: tworzenie, modyfikowanie i usuwanie folderów i dokumentów.", + "teams_table_generic_view": "Podgląd: dostęp do folderów i dokumentów (tylko do odczytu).", "teams_table_generic": "Role i uprawnienia", "teams_table": "Role", - "driveOfflineError": "Twoje połączenie z CryptPad zostało utracone. Zmiany w tym dokumencie nie zostaną zapisane w Twoim CryptDrive. Zamknij wszystkie zakładki CryptPad i spróbuj ponownie w nowym oknie. ", + "driveOfflineError": "Twoje połączenie z CryptPad zostało utracone. Zmiany w tym dokumencie nie zostaną zapisane w Twoim CryptDrive. Zamknij wszystkie zakładki CryptPad i spróbuj jeszcze raz, w nowym oknie. ", "properties_passwordSuccessFile": "Hasło zostało pomyślnie zmienione.", "properties_passwordWarningFile": "Hasło zostało pomyślnie zmienione, ale nie udało nam się zaktualizować Twojego CryptDrive nowymi danymi. Może być konieczne ręczne usunięcie starej wersji pliku.", "properties_confirmNewFile": "Czy jesteś pewien? Dodanie hasła spowoduje zmianę adresu URL tego pliku. Użytkownicy bez hasła stracą dostęp do tego pliku.", @@ -1310,7 +1310,7 @@ "settings_codeBrackets": "Automatyczne zamykanie nawiasów", "team_quota": "Limit miejsca Twojego zespołu", "team_title": "Zespół: {0}", - "team_demoteMeConfirm": "Właśnie rezygnujesz ze swoich praw. Nie będziesz w stanie cofnąć tego działania. Czy jest pan pewien?", + "team_demoteMeConfirm": "Właśnie rezygnujesz ze swoich praw. Nie będziesz w stanie cofnąć tego działania. Czy jesteś pewien?", "team_pendingOwnerTitle": "Administrator ten nie przyjął jeszcze oferty przyznania własności.", "team_pendingOwner": "(w toku)", "team_deleteConfirm": "Zamierzasz usunąć wszystkie dane całego zespołu. Może to wpłynąć na dostęp innych członków zespołu do ich danych. Nie można tego cofnąć. Czy jesteś pewien, że chcesz kontynuować?", @@ -1322,7 +1322,7 @@ "team_kickConfirm": "{0} będzie wiedział, że usunąłeś ich z zespołu. Czy jesteś pewien?", "team_ownerConfirm": "Współwłaściciele mogą modyfikować lub usunąć zespół oraz usunąć Ciebie jako właściciela. Czy jesteś pewien?", "team_rosterPromoteOwner": "Zaoferuj prawo własności", - "owner_team_add": "{0} chce, abyś został właścicielem drużyny {1}. Czy zgadzasz się na to?", + "owner_team_add": "{0} chce, abyś został właścicielem zespołu {1}. Czy zgadzasz się na to?", "team_listSlot": "Dostępne miejsce dla zespołu", "team_listTitle": "Twoje zespoły", "team_maxTeams": "Każde konto użytkownika może być członkiem tylko {0} zespołów.", @@ -1338,8 +1338,8 @@ "team_leaveButton": "Opuść ten zespół", "team_inviteButton": "Zaproś nowych członków", "team_rosterKick": "Wyrzuć z zespołu", - "team_rosterDemote": "Zdegraduj", - "team_rosterPromote": "Awansuj", + "team_rosterDemote": "Zmniejsz kompetencje", + "team_rosterPromote": "Zwiększ kompetencje", "team_createName": "Nazwa zespołu", "team_createLabel": "Utwórz nowy zespół", "team_infoLabel": "O zespołach", @@ -1350,12 +1350,12 @@ "team_cat_create": "Nowy", "team_cat_list": "Zespoły", "team_cat_general": "Informacje ogólne", - "team_declineInvitation": "{0} odrzucił twoją ofertę dołączenia do zespołu: {1}", - "team_acceptInvitation": "{0} zaakceptował twoją ofertę dołączenia do zespołu: {1}", + "team_declineInvitation": "{0} odrzucił Twoją ofertę dołączenia do zespołu: {1}", + "team_acceptInvitation": "{0} zaakceptował Twoją ofertę dołączenia do zespołu: {1}", "team_kickedFromTeam": "{0} wyrzucił Cię z zespołu: {1}", "team_invitedToTeam": "{0} zaprasza Cię do swojego zespołu: {1}", "team_pcsSelectHelp": "Utworzenie dokumentu na dysku zespołu przekazuje zespołowi prawo własności.", - "team_pcsSelectLabel": "Przechowuj", + "team_pcsSelectLabel": "Przechowuj w", "team_inviteModalButton": "Zaproś", "team_pickFriends": "Wybierz kontakty, które chcesz zaprosić do tego zespołu", "share_linkTeam": "Dodaj do dysku zespołu", @@ -1365,37 +1365,37 @@ "owner_request_accepted": "{0} zaakceptował twoją ofertę zostania właścicielem {1}", "owner_request": "{0} chce, abyś był właścicielem {1}", "owner_add": "{0} chce, abyś był właścicielem dokumentu {1}. Czy zgadzasz się na to?", - "owner_addConfirm": "Współwłaściciele będą mogli zmienić zawartość i usunąć Cię jako właściciela. Czy jest Pan/Pani pewien/a?", - "owner_removeMeConfirm": "Właśnie rezygnujesz z prawa własności. Nie będziesz w stanie cofnąć tego działania. Czy jest Pan/Pani pewien/a?", + "owner_addConfirm": "Współwłaściciele będą mogli zmienić zawartość i usunąć Cię jako właściciela. Czy jesteś pewny?", + "owner_removeMeConfirm": "Właśnie rezygnujesz z prawa własności. Nie będziesz w stanie cofnąć tego działania. Czy jesteś pewien?", "owner_removeConfirm": "Czy na pewno chcesz usunąć prawa własności dla wybranych użytkowników? Zostaną oni powiadomieni o tym działaniu.", "owner_unknownUser": "nieznany", "owner_removePendingText": "W trakcie realizacji", "owner_removeText": "Właściciele", - "features_emailRequired": "Wymagany adres e-mail", + "features_emailRequired": "Wymagany adres email", "features_pricing": "Od {0} do {2} € miesięcznie", "features_noData": "Nie są wymagane dane osobowe", "homePage": "Strona główna", "pricing": "Cennik", "properties_unknownUser": "{0} nieznanych użytkowników", - "requestEdit_sent": "Wniosek wysłano", - "requestEdit_accepted": "{1} przyznał Ci prawa do edycji dokumentu {0}", + "requestEdit_sent": "Prośbę wysłano", + "requestEdit_accepted": "{1} przyznał Ci zezwolenie edycji dokumentu {0}", "requestEdit_request": "{1} chce edytować dokument {0}", "later": "Zdecyduj później", "requestEdit_viewPad": "Otwórz dokument w nowej karcie", - "ui_restore": "Przywróc", + "ui_restore": "Przywróć", "ui_archive": "Archiwizuj", "ui_undefined": "nieznany", - "admin_documentType": "Typ", + "admin_documentType": "Typ dokumentu", "support_warning_prompt": "Wybierz najbardziej odpowiednią kategorię dla swojego zgłoszenia. Pomaga to administratorom w selekcji zgłoszeń i zapewnia dalsze sugestie dotyczące informacji, które należy podać", "info_sourceFlavour": "Kod źródłowy CryptPad", - "info_termsFlavour": "Warunki korzystania z usługidla tego urządzenia", + "info_termsFlavour": "Warunki korzystania z usługidla tej instancji", "footer_source": "Kod źródłowy", - "admin_jurisdictionHint": "Kraj, w którym przechowywane są zaszyfrowane dane tego urządzenia", + "admin_jurisdictionHint": "Kraj, w którym przechowywane są zaszyfrowane dane tej instancji", "admin_jurisdictionTitle": "Lokalizacja hostingu", "admin_descriptionHint": "Opis, który wyświetli się dla tej instancji na liście publicznych instancji na stronie cryptpad.org", "admin_descriptionTitle": "Opis instancji", "ui_saved": "{0} zapisano", - "admin_nameHint": "Wyświetlana nazwa dla tego urządzenia z listy publicznych instacji na stronie cryptpad.org", + "admin_nameHint": "Wyświetlana nazwa dla tej instancji na liście publicznych instacji na stronie cryptpad.org", "admin_archiveNote": "Notatka", "common_connectionLost": "Utracono Połączenie z Serwerem
Dopóki połączenie nie wróci, włączony będzie tryb tylko do odczytu.", "admin_infoNotice2": "Więcej informacji można znaleźć w zakładce \"Sieć\".", @@ -1414,20 +1414,20 @@ "ui_openDirectly": "Ta funkcjonalność nie jest dostępna, gdy CryptPad jest osadzony w innej witrynie. Otworzyć ten dokument w nowej karcie?", "support_cat_debugging": "Debuguj dane", "support_debuggingDataTitle": "Informacje dotyczące debugowania konta", - "support_debuggingDataHint": "Poniższe informacje są zawarte w przesyłanych zgłoszeniach do pomocy technicznej. Żadna z nich nie umożliwia administratorom dostępu do dokumentów użytkownika ani ich odszyfrowania. Informacje te są zaszyfrowane w taki sposób, że tylko administratorzy mogą je odczytać.", + "support_debuggingDataHint": "Poniższe informacje są zawarte w zgłoszeniach przesłanych do pomocy technicznej. Nie umożliwiają administratorom dostępu do dokumentów użytkownika ani ich odszyfrowania. Informacje te są zaszyfrowane w taki sposób, że tylko administratorzy mogą je odczytać.", "fivehundred_internalServerError": "Wewnętrzny błąd serwera", "admin_cacheEvictionRequired": "Serwer został zaktualizowany o nowe ustawienia. Użyj przycisku Wyczyść pamięć podręczną, aby upewnić się, że ta zmiana będzie widoczna dla wszystkich użytkowników.", "support_warning_document": "Określ typ dokumentu, który powoduje problem i podaj jego identyfikator lub link", "admin_enableDiskMeasurementsTitle": "Pomiar wydajności dysku", - "admin_bytesWrittenTitle": "Okno pomiaru wydajności dysku", + "admin_bytesWrittenTitle": "Okno czasowe pomiaru wydajności dysku", "error_evalPermitted": "Przerwanie, ponieważ eval nie powinien być dozwolony.\n\nTen błąd jest związany z nagłówkami Content-Security-Policy, może być spowodowany: przestarzałą przeglądarką, która ich nie obsługuje, rozszerzeniami przeglądarki, które zakłócają ich prawidłowe działanie lub nieprawidłową konfiguracją tej instancji CryptPad.", "admin_enableembedsHint": "Zezwól na osadzanie dokumentów i multimediów z tej instancji na innych stronach internetowych. Spowoduje to dodanie opcji \"Osadź\" do menu Udostępnij. Ze względów bezpieczeństwa aplikacje korzystające z OnlyOffice (Arkusze, Dokument, Prezentacja) nie mogą być osadzane, nawet jeśli to ustawienie jest aktywne.", - "admin_bytesWrittenHint": "Jeśli włączono pomiary wydajności dysku, czas trwania okna można skonfigurować poniżej.", + "admin_bytesWrittenHint": "Jeśli włączono pomiary wydajności dysku, czas trwania można skonfigurować poniżej.", "admin_setDuration": "Ustaw czas trwania", "ui_ms": "milisekundy", "admin_enableembedsTitle": "Włącz osadzanie zdalne", "error_embeddingDisabled": "Osadzanie jest wyłączone dla tej instancji CryptPad", - "error_embeddingDisabledSpecific": "Osadzanie jest wyłączone dla tej instancji CryptPad.", + "error_embeddingDisabledSpecific": "Osadzanie jest wyłączone dla tej aplikacji CryptPad.", "error_incorrectAccess": "Dostęp do tej strony można uzyskać tylko przez {0}.", "ui_experimental": "Ta funkcja jest uznawana za eksperymentalną.", "admin_noticeTitle": "Ogłoszenie na stronie głównej", @@ -1437,7 +1437,7 @@ "home_location": "Zaszyfrowane dane znajdują się w {0}", "home_morestorage": "By uzyskać więcej miejsca:", "register_instance": "Tworzenie nowego konta na {0}", - "admin_uptimeHint": "Data i godzina założenia serwera", + "admin_uptimeHint": "Data i godzina uruchomienia serwera", "admin_cat_database": "Baza danych", "ui_false": "fałsz", "ui_none": "brak", @@ -1463,7 +1463,7 @@ "admin_restoreDocument": "Przywróć dokument", "admin_planlimit": "Limit pamięci", "admin_getRawMetadata": "Historia metadanych", - "og_teamDrive": "Dysk grupowy", + "og_teamDrive": "Dysk zespołowy", "admin_cat_users": "Katalog użytkowników", "admin_archiveReason": "Podaj powód archiwizacji i potwierdź, że chcesz kontynuować", "admin_accountMetadataPlaceholder": "ID Użytkownika (klucz publiczny)", @@ -1477,7 +1477,7 @@ "admin_channelAvailable": "Dostępne", "admin_uptimeTitle": "Data uruchomienia", "admin_blockMetadataTitle": "Informacje segmentu logowania", - "admin_blockMetadataHint": "Segment logowania pozwala użytkownikowi na logowanie się do CryptPad'a za pomocą loginu _ hasła", + "admin_blockMetadataHint": "Segment logowania pozwala użytkownikowi na logowanie się do CryptPad za pomocą nazwy użytkownika + hasła", "admin_blockMetadataPlaceholder": "Względny lub bezwzględny adres URL", "admin_planName": "Nazwa planu", "admin_note": "Adnotacja planu", @@ -1513,12 +1513,12 @@ "admin_pinLogAvailable": "Dostępny log pinezek", "admin_pinLogArchived": "Log pinezek został zarchiwizowany", "admin_getPinList": "Lista obecnych pinezek", - "og_default": "CryptPad: szyfrowany end-to-end pakiet narzędzi do wspólnej pracy", + "og_default": "CryptPad: kompleksowo szyfrowany pakiet narzędzi do wspólnej pracy", "calendar_rec_edit": "Powtarzające się wydarzenie", "calendar_str_filter_day": "Dni: {0}", - "calendar_rec_weekdays": "Codziennie w weekendy", + "calendar_rec_weekdays": "Codziennie w dni powszednie", "calendar_str_filter_monthday": "Dni miesiąca: {0}", - "calendar_rec_custom": "Własne", + "calendar_rec_custom": "Niestandardowe", "calendar_str_filter_yearday": "Dni roku: {0}", "calendar_str_filter_weekno": "Tygodnie: {0}", "calendar_str_filter_month": "Miesiące: {0}", @@ -1549,7 +1549,7 @@ "calendar_nth_4": "czwarty", "calendar_rec_monthly_pick": "W dni", "calendar_nth_5": "piąty", - "calendar_str_monthly": "{0} miesiąc/y", + "calendar_str_monthly": "{0} miesięcy", "calendar_str_weekly": "{0} tygodni", "calendar_str_yearly": "{0} lat", "calendar_str_nthdayofmonth": "w {0} {1}", @@ -1558,23 +1558,23 @@ "calendar_str_daily": "{0} dni", "team_inviteRole": "Domyślna rola", "form_exportJSON": "Wyeskportuj do JSON", - "form_alreadyAnsweredMult": "Udzieliłeś/łaś odpowiedzi na ten formularz w dniu:", - "form_responseNotification": "Nowe odpowiedzi w formularzu: {0}", - "form_answer_new": "Wyślij ponownie", - "form_editable_off": "Jednorazowy", - "form_editable_on_del": "Jednorazowy i edytuj/usuń", - "form_multiple": "Wielokrotnie", - "form_multiple_edit": "Wielokrotnie i edytuj/usuń", - "form_editable_on": "Jednorazowy i edytuj", - "form_editable_str": "Zgłoszenie", + "form_alreadyAnsweredMult": "Udzieliłeś odpowiedzi na tą ankietę w dniu:", + "form_responseNotification": "Nowe odpowiedzi w ankiecie: {0}", + "form_answer_new": "Prześlij ponownie", + "form_editable_off": "Jednorazowe", + "form_editable_on_del": "Jednorazowe i edytuj/usuń", + "form_multiple": "Wielokrotne", + "form_multiple_edit": "Wielokrotne i edytuj/usuń", + "form_editable_on": "Jednorazowe i edytuj", + "form_editable_str": "Przesłanie odpowiedzi", "team_linkUses": "(pozostało {0}/{1})", "form_anonymized": "Odpowiedzi są anonimowe", - "form_settingsButton": "Ustawienia formularza", + "form_settingsButton": "Ustawienia ankiety", "calendar_desc": "Opis", "calendar_description": "Opis:{0}{1}", "sso_login_description": "Zaloguj się z", "sso_register_description": "Zarejestruj się z", - "recovery_mfa_description": "Jeśli straciłeś dostęp do swojej metody 2FA możesz wyłączyć je dla swojego konta używając kodu odzyskiwania. Zacznij od wprowadzenia swojej nazwy użytkownika i hasła:", + "recovery_mfa_description": "Jeśli straciłeś dostęp do swojej metody 2FA, możesz wyłączyć ją dla swojego konta używając kodu odzyskiwania. Zacznij od wprowadzenia swojej nazwy użytkownika i hasła:", "calendar_removeNotification": "Usuń przypomnienie", "team_inviteUses": "Dozwolona ilość użycia linku (0 = nielimitowany)", "form_deleteAll": "Usuń wszystko", @@ -1585,7 +1585,7 @@ "done": "Zakończone", "continue": "Kontynuuj", "settings_otp_invalid": "Niewłaściwy kod weryfikacyjny", - "duplicate": "Duplikat", + "duplicate": "Duplikuj", "mfa_revoke_label": "Aby wyłączyć 2FA, na początku wprowadź swoje hasło", "mfa_revoke_button": "Potwierdź wyłączenie 2FA", "team_nameAlreadySet": "{0} jest już nazwą zespołu", @@ -1596,7 +1596,7 @@ "admin_archiveAccountInfo": "Łącznie z dokumentami, które są jego własnością", "admin_restoreAccount": "Przywróć to konto", "admin_accountSuspended": "Konto zarchiwizowane przez administratora", - "dph_sf_pw": "Folder współdzielony {0} jest chroniony nowym hasłem. Wprowadź nowe hasło aby uzyskać dostęp, lub usuń folder ze swojego dysku.", + "dph_sf_pw": "Folder współdzielony {0} jest chroniony nowym hasłem. Wprowadź nowe hasło, aby uzyskać dostęp, lub usuń folder ze swojego dysku.", "settings_mfaTitle": "Uwierzytelnianie Dwuetapowe (2FA)", "dph_account_inactive": "To konto zostało usunięte z powodu braku aktywności", "dph_account_moderated": "To konto zostało zawieszone przez moderatora", @@ -1614,14 +1614,14 @@ "form_condorcetRanked": "Metoda Tidemana (Ranked Pairs)", "form_showCondorcetWinner": "zwycięzca: ", "form_showDetails": "Szczegóły", - "form_condorcetExtendedDisplay": "Ilość cząstkowych wygranych dla każdego z kandydatów: ", + "form_condorcetExtendedDisplay": "Ilość rund wygranych przez każdego z kandydatów: ", "form_noCondorcetWinner": "Brak zwycięzcy", "form_type_date": "Data", "mfa_setup_label": "Aby włączyć 2FA, na początku wprowadź swoje hasło", "mfa_revoke_code": "Wprowadź swój kod uwierzytelniający", "dph_pad_pw": "Ten dokument jest chroniony nowym hasłem", "support_insertRecorded": "Wstaw fragment", - "support_team": "Zespół Pomocy Technicznej", + "support_team": "Zespół Wsparcia Technicznego", "support_answerAs": "Odpowiadasz jako {0}", "support_movePending": "Przenieś do archiwum", "support_moveActive": "Przenieś do aktywnych", @@ -1639,7 +1639,7 @@ "mfa_enable": "Włącz 2FA", "settings_removeOwnedButton": "Zniszcz swoje dokumenty", "admin_totpEnabled": "2FA jest włączone", - "recovery_mfa_error": "Nieznany błąd. Odśwież i spróbuj ponownie.", + "recovery_mfa_error": "Nieznany błąd. Załaduj ponownie i spróbuj jeszcze raz.", "recovery_mfa_disabled": "Uwierzytelnianie wieloetapowe jest już wyłączone dla tego konta.", "recovery_mfa_secret_ph": "Kod odzyskiwania", "admin_invitationTitle": "Zaproszenia", @@ -1648,34 +1648,34 @@ "admin_usersRemove": "Usuń", "register_invalidToken": "Zaproszenie jest nieprawidłowe", "label_logo": "Logo CryptPad", - "recovery_mfa_secret": "Wprowadź swój kod odzyskiwania aby wyłączyć 2FA dla swojego konta:", + "recovery_mfa_secret": "Wprowadź swój kod odzyskiwania, aby wyłączyć 2FA dla swojego konta:", "login_notFilledUser": "Wprowadź nazwę użytkownika", "login_notFilledPass": "Wprowadź hasło", "date": "Data", - "settings_removeOwnedHint": "Wszystkie dokumenty których jesteś jedynym właścicielem zostaną bezpowrotnie zniszczone", + "settings_removeOwnedHint": "Wszystkie dokumenty, których jesteś jedynym właścicielem, zostaną bezpowrotnie zniszczone", "mfa_status_off": "2FA nieaktywne na tym koncie", - "mfa_recovery_hint": "Jeśli stracisz dostęp do swojej aplikacji uwierzytelniającej możesz pozbawić się możliwości dostępu do konta CryptPad. Kod odzyskiwania może zostać użyty aby wyłączyć 2FA i przywrócić dostęp.", - "admin_totpRecoveryHint": "Użytkownik może skopiować dane ze strony /recovery/ przywracania 2FA i wysłać je mailem do administratora instancji. Wklej dane przywracania poniżej aby wyłączyć 2FA dla konta", + "mfa_recovery_hint": "Jeśli stracisz dostęp do swojej aplikacji uwierzytelniającej, możesz pozbawić się możliwości dostępu do konta CryptPad. Kod odzyskiwania może zostać użyty, aby wyłączyć 2FA i przywrócić dostęp.", + "admin_totpRecoveryHint": "Użytkownik może skopiować dane ze strony /recovery/ przywracania 2FA i wysłać je mailem do administratora instancji. Wklej dane przywracania poniżej, aby wyłączyć 2FA dla konta", "admin_totpRecoveryMethod": "Sposób przywrócenia 2FA", "admin_totpDisable": "Wyłącz 2FA dla tego konta", "mfa_recovery_warning": "Ten kod nie zostanie wyświetlony ponownie, zapisz go w bezpiecznym miejscu i nie udostępniaj nikomu.", - "settings_otp_tuto": "Zeskanuj kod QR swoją aplikacją uwierzytelniającą i wpisz kod weryfikacyjny aby potwierdzić.", + "settings_otp_tuto": "Zeskanuj kod QR swoją aplikacją uwierzytelniającą i wpisz kod weryfikacyjny, aby potwierdzić.", "admin_totpFailed": "Weryfikacja podpisu nie udała się", "admin_totpCheck": "Weryfikacja podpisu powiodła się", "admin_totpDisableButton": "Wyłącz", "register_nameTooLong": "Nazwa użytkownika musi zawierać poniżej {0} znaków", "loading_enter_otp": "To konto jest chronione za pomocą uwierzytelniania dwuskładnikowego. Wprowadź swój kod weryfikacyjny", "loading_recover": "Nie możesz zdobyć kodu? Przywróć swoje konto", - "goLeft": "Lewo", + "goLeft": "W lewo", "ssoauth_header": "Hasło CryptPad", "ssoauth_form_hint_login": "Wprowadź swoje hasło CryptPad", "kanban_showTags": "Wszystkie tagi", "kanban_hideTags": "Mniej tagów", - "admin_forcemfaTitle": "Wymagaj Uwierzytelniania Dwuskładnikowego", - "admin_forcemfaHint": "Wszyscy użytkownicy tej instancji zostaną poproszeni o skonfigurowanie uwierzytelniania dwuskładnikowego, aby zalogować się do swojego konta. Użytkownicy już istniejący również nie będą mogli korzystać ze swojego konta bez konfiguracji aplikacji TOTP.", + "admin_forcemfaTitle": "Wymagaj Uwierzytelniania Dwuetapowego", + "admin_forcemfaHint": "Wszyscy użytkownicy tej instancji zostaną poproszeni o skonfigurowanie uwierzytelniania dwuetapowego, aby zalogować się do swojego konta. Użytkownicy już istniejący również nie będą mogli korzystać ze swojego konta bez konfiguracji aplikacji TOTP.", "support_recordedContent": "Treść", "support_legacyDump": "Wyeksportuj wszystko", - "support_legacyClear": "Usuń to konto", + "support_legacyClear": "Usuń dla tego konta", "mfa_disable": "Wyłącz 2FA", "admin_totpRecoveryTitle": "Przywrócenie 2FA", "mfa_recovery_title": "Zapisz kod odzyskania teraz", @@ -1688,23 +1688,23 @@ "recovery_header": "Przywracanie 2FA", "recovery_forgot": "Zapomniany kod odzyskiwania", "recovery_forgot_text": "Skopiuj następujące informacje i prześlij je administratorom swojej instancji", - "goRight": "Prawo", - "loading_mfa_required": "Uwierzytelnianie dwuskłądnikowe jest wymagane na tej instancji. Uaktualnij swoje konto z użyciem aplikacji uwierzytelniającej i poniższego formularza.", + "goRight": "W prawo", + "loading_mfa_required": "Uwierzytelnianie dwuetapowe jest wymagane na tej instancji. Uaktualnij swoje konto z użyciem aplikacji uwierzytelniającej i poniższego formularza.", "admin_invitationLink": "Zaproszenie", "admin_registrationSsoTitle": "Zamknij rejestrację SSO", "admin_usersAdd": "Dodaj istniejącego użytkownika", "admin_storeInvitedLabel": "Automatycznie dodaj zaproszonych użytkowników", "admin_usersRemoveConfirm": "Czy na pewno chcesz usunąć użytkownika z katalogu? Nadal będą mieć dostęp do i będą w stanie używać swojego konta.", - "ssoauth_form_hint_register": "Dodaj hasło CryptPad aby zwiększyć poziom zabezpieczenia, lub pozostaw puste i kontynuuj. Jeśli nie dodasz hasła, klucze chroniące Twoje dane będą dostępne dla administratorów instancji.", + "ssoauth_form_hint_register": "Dodaj hasło CryptPad, aby zwiększyć poziom zabezpieczenia, lub pozostaw puste i kontynuuj. Jeśli nie dodasz hasła, klucze chroniące Twoje dane będą dostępne dla administratorów instancji.", "label_viewMode": "Włącz tryb podglądu", "team_nameTooLong": "Zbyt długa nazwa zespołu (maks. 50 znaków)", "context_menu": "Akcje folderów", "admin_accountReport": "Raport archiwizacji konta", "admin_accountReportFull": "Pobierz raport szczegółowy", "admin_channelPlaceholder": "Zastępstwo zniszczonego dokumentu", - "status": "Status strony", + "status": "Strona statusu", "admin_diskUsageWarning": "Uwaga! W zależności od ilości danych przechowywanych w tej instancji, wygenerowanie raportu może pochłonąć całą pamięć dostępną na serwerze i spowodować awarię.", - "calendar_rec_change": "Przenoszenie powtarzającego się wydarzenia do innego kalendarza. Zmiana może zostać zrobiona tylko dla tego wydarzenia, lub dla wszystkich jego powtórzeń.", + "calendar_rec_change": "Przenoszenie powtarzającego się wydarzenia do innego kalendarza. Zmiana może zostać zastosowana tylko dla tego wydarzenia, lub dla wszystkich jego powtórzeń.", "calendar_rec_change_first": "Przenoszenie pierwszego powtarzającego się wydarzenia do innego kalendarza. Powtórzenia również zostaną przeniesione.", "admin_cat_security": "Bezpieczeństwo", "admin_cat_customize": "Dostosuj", @@ -1712,9 +1712,9 @@ "admin_logoTitle": "Własne logo", "admin_supportAdd": "Dodaj kontakt do zespołu pomocy technicznej", "admin_logoHint": "SVG, PNG lub JPG, maksymalny rozmiar 200KB", - "admin_logoButton": "Prześlij nowe", + "admin_logoButton": "Wrzuć nowe", "admin_logoRemoveButton": "Przywróć domyślne", - "admin_colorHint": "Zmień kolor akcentu Twojej instancji CryptPad. Dopilnuj, żeby tekst i przyciski były czytelne i posiadały wystarczający kontrast zarówno dla jasnego jak i ciemnego motywu.", + "admin_colorHint": "Zmień kolor akcentu Twojej instancji CryptPad. Dopilnuj, żeby tekst i przyciski były czytelne i posiadały wystarczający kontrast zarówno dla jasnego, jak i ciemnego motywu.", "admin_colorCurrent": "Obecny kolor akcentu", "admin_colorChange": "Zmień kolor", "admin_colorPick": "Wybierz kolor", @@ -1736,20 +1736,20 @@ "support_active_tag": "Skrzynka odbiorcza", "support_closed_tag": "Zamknięte", "support_privacyTitle": "Odpowiedz anonimowo", - "support_privacyHint": "Zaznacz tę opcję żeby odpowiedzieć jako 'Zespół Pomocy Technicznej' zamiast własną nazwą użytkownika", + "support_privacyHint": "Zaznacz tę opcję, żeby odpowiedzieć jako 'Zespół Pomocy Technicznej' zamiast pod własną nazwą użytkownika", "support_notificationsTitle": "Wyłącz powiadomienia", "support_userChannel": "ID kanału powiadomień użytkownika", "support_openTicketHint": "Skopiuj dane użytkownika odbiorcy z ich profilu lub z istniejącego zgłoszenia. Otrzymają powiadomienie o wiadomości.", - "support_recordedId": "ID formatki (unikalny)", + "support_recordedId": "ID fragmentu (unikalny)", "support_userKey": "Klucz publiczny użytkownika", "support_invalChan": "Nieprawidłowy kanał powiadomień", - "support_recordedTitle": "Formatki", + "support_recordedTitle": "Fragmenty", "admin_supportTeamTitle": "Zarządzaj zespołem pomocy technicznej", "admin_supportTeamHint": "Dodaj lub usuń osoby z zespołu pomocy technicznej tej instancji", "support_pasteUserData": "Wklej tu dane użytkownika", "support_legacyButton": "Pokaż aktywne zgłoszenia", "support_recordedHint": "Zdefiniuj często używane fragmenty tekstu, które będzie można potem wstawić do wiadomości jednym kliknięciem.", - "support_recordedEmpty": "Brak formatek", + "support_recordedEmpty": "Brak fragmentów", "support_legacyTitle": "Zobacz stare dane pomocy", "support_searchLabel": "Znajdź (tytuł lub ID zgłoszenia)", "support_legacyHint": "Zobacz zgłoszenia z poprzedniego systemu pomocy technicznej i odtwórz je w nowym.", @@ -1757,10 +1757,10 @@ "admin_supportInit": "Inicjalizuj helpdesk na tej instancji", "moderationPage": "Helpdesk", "support_userNotification": "Nowe zgłoszenie lub odpowiedź: {0}", - "admin_invitationHint": "Każde zaproszenie stworzy jedno konto, nawet jeśli rejestracja jest zamknięta. Nazwa użytkownika i email są wyłącznie poglądowe. CryptPad nie wyśle zaproszenia (czy czegokolwiek innego) mailem, skopiuj link i prześlij go za pomocą wybranego bezpiecznego kanału.", + "admin_invitationHint": "Każde zaproszenie stworzy jedno konto, nawet jeśli rejestracja jest zamknięta. Nazwa użytkownika i email służą wyłącznie do identyfikacji. CryptPad nie wyśle zaproszenia (czy czegokolwiek innego) mailem, skopiuj link i prześlij go za pomocą wybranego bezpiecznego kanału.", "admin_storeSsoLabel": "Automatycznie dodaj użytkowników SSO", "admin_usersBlock": "URL bloku logowania użytkownika (opcjonalne)", - "admin_usersHint": "Lista znanych Ci kont na tej instancji. Zaznacz poniżej aby dodać konta automatycznie, lub wprowadź informacje ręcznie za pomocą formularza.", + "admin_usersHint": "Lista znanych Ci kont na tej instancji. Zaznacz poniżej, aby dodać konta automatycznie, lub wprowadź informacje ręcznie za pomocą formularza.", "admin_supportSetupHint": "Stwórz lub aktualizuj klucze pomocy.", "admin_supportRotateNotify": "Uwaga: nowe klucze zostały wygenerowane, ale nieoczekiwany błąd nie pozwolił systemowi wysłać ich moderatorom. Usuń i dodaj ponownie członków zespołu", "support_notificationsHint": "Zaznacz tę opcję, żeby wyłączyć powiadomienia o nowych zgłoszeniach i odpowiedziach", @@ -1772,7 +1772,7 @@ "install_header": "Instalacja", "install_instance": "Stwórz pierwsze konto administratora, a następnie dostosuj instancję", "install_launch": "Konfiguracja instancji", - "install_notes": "
  • Na tej stronie stworzysz swoje pierwsze konto administratora. Administratorzy zarządzają ustawieniami instancji, w tym przydziałem przestrzeni dyskowej i mają dostęp do narzędzi moderacji.
  • Twoje hasło to tajny klucz, szyfrujący wszystkie Twoje dokumenty i przywileje administratora na tej instancji. Jeśli je zgubisz, nie mamy możliwości odzyskania Twoich danych.
  • Jeśli dzielisz komputer z innymi osobami, pamiętaj, aby się wylogować po zakończeniu pracy. Zamknięcie jedynie okna przeglądarki naraża bezpieczeństwo Twojego konta.
", + "install_notes": "
  • Na tej stronie stworzysz swoje pierwsze konto administratora. Administratorzy zarządzają ustawieniami instancji, w tym przydziałem przestrzeni dyskowej, i mają dostęp do narzędzi moderacji.
  • Twoje hasło to tajny klucz, szyfrujący wszystkie Twoje dokumenty i przywileje administratora na tej instancji. Jeśli je zgubisz, nie mamy możliwości odzyskania Twoich danych.
  • Jeśli dzielisz komputer z innymi osobami, pamiętaj, aby się wylogować po zakończeniu pracy. Zamknięcie jedynie okna przeglądarki naraża bezpieczeństwo Twojego konta.
", "onboarding_upload": "Wybierz logo", "onboarding_save_error": "Niektóre opcje nie zostały prawidłowo zapisane. Odwiedź panel administratora, aby sprawdzić ich wartości.", "admin_onboardingNameHint": "Wybierz tytuł, opis, kolor wiodący i logo (opcjonalnie)", @@ -1781,7 +1781,7 @@ "admin_onboardingNamePlaceholder": "Tytuł instancji", "admin_onboardingDescPlaceholder": "Treść opisu instancji", "admin_onboardingOptionsHint": "Zaznacz właściwą opcję dla Twojej instancji.
To ustawienie może być później zmienione w panelu administratora.", - "team_autoTrim": "Zmniejszanie historii dysku... Proszę czekać.", + "team_autoTrim": "Zmniejszanie historii dysku zespołu... Proszę czekać.", "admin_mfa_confirm_enable": "Czy na pewno chcesz włączyć uwierzytelnianie wieloetapowe?", "admin_mfa_confirm_disable": "Czy na pewno chcesz wyłączyć uwierzytelnianie wieloetapowe?" } diff --git a/www/common/translations/messages.tr.json b/www/common/translations/messages.tr.json index 62b85d2e5..40c8eccb4 100644 --- a/www/common/translations/messages.tr.json +++ b/www/common/translations/messages.tr.json @@ -11,8 +11,8 @@ "slide": "Markdown Sunumları", "poll": "Anket", "code": "Kod", - "pad": "Zengin metin biçimi", - "doc": "Doküman", + "pad": "Zengin Metin", + "doc": "Belge", "presentation": "Sunum", "diagram": "Diyagram", "sheet": "Sheet", @@ -45,12 +45,12 @@ "MB": "MB", "GB": "GB", "formattedGB": "{0} GB", - "formattedKB": "{0} KB", + "formattedKB": "{0} kB", "importButton": "İçe aktar", "clickToEdit": "Düzenlemek için tıkla", "forgetButton": "Sil", "shareButton": "Paylaş", - "uploadFolderButton": "Klasör yükle", + "uploadFolderButton": "Dizini karşıya yükle", "saveTemplatePrompt": "Şablon için bir başlık seçin", "templateSaved": "Şablon kaydedildi!", "selectTemplate": "Bir şablon seçin veya escape tuşuna basın", @@ -66,15 +66,15 @@ "mustLogin": "Bu sayfaya erişmek için giriş yapmalısınız", "forgotten": "Çöp kutusuna taşındı", "errorState": "Kritik hata: {0}", - "KB": "KB", + "KB": "kB", "formattedMB": "{0} MB", - "typeError": "Bu doküman seçilmiş uygulama ile uyumlu değil", + "typeError": "Bu belge seçilen uygulama ile uyumlu değil", "disconnected": "Bağlantı kesildi", "forgetPrompt": "Tamam'ı tıkladığınızda bu belge çöp kutunuza taşınacaktır. Emin misin?", "uploadButtonTitle": "CryptDrive'ınıza yeni bir dosya yükleyin", "userAccountButton": "Kullanıcı menüsü", "deletedError": "Bu belge silindi ve artık mevcut değil.", - "inactiveError": "Bu belge, işlem yapılmaması nedeniyle silinmiştir. Yeni bir belge oluşturmak için Esc tuşuna basın.", + "inactiveError": "Bu belge, işlem yapılmaması nedeniyle silindi. Yeni bir belge oluşturmak için Esc tuşuna basın.", "chainpadError": "İçeriğiniz güncellenirken kritik bir hata oluştu. Çalışmanızı kaybetmemeniz için bu sayfa salt okunur modundadır.
Bu belgeyi görüntülemeye devam etmek için Esc tuşuna basın veya yeniden düzenlemeyi denemek için yeniden yükleyin.", "errorRedirectToHome": "CryptDrive'ınıza yönlendirilmek için Esc tuşuna basın.", "newVersionError": "CryptPad'in yeni bir sürümü mevcut. Yeni sürümü kullanmak için
yeniden yükleyin veya çevrimdışı modda içeriğinize erişmek için escape tuşuna basın.", @@ -84,5 +84,453 @@ "pinLimitReachedAlert": "Depolama sınırınıza ulaştınız. Yeni belgeler CryptDrive'ınızda saklanmaz.
Sınırınızı artırmak için belgeleri CryptDrive'ınızdan kaldırabilir veya premium bir teklife abone olabilirsiniz.", "pinLimitNotPinned": "Depolama sınırınıza ulaştınız.
Bu belge CryptDrive'ınızda saklanmıyor.", "movedToTrash": "Bu doküman çöp kutusuna taşındı.
Drive'ıma erişin", - "saveTemplateButton": "Şablon olarak kaydet" + "saveTemplateButton": "Şablon olarak kaydet", + "propertiesButton": "Özellikler", + "filePicker_close": "Kapat", + "poll_unlocked": "Kilidi açık", + "pad_mediatagPreview": "Ön izleme", + "printText": "Yazdır", + "slideOptionsText": "Seçenekler", + "languageButton": "Dil", + "themeButton": "Tema", + "ok": "Tamam", + "cancel": "İptal", + "help_button": "Yardım", + "historyText": "Geçmiş", + "kanban_done": "Tamamlandı", + "poll_publish_button": "Yayınla", + "poll_commit": "Gönder", + "poll_optionPlaceholder": "Seçenek", + "poll_remove": "Kaldır", + "poll_edit": "Düzenle", + "poll_locked": "Kilitli", + "exportButton": "Dışarı Aktar", + "canvas_clear": "Temizle", + "settings_import": "İçeri Aktar", + "upload_pending": "Bekleniyor", + "fm_templateName": "Şablonlar", + "settingsButton": "Ayarlar", + "fm_searchPlaceholder": "Ara...", + "fm_prop_tagsList": "Etiketler", + "fc_rename": "Yeniden Adlandır", + "settings_resetButton": "Kaldır", + "settings_cat_account": "Hesap", + "upload_size": "Size", + "notificationsPage": "Bildirimler", + "settings_thumbnails": "Küçük Resimler", + "settings_autostoreYes": "Otomatik", + "upload_cancelled": "İptal Edildi", + "upload_up": "Karşıya Yükle", + "properties_changePasswordButton": "Gönder", + "share_withFriends": "Paylaş", + "mdToolbar_tutorial": "https://www.markdowntutorial.com/", + "edit": "düzenle", + "features": "Özellikler", + "share_linkEdit": "Düzenle", + "share_linkPresent": "Present", + "contact_chat": "Sohbet", + "settings_codeSpellcheckTitle": "Yazım denetimi", + "support_formButton": "Gönder", + "team_cat_list": "Takımlar", + "team_cat_chat": "Sohbet", + "poll_total": "TOPLAM", + "poll_comment_list": "Yorumlar", + "poll_comment_submit": "Gönder", + "canvas_width": "Genişlik", + "canvas_opacity": "Opaklık", + "profileButton": "Profil", + "contacts_title": "Kişiler", + "contacts_send": "Gönder", + "contacts_padTitle": "Sohbet", + "contacts_rooms": "Odalar", + "fm_rootName": "Drive", + "fm_trashName": "Çöp", + "fm_searchName": "Ara", + "fm_recentPadsName": "Son", + "fm_ownedPadsName": "Sahiplenmiş", + "fm_tagsName": "Etiketler", + "fm_newButton": "Yeni", + "fm_folder": "Dizin", + "fm_type": "Tür", + "fm_creation": "Oluşturma", + "fc_open": "Aç", + "fc_delete_owned": "Yok Et", + "fc_restore": "Geri Getir", + "fc_remove": "Kaldır", + "fc_remove_sharedfolder": "Kaldır", + "fc_prop": "Özellikler", + "fc_hashtag": "Etiketler", + "login_username": "Kullanıcı Adı", + "login_password": "Parola", + "register_header": "Kayıt Ol", + "register_cancel": "İptal", + "register_warning": "Uyarı", + "settings_cat_drive": "CryptDrive", + "settings_cat_cursor": "İmleç", + "settings_cat_code": "Kod", + "settings_cat_subscription": "Abonelik", + "settings_title": "Ayarlar", + "settings_save": "Kaydet", + "settings_backupCategory": "Yedekle", + "settings_backup": "Yedekle", + "settings_restore": "Geri Getir", + "settings_resetTipsAction": "Sıfırla", + "settings_resetTips": "İpuçları", + "settings_resetThumbnailsAction": "Temizle", + "settings_userFeedbackTitle": "Geri Bildirim", + "settings_padSpellcheckTitle": "Yazım Denetimi", + "download_mt_button": "İndir", + "download_step1": "İndiriliyor", + "download_dl": "İndir", + "download_step2": "Şifre çözülüyor", + "todo_title": "CryptTodo", + "mdToolbar_help": "Yardım", + "mdToolbar_bold": "Kalın", + "mdToolbar_italic": "İtalik", + "mdToolbar_strikethrough": "Üstü çizili", + "mdToolbar_heading": "Başlık", + "mdToolbar_link": "Bağlantı", + "mdToolbar_quote": "Quote", + "mdToolbar_code": "Kod", + "about": "Hakkında", + "contact": "İletişim", + "features_title": "Özellikler", + "features_anon": "Misafir", + "features_registered": "Kayıt olundu", + "features_premium": "Premium", + "features_f_subscribe": "Abone ol", + "view": "görüntüle", + "creation_expireFalse": "Sınırsız", + "creation_expireHours": "Saat", + "creation_expireDays": "Gün", + "creation_expireMonths": "Ay", + "creation_password": "Parola\n", + "creation_create": "Oluştur", + "creation_owners": "Sahipler", + "creation_passwordValue": "Parola", + "password_submit": "Gönder", + "share_linkCategory": "Bağlantı", + "share_linkView": "Görüntüle", + "share_contactCategory": "Contacts", + "share_embedCategory": "Gömülü", + "autostore_file": "dosya", + "autostore_sf": "dizin", + "autostore_pad": "pad", + "autostore_store": "Depola", + "crowdfunding_button2": "Bağış Yap", + "markdown_toc": "İçerikler", + "admin_cat_general": "Genel", + "admin_cat_stats": "İstatistikler", + "adminPage": "Yönetim", + "footer_donate": "Bağış", + "contact_email": "E-posta", + "friendRequest_decline": "Reddet", + "notifications_dismiss": "Anımsatma", + "supportPage": "Destek", + "admin_cat_support": "Destek", + "support_answer": "Yanıtla", + "notifications_cat_all": "Tüm", + "notifications_cat_archived": "Geçmiş", + "pricing": "Fiyatlandırma", + "owner_removeText": "Sahipler", + "owner_removePendingText": "Bekleniyor", + "owner_unknownUser": "bilinmiyor", + "team_inviteModalButton": "Davet et", + "team_cat_general": "Hakkında", + "team_cat_create": "Yeni", + "team_cat_members": "Üyeler", + "team_cat_drive": "Drive", + "team_cat_admin": "Yönetim", + "team_rosterPromote": "Promote", + "team_rosterDemote": "Demote", + "team_owner": "Sahipler", + "team_admins": "Yöneticiler", + "team_members": "Üyeler", + "broadcast_start": "Başlat", + "broadcast_end": "Bitir", + "kanban_delete": "Sil", + "toolbar_tools": "Araçlar", + "drive_treeButton": "Dosyalar", + "support_cat_other": "Diğer", + "admin_cat_performance": "Performans", + "settings_colortheme_dark": "Koyu", + "ui_ms": "milisaniye", + "form_editor": "Düzenleyici", + "team_inviteFrom": "From:", + "snapshots_delete": "Sil", + "Offline": "Çevrim dışı", + "admin_performanceKeyHeading": "Komut", + "expiredError": "Bu belgenin geçerlilik süresi doldu ve artık mevcut değil.", + "team_viewers": "İzleyiciler", + "oo_refresh": "Yenile", + "access_main": "Erişim", + "calendar_notifications": "Hatırlatıcılar", + "form_poll_day": "Gün", + "form_pollTotal": "Toplam", + "form_text_number": "Sayı", + "form_input_ph_email": "eposta@ornek.com", + "calendar_rec_freq_daily": "gün", + "admin_limitSetNote": "Not", + "tag_edit": "Düzenle", + "form_preview_button": "Ön izleme", + "download_step3": "Dönüştürülüyor...", + "initializing": "Initializing...", + "admin_documentConflict": "Arşiv/geri getir", + "upgradeAccount": "Hesabı yükselt", + "error_incorrectAccess": "Bu sayfaya yalnızca {0} üzerinden erişilebilir.", + "toolbar_preview": "Ön izleme", + "calendar_rec_daily": "Günlük", + "calendar_str_filter": "Filtreler:", + "form_editable_str": "Başvuru", + "admin_cat_network": "Ağ bağlantısı", + "fm_link_type": "Bağlantı", + "ui_archive": "Arşivle", + "admin_totpDisableButton": "Devre dışı bırak", + "printButton": "Yazdır (enter)", + "invalidHashError": "İstediğiniz belgenin bağlantısı geçersiz.", + "deletedFromServer": "Belge yok edildi", + "user_displayName": "Görünen ad", + "printOptions": "Tasarım seçenekleri", + "editShare": "Düzenleme bağlantısı", + "viewShare": "salt-okunur bağlantı", + "okButton": "Tamam (enter)", + "cancelButton": "İptal (esc)", + "show_help_button": "Yardımı göster", + "history_next": "Sonraki sürüm", + "history_prev": "Önceki sürüm", + "history_restoreDone": "Belge geri getirildi", + "pad_mediatagTitle": "Medya-Etiket ayarları", + "pad_mediatagWidth": "Genişlik (px)", + "pad_mediatagHeight": "Yükseklik (px)", + "pad_mediatagRatio": "Oranı koru", + "pad_mediatagOptions": "Resim özellikleri", + "kanban_newBoard": "Yeni Tahta", + "kanban_item": "Öge {0}", + "kanban_todo": "Yapılacaklar", + "kanban_working": "Üzerinden çalışılıyor", + "poll_userPlaceholder": "İsminiz", + "poll_comment_placeholder": "Yorumunuz", + "canvas_delete": "Seçili kısmı sil", + "canvas_opacityLabel": "Opaklık: {0}", + "canvas_widthLabel": "Genişlik: {0}", + "canvas_currentBrush": "Geçerli fırça", + "fm_filesDataName": "Tüm dosyalar", + "ui_more": "Daha fazla", + "fm_newFile": "Yeni belge", + "fm_sharedFolder": "Paylaşılmış dizinler", + "fm_folderName": "Dizin ismi", + "fm_fileName": "Dosya ismi", + "fm_lastAccess": "Son erişim", + "fm_forbidden": "Yasaklı eylem", + "fm_newFolder": "Yeni dizin", + "fm_sharedFolderName": "Paylaşılmış dizinle", + "team_pending": "Davet Edildi", + "team_deleteButton": "Sil", + "team_pendingOwner": "(bekleniyor)", + "teams_table": "Roller", + "teams_table_specific": "İstisnalar", + "teams_table_role": "Rol", + "contacts_mute": "Sessize Al", + "contacts_unmute": "Sesi Aç", + "allow_disabled": "devre dışı", + "access_allow": "Liste", + "accessButton": "Erişim", + "contacts": "Contacts", + "allow_enabled": "etkinleştirildi", + "teams": "Takımlar", + "kanban_title": "Başlık", + "kanban_body": "İçerik", + "kanban_color": "Renk", + "canvas_brush": "Fırça", + "canvas_select": "Seç", + "cba_enable": "Etkinleştir", + "comments_edited": "Düzenlendi", + "comments_submit": "Gönder", + "comments_reply": "Yanıtla", + "comments_resolve": "Çözümle", + "comments_comment": "Yorum", + "fm_sort": "Sırala", + "toolbar_theme": "Tema", + "toolbar_insert": "Insert", + "toolbar_file": "Dosya", + "support_cat_all": "Tüm", + "support_attachments": "Ekler", + "pad_tocHide": "Taslak", + "settings_kanbanTagsAnd": "VE", + "settings_kanbanTagsOr": "VEYA", + "settings_cat_kanban": "Kanban", + "history_restore": "Geri Getir", + "history_close": "Kapat", + "snaphot_title": "Anlık Görüntü Al", + "snapshots_button": "Anlık Görüntüler", + "snapshots_open": "Aç", + "snapshots_restore": "Geri Getir", + "snapshots_close": "Kapat", + "oo_version_latest": "En son", + "oo_version": "Versiyon: ", + "team_exportButton": "İndir", + "tag_add": "Ekle", + "admin_archiveButton": "Arşivle", + "admin_unarchiveButton": "Geri Getir", + "mediatag_saveButton": "Kaydet", + "admin_support_open": "Göster", + "admin_support_collapse": "Daralt", + "docs_link": "Belgeleme (Dokümantasyon)", + "settings_cacheTitle": "Önbellek", + "undo": "Geri Al", + "redo": "Yeniden Yap", + "admin_performanceProfilingTitle": "Performans", + "admin_performancePercentHeading": "Yüzde", + "settings_cat_style": "Görünüm", + "settings_colortheme_light": "Açık", + "pad_settings_hide": "Gizle", + "pad_settings_show": "Göster", + "settings_colortheme_custom": "Özel", + "admin_cat_broadcast": "Broadcast", + "admin_maintenanceTitle": "Bakım", + "admin_surveyTitle": "Anket", + "admin_surveyCancel": "Kaldır", + "admin_broadcastButton": "Gönder", + "broadcast_translations": "Çeviriler", + "footer_roadmap": "Roadmap", + "calendar_before": "önceki", + "calendar": "Takvim", + "calendar_day": "Gün", + "calendar_week": "Hafta", + "calendar_month": "Ay", + "calendar_today": "Bugün", + "calendar_update": "Güncelle", + "calendar_title": "Başlık", + "calendar_loc": "Konum", + "form_required_answer": "Cevap: ", + "form_required_on": "Gerekli", + "form_required_off": "Opsiyonel", + "admin_usersRemove": "Kaldır", + "calendar_minutes": "Dakika", + "calendar_hours": "Saat", + "calendar_days": "Gün", + "calendar_noNotification": "None", + "mediatag_defaultImageName": "resim", + "share_formEdit": "Yazar", + "share_formAuditor": "Denetçi", + "share_formView": "Katılımcı", + "form_editBlock": "Düzenle", + "form_poll_time": "Zaman", + "form_text_url": "Bağlantı", + "form_text_text": "Metin", + "form_poll_text": "Metin", + "form_text_email": "E-posta", + "form_type_input": "Metin", + "form_type_textarea": "Paragraf", + "form_type_radio": "Seçim", + "form_type_checkbox": "Checkbox", + "form_type_poll": "Anket", + "form_type_md": "Açıklama", + "form_submit": "Gönder", + "form_update": "Güncelle", + "form_reset": "Sıfırla", + "form_delete": "Sil", + "form_viewButton": "Görüntüle", + "form_backButton": "Geri", + "form_input_ph_url": "https://ornek.com", + "form_open": "Aç", + "form_anonymous_on": "İzin verildi", + "form_anonymous_off": "Blocked", + "form_clear": "Temizle", + "fm_link_url": "Bağlantı", + "ui_collapse": "Daralt", + "ui_expand": "Genişlet", + "form_condition_is": "dır", + "form_condition_has": "sahiptir", + "admin_archiveNote": "Not", + "support_cat_document": "Belge", + "admin_noticeTitle": "Ana sayfa bildirimi", + "home_morestorage": "Daha fazla depolama alanı için:", + "admin_cat_database": "Veri tabanı", + "ui_true": "doğru", + "ui_false": "yanlış", + "ui_undefined": "bilinmiyor", + "ui_none": "none", + "ui_success": "Başarılı", + "ui_restore": "Geri Getir", + "ui_fetch": "Fetch", + "ui_confirm": "Onayla", + "admin_documentCreationTime": "Oluşturuldu", + "admin_channelAvailable": "Uygun", + "admin_channelArchived": "Arşivlendi", + "fm_filterBy": "Filtre", + "calendar_rec": "Tekrarla", + "calendar_rec_custom": "Özel", + "calendar_rec_freq_weekly": "hafta", + "calendar_rec_freq_monthly": "ay", + "calendar_rec_freq_yearly": "yıl", + "calendar_rec_until_no": "Asla", + "calendar_rec_until_count": "Sonra", + "calendar_rec_until_count2": "kere", + "calendar_nth_1": "ilk", + "calendar_nth_2": "ikinci", + "calendar_nth_3": "üçüncü", + "calendar_nth_4": "dördüncü", + "calendar_nth_last": "en son", + "calendar_nth_5": "beşinci", + "form_condorcetSchulze": "Schulze", + "form_showCondorcetWinner": "kazanan: ", + "form_showDetails": "Detaylar", + "form_type_date": "Tarih", + "done": "Tamamlandı", + "continue": "Devam et", + "goLeft": "Sol", + "goRight": "Sağ", + "date": "Tarih", + "calendar_desc": "Açıklama", + "calendar_description": "Açıklama:{0}{1}", + "duplicate": "Kopya", + "admin_cat_security": "Güvenlik", + "admin_cat_customize": "Özelleştir", + "support_cat_open": "Gelen kutusu", + "support_cat_search": "Ara", + "support_cat_closed": "Kapatıldı", + "support_cat_settings": "Ayarlar", + "support_cat_legacy": "Eskiden kalma", + "support_pending_tag": "Arşivlendi", + "support_active_tag": "Gelen Kutusu", + "support_closed_tag": "Kapatıldı", + "support_recordedTitle": "Kod parçacıkları", + "support_recordedContent": "İçerik", + "moderationPage": "Yardım-masası", + "install_header": "Yükleme", + "admin_cat_apps": "Uygulamalar", + "fm_noname": "Başlıksız Belge", + "fm_originalPath": "Orijinal yol", + "fm_viewListButton": "Liste görünümü", + "fm_viewGridButton": "Tablo görünümü", + "fm_tags_name": "Etiket ismi", + "fm_passwordProtected": "Parola korundu", + "fc_newfolder": "Yeni dizin", + "fc_color": "Rengi değiştir", + "fc_open_ro": "Aç (salt-okunur)", + "fc_expandAll": "Hepsini genişlet", + "fc_collapseAll": "Hepsini daralt", + "login_login": "Giriş", + "login_register": "Kayıt ol", + "logoutButton": "Çıkış", + "login_invalUser": "Kullanıcı adı gerekli", + "login_invalPass": "Parola gerekli", + "settings_cat_pad": "Zengin metin", + "settings_export_compressing": "Veri sıkıştırılıyor...", + "settings_exportError": "Hataları görüntüle", + "settings_resetNewTitle": "CryptDrive'ı Temizle", + "settings_importDone": "İçeri aktarma tamamlandı", + "settings_deleteTitle": "Hesap silme", + "settings_logoutEverywhereButton": "Çıkış", + "settings_driveDuplicateLabel": "Kopyaları gizle", + "settings_ownDriveTitle": "Hesabı Güncelle", + "settings_changePasswordButton": "Parola değiştir", + "settings_changePasswordCurrent": "Şuanki parola", + "settings_changePasswordNew": "Yeni parola", + "settings_cursorColorTitle": "İmleç rengi", + "settings_cursorShowLabel": "İmleçleri göster", + "upload_title": "Dosya yükleme", + "upload_modal_owner": "Sahip olunan dosya", + "uploadFolder_modal_filesPassword": "Dosya parolası" } diff --git a/www/common/translations/messages.zh.json b/www/common/translations/messages.zh.json index d3c10c419..c25eb1c22 100644 --- a/www/common/translations/messages.zh.json +++ b/www/common/translations/messages.zh.json @@ -20,7 +20,7 @@ "diagram": "图表" }, "common_connectionLost": "伺服器連線中斷
現在是唯讀狀態,直到連線恢復正常。", - "typeError": "此文档与所选应用进程不兼容", + "typeError": "此文档与所选应用不兼容", "onLogout": "您已退出登录,{0}点击此处{1}登录
或按 Esc 以只读模式访问您的文档。", "loading": "載入中...", "error": "錯誤", diff --git a/www/cryptpad-api.js b/www/cryptpad-api.js index c398cdb54..af56913e5 100644 --- a/www/cryptpad-api.js +++ b/www/cryptpad-api.js @@ -227,7 +227,7 @@ cb(); }); chan.on('ON_INSERT_IMAGE', function(data, cb) { - if (config.events.onIntertImage) { + if (config.events.onInsertImage) { config.events.onInsertImage(data, cb); } else { cb(); } }); @@ -381,5 +381,3 @@ window.CryptPadAPI = factory(); } }()); - - diff --git a/www/form/app-form.less b/www/form/app-form.less index 00fdfafb2..2042999ce 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -980,6 +980,7 @@ .cp-radio, .cp-checkmark { display: inline-flex; max-width: 100%; + padding: 0.313rem 0; } .cp-checkmark-label { word-break: break-word; @@ -1043,7 +1044,7 @@ } .cp-form-sort-order { border: 1px solid @cryptpad_text_col; - padding: 0 5px; + padding: 0 0.313rem; margin-right: 5px; } &:hover { @@ -1318,6 +1319,22 @@ } } } + .cp-radio { + margin: 0.2rem 0; + } + .cp-form-status { + margin-bottom: 0.2rem; + } + .cp-form-mute-radio { + margin-top: 0.2rem; + } + .cp-form-privacy-container { + margin-top: 0.8rem + } + .cp-form-results-type { + display: inline-block; + margin: 0.2rem 0 0.2rem 0; + } } } & > .flatpickr-calendar { diff --git a/www/form/inner.js b/www/form/inner.js index 3428d98b6..661b0ee98 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1097,6 +1097,11 @@ define([ block = h('div.cp-form-edit-options-block', [t]); cm = SFCodeMirror.create("gfm", CMeditor, t); editor = cm.editor; + editor.setOption("extraKeys", { + "Esc": function () { + editor.display.input.blur(); + }, + }); editor.setOption('lineNumbers', true); editor.setOption('lineWrapping', true); editor.setOption('styleActiveLine', true); @@ -4928,7 +4933,7 @@ define([ // End date / Closed state var endDateContainer = h('div.cp-form-status-container'); - var endDateStr = h('div'); + var endDateStr = h('div.cp-form-status'); var $endDate = $(endDateContainer); var $endDateStr = $(endDateStr); diff --git a/www/form/templates.js b/www/form/templates.js index 0bc17d352..631246983 100644 --- a/www/form/templates.js +++ b/www/form/templates.js @@ -44,7 +44,10 @@ define([ } } }, - order: ["1", "2"] + order: ["1", "2"], + metadata: { + title: Messages.form_template_poll + } } }]; }); diff --git a/www/kanban/jkanban_cp.js b/www/kanban/jkanban_cp.js index 1b3a9967b..f6411e36e 100644 --- a/www/kanban/jkanban_cp.js +++ b/www/kanban/jkanban_cp.js @@ -110,6 +110,7 @@ define([ var boardContainerOuter = document.createElement('div'); boardContainerOuter.classList.add('kanban-container-outer'); var boardContainer = document.createElement('div'); + boardContainer.setAttribute('id', 'kanban-container'); boardContainer.classList.add('kanban-container'); boardContainerOuter.appendChild(boardContainer); self.container = boardContainer; @@ -737,6 +738,15 @@ define([ return boardNode; }; + + let reorder = () => { + // Push "add" button to the end of the list + let add = document.getElementById('kanban-addboard'); + let list = document.getElementById('kanban-container'); + if (!add || !list) { return; } + list.appendChild(add); + }; + this.addBoard = function (board) { if (!board || !board.id) { return; } // We need to store all the columns in _boards too because it's used to @@ -757,6 +767,7 @@ define([ _boards.list.push(board.id); var boardNode = getBoardNode(board); self.container.appendChild(boardNode); + reorder(); }; this.addBoards = function() { @@ -824,6 +835,7 @@ define([ $('.kanban-board[data-id="'+id+'"] .kanban-drag').scrollTop(scroll[id]); }); $el.scrollLeft(scrollLeft); + reorder(); }; // If the tab is not focused, redraw on focus diff --git a/www/pad/export.js b/www/pad/export.js index 6e9de71c1..5e5a23689 100644 --- a/www/pad/export.js +++ b/www/pad/export.js @@ -94,9 +94,59 @@ define([ return void cb(blob); } if (ext === ".md") { + let strikethrough = { + filter: ['s', 'del', 'strike'], + replacement: function (content) { + return '~' + content + '~'; + } + }; + let underline = { + filter: ['u'], + replacement: function (content) { + return '' + content + ''; + } + }; var md = Turndown({ headingStyle: 'atx' - }).turndown(toExport); + }).addRule('table', { + filter: ['table'], + replacement: function (content, node) { + var childNodeArr = Array.from(node.childNodes); + var table = ''; + childNodeArr.forEach(function(rowNode) { + rowNode.childNodes.forEach(function(childNode) { + var rowContent = Array.from(childNode.childNodes); + var indexOf = Array.prototype.indexOf; + var index = childNodeArr.length > 1 ? indexOf.call(node.childNodes, rowNode) : indexOf.call(rowNode.childNodes, childNode); + var row = '|'; + var rowLength = rowContent.filter(Boolean).length; + for (var i =0; i < rowLength; i++) { + var cell = rowContent[i]; + var cellContent = Array.from(cell.childNodes); + if ((cellContent.length === 1 && cellContent[0].nodeName === "BR") || !cellContent.length) { + row += '|'; + } else if (cellContent.length >= 1) { + row += Turndown({ + headingStyle: 'atx' + }).addRule('strikethrough', strikethrough) + .addRule('underline', underline) + .turndown(cell.innerHTML).replaceAll('\n', '
'); + row += '|'; + } + } + var newRow = row.concat('\n'); + if (index === 0) { + var separator = '|-'; + newRow += `${separator.repeat(rowLength)}|\n`; + } + table += newRow; + return newRow; + }); + }); + return table; + }}).addRule('strikethrough', strikethrough) + .addRule('underline', underline) + .turndown(toExport); var mdBlob = new Blob([md], { type: 'text/markdown;charset=utf-8' });