From 411039abebbb37406773348ff19070c9ca1b349c Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 27 Jun 2024 16:26:57 +0200 Subject: [PATCH 001/179] Add support for a serverside crypto plugin --- lib/crypto.js | 24 ++++++++++++++++ lib/workers/db-worker.js | 11 ++++++-- scripts/testcrypto.js | 61 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 lib/crypto.js create mode 100644 scripts/testcrypto.js diff --git a/lib/crypto.js b/lib/crypto.js new file mode 100644 index 000000000..9219f7c5f --- /dev/null +++ b/lib/crypto.js @@ -0,0 +1,24 @@ +const Nacl = require('tweetnacl/nacl-fast'); +const CPCrypto = module.exports; +const plugins = require('./plugin-manager'); + +CPCrypto.init = (cb) => { + const crypto = {}; + crypto.open = (signedMsg, validateKey) => { + return Nacl.sign.open(signedMsg, validateKey); + }; + crypto.detachedVerify = (signedBuffer, signatureBuffer, validateKey) => { + return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer); + }; + if (plugins.SODIUM && plugins.SODIUM.crypto) { + let c = plugins.SODIUM.crypto; + if (c.open) { crypto.open = c.open; } + if (c.detachedVerify) { crypto.detachedVerify = c.detachedVerify; } + } + + // Make async because we might need it later with libsodium's promise + // libsodium.ready.then(() => {}); + setTimeout(() => { + cb(void 0, crypto); + }); +}; diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 63b2a8497..398260d61 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -16,6 +16,7 @@ const Logger = require("../log"); const Tasks = require("../storage/tasks"); const Nacl = require('tweetnacl/nacl-fast'); const Eviction = require("../eviction"); +const CPCrypto = require('../crypto'); const Env = { Log: {}, @@ -101,6 +102,10 @@ const init = function (config, _cb) { } Env.tasks = tasks; })); + }).nThen(function (w) { + CPCrypto.init(w(function (err, crypto) { + Env.crypto = crypto; + })); }).nThen(function () { cb(); }); @@ -680,7 +685,8 @@ COMMANDS.INLINE = function (data, cb) { return void cb("E_BADKEY"); } // validate the message - const validated = Nacl.sign.open(signedMsg, validateKey); + //const validated = Nacl.sign.open(signedMsg, validateKey); + const validated = Env.crypto.open(signedMsg, validateKey); if (!validated) { return void cb("FAILED"); } @@ -720,7 +726,8 @@ const checkDetachedSignature = function (signedMsg, signature, publicKey) { throw new Error("INVALID_SIGNATURE_LENGTH"); } - if (Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer) !== true) { + //if (Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer) !== true) { + if (Env.crypto.detachedVerify(signedBuffer, signatureBuffer, pubBuffer) !== true) { throw new Error("FAILED"); } }; diff --git a/scripts/testcrypto.js b/scripts/testcrypto.js new file mode 100644 index 000000000..893ab6ec8 --- /dev/null +++ b/scripts/testcrypto.js @@ -0,0 +1,61 @@ +let SodiumNative = require('sodium-native'); +let Nacl = require('tweetnacl/nacl-fast'); +let LibSodium = require('libsodium-wrappers'); + + +let msgStr = "This is a test"; +let keys = Nacl.sign.keyPair(); +let pub = keys.publicKey; + +let msg = Nacl.util.decodeUTF8(msgStr); +let signedMsg = Nacl.sign(msg, keys.secretKey); +let sig = signedMsg.subarray(0, 64); + +LibSodium.ready.then(() => { + +/* +console.log('tweetnacl open'); +console.log(!!Nacl.sign.open(signedMsg, pub)); +console.log('tweetnacl detached'); +console.log(Nacl.sign.detached.verify(msg, sig, pub)); +console.log('sodium-native open'); +console.log(SodiumNative.crypto_sign_open(msg, signedMsg, pub)); +console.log('sodium-native detached'); +console.log(SodiumNative.crypto_sign_verify_detached(sig, msg, pub)); +LibSodium.ready.then(() => { +console.log('libsodium open'); +console.log(!!LibSodium.crypto_sign_open(signedMsg, pub)); +console.log('libsodium detached'); +console.log(LibSodium.crypto_sign_verify_detached(sig, msg, pub)); +}); +*/ + + const n = 10000; + let a; + + console.log('start sodium-native'); + a = +new Date(); + for (var i = 0; i < n; i++) { + SodiumNative.crypto_sign_open(msg, signedMsg, pub); + SodiumNative.crypto_sign_verify_detached(sig, msg, pub); + } + console.log('end sodium-native ', (+new Date() - a), ' ms'); + + console.log('start libsodium'); + a = +new Date(); + for (var i = 0; i < n; i++) { + LibSodium.crypto_sign_open(signedMsg, pub); + LibSodium.crypto_sign_verify_detached(sig, msg, pub); + } + console.log('end libsodium ', (+new Date() - a), ' ms'); + + console.log('start tweetnacl'); + a = +new Date(); + for (var i = 0; i < n; i++) { + Nacl.sign.open(signedMsg, pub); + Nacl.sign.detached.verify(msg, sig, pub); + } + + console.log('end tweetnacl ', (+new Date() - a), ' ms'); +}); + From 5383f9ef1c681e1874aeeaac602019d93b2d302c Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 4 Jul 2024 11:33:43 +0200 Subject: [PATCH 002/179] Fix potential memory leak --- lib/api.js | 3 +++ lib/hk-util.js | 1 + lib/storage/file.js | 13 +++++++++++++ 3 files changed, 17 insertions(+) diff --git a/lib/api.js b/lib/api.js index c0e570095..bccf917f8 100644 --- a/lib/api.js +++ b/lib/api.js @@ -190,6 +190,9 @@ nThen(function (w) { removed++; } }); + if (Env.store) { + Env.store.closeInactiveChannels(active); + } if (removed) { Env.Log.info("CLEANED_ACTIVE_CHANNELS_MAP", {removed}); } diff --git a/lib/hk-util.js b/lib/hk-util.js index 7080d3d4a..1bc7f2022 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -146,6 +146,7 @@ const dropChannel = HK.dropChannel = function (Env, chanName) { expireChannel(Env, chanName); }, TEMPORARY_CHANNEL_LIFETIME); } + store.closeChannel(chanName, function () {}); }; /* checkExpired diff --git a/lib/storage/file.js b/lib/storage/file.js index 2c2888f7a..98cbfd7db 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -286,6 +286,16 @@ var closeChannel = function (env, channelName, cb) { } }; +var closeInactiveChannels = function (env, schedule, active) { + Object.keys(env.channels).forEach(channelName => { + if (!active.includes(channelName)) { + schedule.ordered(channelName, function (next) { + closeChannel(env, channelName, next); + }); + } + }); +}; + var clearOffset = function (env, channelId, cb) { var path = mkOffsetPath(env, channelId); // we should always be able to recover from invalid offsets, so failure to delete them @@ -1445,6 +1455,9 @@ module.exports.create = function (conf, _cb) { closeChannel(env, channelName, Util.both(cb, next)); }); }, + closeInactiveChannels: function (active) { + closeInactiveChannels(env, schedule, active); + }, // write to a log file log: function (channelName, content, cb) { // you probably want the events in your log to be in the correct order. From a7e622dddcf945f3bbcaf11ee1baac982d108846 Mon Sep 17 00:00:00 2001 From: Corentin ARNOULD Date: Sat, 6 Jul 2024 10:23:49 +0200 Subject: [PATCH 003/179] Fix bash indentation and trailing whitespaces Some shell scripts had tabs indentation. Made it all four spaces. Hope it's ok with spaces. Some files had a trailing space in it. It was not useful and takes few bytes for nothing. I didn't delete everything. You can find all tab indented lines with: grep -rP '^\t' 2>/dev/null And more trailing space with: grep -rP ' $' 2>/dev/null --- CHANGELOG.md | 4 ++-- Dockerfile | 2 +- LICENSES/BSD-3-Clause.txt | 2 +- LICENSES/MPL-2.0.txt | 2 +- docker-entrypoint.sh | 6 +++--- readme.md | 2 +- scripts/convert-favicons-to-ico.sh | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be2161b23..5b4da42a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ This release introduces a new onboarding flow to guide administrators through th - Onboarding screens & app configuration [#1513](https://github.com/cryptpad/cryptpad/pull/1513) - Bahasa Indonesia is a new available language [fe78b6a](https://github.com/cryptpad/cryptpad/commit/fe78b6ab1dc76ce9eb8d5361c309db8e92117fa8) - - Thanks to our [Weblate](https://weblate.cryptpad.org) contributors who made that happen! + - Thanks to our [Weblate](https://weblate.cryptpad.org) contributors who made that happen! ## Improvements @@ -46,7 +46,7 @@ This release introduces a new onboarding flow to guide administrators through th - Switch to new `http2` Nginx option [#1516](https://github.com/cryptpad/cryptpad/pull/1516) - Server fixes and aggregated stats [#1509](https://github.com/cryptpad/cryptpad/pull/1509) - Create the block folder at boot [#911](https://github.com/cryptpad/cryptpad/pull/911) - - Remove obsolete `version` from `docker-compose.yml` [2e716eb](https://github.com/cryptpad/cryptpad/commit/2e716eb4e39fb835f95a1fa1a340e01142d11b1c) + - Remove obsolete `version` from `docker-compose.yml` [2e716eb](https://github.com/cryptpad/cryptpad/commit/2e716eb4e39fb835f95a1fa1a340e01142d11b1c) - Other - Unsharp the corners when hovering the dismiss button on notification drop-down menu [#1466](https://github.com/cryptpad/cryptpad/pull/1466) - Fix contextual menu `Open` on anonymous drive [#1464](https://github.com/cryptpad/cryptpad/pull/1464) diff --git a/Dockerfile b/Dockerfile index e2be11805..c6d343942 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ COPY . /cryptpad RUN sed -i "s@//httpAddress: 'localhost'@httpAddress: '0.0.0.0'@" /cryptpad/config/config.example.js RUN sed -i "s@installMethod: 'unspecified'@installMethod: 'docker'@" /cryptpad/config/config.example.js - + # Install dependencies RUN npm install --production \ && npm run install:components diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt index ea890afbc..086d3992c 100644 --- a/LICENSES/BSD-3-Clause.txt +++ b/LICENSES/BSD-3-Clause.txt @@ -1,4 +1,4 @@ -Copyright (c) . +Copyright (c) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/LICENSES/MPL-2.0.txt b/LICENSES/MPL-2.0.txt index ee6256cdb..d0a1fa148 100644 --- a/LICENSES/MPL-2.0.txt +++ b/LICENSES/MPL-2.0.txt @@ -35,7 +35,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 3429b90f6..59972bac6 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -22,16 +22,16 @@ if [ ! -f "$CPAD_CONF" ]; then eg: docker run -v /path/to/config.js:/cryptpad/config/config.js \n\ #################################################################### \n" - cp "$CPAD_HOME"/config/config.example.js "$CPAD_CONF" + cp "$CPAD_HOME"/config/config.example.js "$CPAD_CONF" - sed -i -e "s@\(httpUnsafeOrigin:\).*[^,]@\1 '$CPAD_MAIN_DOMAIN'@" \ + sed -i -e "s@\(httpUnsafeOrigin:\).*[^,]@\1 '$CPAD_MAIN_DOMAIN'@" \ -e "s@\(^ *\).*\(httpSafeOrigin:\).*[^,]@\1\2 '$CPAD_SANDBOX_DOMAIN'@" "$CPAD_CONF" fi cd $CPAD_HOME if [ "$CPAD_INSTALL_ONLYOFFICE" == "yes" ]; then - ./install-onlyoffice.sh --accept-license + ./install-onlyoffice.sh --accept-license fi npm run build diff --git a/readme.md b/readme.md index d5766eed6..f24355c3d 100644 --- a/readme.md +++ b/readme.md @@ -28,7 +28,7 @@ The most recent version and all past release notes can be found on the [releases ## Setup using Docker -You can find `Dockerfile`, `docker-compose.yml` and `docker-entrypoint.sh` files at the root of this repository. We also publish every release on [Docker Hub](https://hub.docker.com/r/cryptpad/cryptpad) as AMD64 & ARM64 official images. +You can find `Dockerfile`, `docker-compose.yml` and `docker-entrypoint.sh` files at the root of this repository. We also publish every release on [Docker Hub](https://hub.docker.com/r/cryptpad/cryptpad) as AMD64 & ARM64 official images. Previously, Docker images were community maintained, had their own repository and weren't official supported. We changed that with v5.4.0 during July 2023. Thanks to @promasu for all the work on the community images. diff --git a/scripts/convert-favicons-to-ico.sh b/scripts/convert-favicons-to-ico.sh index 6f6980876..972b93df7 100755 --- a/scripts/convert-favicons-to-ico.sh +++ b/scripts/convert-favicons-to-ico.sh @@ -5,6 +5,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later for f in ../customize.dist/favicon/*.png; do - base="$(basename $f ".png")" - magick convert $f -define icon:auto-resize=16,24,32,48,64,72,96,128,256 "$base.ico" + base="$(basename $f ".png")" + magick convert $f -define icon:auto-resize=16,24,32,48,64,72,96,128,256 "$base.ico" done From 9c032931d6560239e4c389712830e2ee201c05e9 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Tue, 9 Jul 2024 16:26:26 +0300 Subject: [PATCH 004/179] Add confirmation modal + logic --- www/admin/inner.js | 80 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index d513ab0b1..5ae30471a 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -578,23 +578,77 @@ define([ return APP.instanceStatus.enforceMFA; }, query: function (val, setState) { - sFrameChan.query('Q_ADMIN_RPC', { - cmd: 'ADMIN_DECREE', - data: ['ENFORCE_MFA', [val]] - }, function (e, response) { - if (e || response.error) { - UI.warn(Messages.error); - console.error(e, response); + var isChecked = APP.instanceStatus.enforceMFA; + var confirmationContent = isChecked + ? 'Are you sure you want to disable enforced MFA? This action would lessen the security of your account.' + : 'Are you sure you want to enforce MFA? This action would require to set up an authenticator app.'; + + function showConfirmationModal(callback) { + var modal = UI.dialog.customModal(confirmationContent, { + buttons: [{ + className: 'cancel', + name: Messages.cancel, + onClick: function () { + if (!isChecked) { + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: ['ENFORCE_MFA', [false]] + }, function (e, response) { + if (e || response.error) { + UI.warn(Messages.error); + console.error(e, response); + } else { + APP.updateStatus(function () { + setState(false); + flushCache(); + }); + } + }); + } + //check the checkbox again + else { + APP.updateStatus(function () { + setState(APP.instanceStatus.enforceMFA); + flushCache(); + }); + } + }, + keys: [27] // Esc key to close modal + }, { + className: 'primary', + name: Messages.settings_save, + onClick: function () { + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: ['ENFORCE_MFA', [val]] + }, function (e, response) { + if (e || response.error) { + UI.warn(Messages.error); + console.error(e, response); + } else { + APP.updateStatus(function () { + setState(APP.instanceStatus.enforceMFA); + flushCache(); + }); + } + }); + }, + keys: [13] // Enter key to confirm + }] + }); + var $modal = $(modal); + UI.openCustomModal(modal); + $modal.closest('.alertify').on('mousedown', function (e) { + e.stopPropagation(); + }); } - APP.updateStatus(function () { - setState(APP.instanceStatus.enforceMFA); - flushCache(); - }); - }); - }, + + showConfirmationModal(); + } }); + var getInstanceString = function (attr) { var val = APP.instanceStatus[attr]; var type = typeof(val); From e43b16a6ee5089457dec806a14e7b867d3a7ca7c Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:24:17 +0300 Subject: [PATCH 005/179] Add responsive styling to performance table --- .../src/less2/include/sidebar-layout.less | 22 +++++++++++++++++++ www/admin/inner.js | 2 ++ 2 files changed, 24 insertions(+) diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index 5b616e0e8..eeb5da80a 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -194,6 +194,28 @@ background-color: @cp_sidebar-left-item-bg; } } + + } + .cp-sidebar-table#performance-profiling-table { + @media (max-width: 900px) { + width: 100%; + + tr { + display: flex; + flex-wrap: wrap; + align-items: center; + } + + th, td { + border: none; + flex: 1 1 auto; + width: 5rem; + margin-right: 0; + font-size: 13px; + word-wrap: break-word; + white-space: normal; + } + } } .cp-sidebar-input-block { display: inline-flex; diff --git a/www/admin/inner.js b/www/admin/inner.js index d513ab0b1..7cb627abf 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -3596,6 +3596,8 @@ define([ var table = blocks.table(header, []); + table.id = 'performance-profiling-table'; + const onRefresh = function () { sFrameChan.query('Q_ADMIN_RPC', { cmd: 'GET_WORKER_PROFILES', From 7c57db6420b40b9daa27ed3b45cdd5a9df262f4f Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 10 Jul 2024 16:27:41 +0300 Subject: [PATCH 006/179] change focus style for inputs on calendar modals #1506 --- customize.dist/src/less2/include/forms.less | 3 + www/calendar/app-calendar.less | 740 -------------------- 2 files changed, 3 insertions(+), 740 deletions(-) delete mode 100644 www/calendar/app-calendar.less diff --git a/customize.dist/src/less2/include/forms.less b/customize.dist/src/less2/include/forms.less index 065b9db1d..5d8b242f1 100644 --- a/customize.dist/src/less2/include/forms.less +++ b/customize.dist/src/less2/include/forms.less @@ -28,6 +28,9 @@ } &.tui-full-calendar-content { font-size: @colortheme_app-font-size; + &:focus { + outline: @cryptpad_color_brand solid 2px; + } } &[readonly] { //margin-top:1rem; diff --git a/www/calendar/app-calendar.less b/www/calendar/app-calendar.less deleted file mode 100644 index bdf59fb6d..000000000 --- a/www/calendar/app-calendar.less +++ /dev/null @@ -1,740 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 XWiki CryptPad Team and contributors - * - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -@import (reference) '../../customize/src/less2/include/framework.less'; -@import (reference) '../../customize/src/less2/include/sidebar-layout.less'; -@import (reference) '../../customize/src/less2/include/tools.less'; -@import (reference) '../../customize/src/less2/include/avatar.less'; -@import (reference) '../../customize/src/less2/include/variables.less'; - -&.cp-app-calendar { - - .framework_min_main(); - .sidebar-layout_main(); - - display: flex; - flex-flow: column; - - .cp-toolbar-bottom-mid > div { - color: @cryptpad_text_col; - .cp-small { display: none; } - } - - .flatpickr-calendar { - z-index: 100001 !important; // Alertify is 100000 - } - #cp-sidebarlayout-container #cp-sidebarlayout-rightside { - padding: 0; - & > div { - margin: 0; - } - - .cp-forcehide { - display: none !important; - } - - - .tui-full-calendar-confirm { - span, i { - padding: 0.5rem; - } - span { - padding-left: 0; - } - width: unset; - } - - .tui-full-calendar-layout { - background-color: @cp_sidebar-right-bg !important; - color: @cryptpad_text_col; - display: flex; - flex-flow: column; - .tui-full-calendar-week-container { - min-height: 0; - display: flex; - flex-flow: column; - .tui-full-calendar-vlayout-area { - display: flex; - flex-flow: column; - flex: 1; - min-height: 0; - & > div:last-child { - flex: 1; - min-height: 0; - } - } - } - .tui-full-calendar-weekday-filled { - background-color: @cp_dropdown-bg-hover !important; - } - - .tui-full-calendar-timegrid-hourmarker-time { - color: @cp_calendar-now !important; - } - .tui-full-calendar-timegrid-hourmarker-line-left, .tui-full-calendar-timegrid-hourmarker-line-today { - border-color: @cp_calendar-now !important; - } - .tui-full-calendar-timegrid-todaymarker { - background-color: @cp_calendar-now !important; - } - - .tui-full-calendar-month { - display: flex; - flex-flow: column; - & > div:last-child { - display: flex; - flex-flow: column; - flex: 1; - min-height: 0; - overflow: hidden; - } - .tui-full-calendar-today .tui-full-calendar-weekday-grid-date-decorator { - background-color: @cp_calendar-now !important; - color: @cp_calendar-now-fg !important; - } - .tui-full-calendar-weekday-schedule-time .tui-full-calendar-weekday-schedule-title { - color: @cryptpad_text_col !important; - } - .tui-full-calendar-extra-date { - .tui-full-calendar-weekday-grid-date { - color: @cp_sidebar-hint !important; - opacity: 0.5; - } - } - .tui-full-calendar-weekday-grid-date { - color: @cryptpad_text_col !important; - } - .tui-full-calendar-month-dayname-item span { - color: @cryptpad_text_col !important; - } - } - .tui-full-calendar-dayname * { - color: @cryptpad_text_col !important; - } - .tui-full-calendar-month-more { - background-color: @cp_sidebar-right-bg !important; - color: @cryptpad_text_col; - span { - color: @cryptpad_text_col !important; - } - } - - .tui-full-calendar-floating-layer.cp-calendar-popup-flex { - top: 0 !important; - left: 0 !important; - right: 0 !important; - bottom: 0 !important; - justify-content: center !important; - align-items: center !important; - .tui-full-calendar-popup { - width: 540px; - max-width: 100%; - max-height: 100%; - } - } - #tui-full-calendar-popup-arrow { - display: none !important; - } - } - .tui-full-calendar-timegrid-timezone { - background-color: @cp_sidebar-right-bg !important; - .tui-full-calendar-timegrid-hour { - color: @cryptpad_text_col !important; - } - color: @cryptpad_text_col; - } - .tui-full-calendar-timegrid-gridline, .tui-full-calendar-time-date { - border-color: @cp_calendar-border !important; - } - .tui-full-calendar-splitter, .tui-full-calendar-left, .tui-full-calendar-dayname-container, .tui-full-calendar-weekday-grid-line { - border-color: @cp_calendar-border !important; - - } - .tui-full-calendar-popup { - border-radius: @variables_radius_L; - } - .tui-full-calendar-popup-container { - min-width: 100%; - background: @cp_flatpickr-bg; - color: @cryptpad_text_col; - border-radius: @variables_radius_L; - font-weight: normal; - .tui-full-calendar-icon:not(.tui-full-calendar-calendar-dot):not(.tui-full-calendar-dropdown-arrow):not(.tui-full-calendar-ic-checkbox):not(.fa-map-marker) { - display: none; - } - .tui-full-calendar-icon { - text-align:center; - } - .tui-full-calendar-popup-detail-item { - a { - color: @cryptpad_color_link; - text-decoration: underline; - } - } - .tui-full-calendar-section-button-save { - height: 40px; - .btn-primary { // Update button - margin-right: 0px; - } - } - - } - li.tui-full-calendar-popup-section-item { - padding: 0 6px; - height: 32px; - } - .tui-full-calendar-popup-section-item { - height: auto; - margin: 0; - &:not(li):not(button) { - padding: 0; - margin-top: 5px; - } - #tui-full-calendar-schedule-calendar { - width: 179px; - top: 0; - } - &:not(button) { - border: none; - display: inline-flex; - align-items: center; - &:hover { - background-color: @cp_dropdown-bg-hover; - } - .tui-full-calendar-content { - text-overflow: ellipsis; - font: @colortheme_app-font; - padding: 0 10px; - } - input { flex: 1; } - } - } - .tui-full-calendar-section-date-dash { - height: auto; - } - .tui-full-calendar-section-title, .tui-full-calendar-section-location, .tui-full-calendar-section-body { - width: 100%; - } - .tui-full-calendar-dropdown-menu { - top: 38px; - width: 221px; // same as button - background-color: @cp_dropdown-bg; - color: @cp_dropdown-fg; - } - .tui-full-calendar-section-state, #tui-full-calendar-schedule-private { - display: none !important; - } - - .tui-full-calendar-popup:not(.tui-full-calendar-popup-detail) { - .tui-full-calendar-section-calendar { - width: 221px; // 50% - } - .tui-full-calendar-popup-section { - display: flex; - align-items: center; - flex-wrap: wrap; - .tui-full-calendar-section-start-date, .tui-full-calendar-section-end-date { - flex: 1; - } - .tui-full-calendar-section-allday { - width: 100%; - height: 32px; - border-radius: @variables_radius; - input[type="checkbox"].tui-full-calendar-checkbox-square:checked + span { - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABbmlDQ1BpY2MAACiRdZHNK0RRGMZ/Zoh8NIqFNItZDFmMEiVLxsJmkgZlsLn3zpe6c93uvZNkq2wspizExtfCf8BW2VJKkZKs/AG+Npqu97hqJM7t3PfXc87zds5zIJQyjZJbPwAly3PSE8nYXGY+1vhEMy20EyaqGa49NjWV4t/xfkOdqtf9qtf/+/4cLdmca0Bdk/CwYTue8KhwasWzFW8KdxpFLSu8L5xw5IDCF0rXA35UXAj4VbEzkx6HkOoZK/xg/QcbRack3CccL5ll4/s86iatOWt2Wmq3zCguaSZIEkOnzBImHv1SLcnsb9/Al2+SZfEY8rdZxRFHgaJ4E6KWpWtOal70nHwmqyr333m6+aHBoHtrEhoefP+lBxq3oFrx/Y8D368eQvgezqyaf1lyGnkTvVLT4nsQWYeT85qmb8PpBnTd2ZqjfUlhmaF8Hp6PoS0DHVfQvBBk9b3O0S3MrMkTXcLOLvTK/sjiJ6CLZ94KREMsAAAACXBIWXMAAAsSAAALEgHS3X78AAABHUlEQVQoFWNkaP//n4EMwESGHrAW6mtkZvz3G2g03BsBagz/nRUQ7sNp49//TJ+Byv6BlMbrMjCsC2Jg3BbKwOAgB9GMolGAg4GBESIOIrmA+A9I03xvFHGwCrhGkDOe5TAw9LvAFbEn6jEwwTT9BtodvJ7h/4FHYH0MLBCKgaHTgYGBE8jLN2FgYAJae+4FA8NcLwZWkAtAmoLWMTBsuYNwECMsHrVEGBj2RzEwiIEciATANgE1bb6DJAgMNLhTr71hYHBcxsDw+htCAQ5NIAU/4RpBPKjmf2++MfwHaQpZD7cJyEMB3+BORRL+rybE8FOEk4Hj2FO4KMgdrFAMitun2DTCVSMxYAkBFFYg9j94qCIpwsZEil5wyDIDAAXIUsnSKmq7AAAAAElFTkSuQmCC); - } - .tui-full-calendar-ic-checkbox { - margin-left: 5px; - border-radius: 2px; - } - } - .CodeMirror { - margin-top: 5px; - background: @cp_forms-bg !important; - color: @cryptpad_text_col; - border: 1px solid @cp_forms-border; - border-radius: @variables_radius; - width: 100%; - height: 80px; - font: @colortheme_app-font; - font-size: 16px; - line-height: initial; - padding-left: 0.3rem; - pre { - margin: 0; - font-family: inherit; - font-size: inherit; - line-height: inherit; - } - } - .CodeMirror-placeholder { - color: @cp_forms-placeholder; - } - } - } - .tui-full-calendar-popup-detail { - font: @colortheme_app-font; - color: @cryptpad_text_col; - box-shadow: @cryptpad_ui_shadow; - .tui-full-calendar-popup-container { - padding-bottom: 17px; - } - .tui-full-calendar-popup-detail-date { - font-size: 14px; - } - .tui-full-calendar-section-button { - margin-top: 10px; - border: 0; - display: flex; - align-items: start; - button { - flex: 1; - margin: 0; - } - } - .tui-full-calendar-popup-top-line { - border-radius: 10px 10px 0px 0px; - height: 10px; - } - .tui-full-calendar-popup-vertical-line { - visibility: hidden; - width: 10px; - } - } - - .cp-recurrence-label, .cp-notif-label { - color: @cryptpad_text_col; - margin-right: 1rem; - i { - margin-right: 0.5rem; - } - } - - .cp-calendar-recurrence-container { - margin-top: 1rem; - .cp-calendar-rec-translated-str { - margin-top: 0.5rem; - } - } - - .cp-calendar-add-notif { - flex-flow: column; - align-items: baseline !important; - margin: 1rem 0; - * { - font-size: @colortheme_app-font-size; - font-weight: normal; - } - & > div { - display: flex; - } - .cp-calendar-notif-list-container { - width: 100%; - margin-bottom: 10px; - .cp-notif-label { - margin-top: 0.5em; - } - } - .cp-calendar-notif-list { - display: flex; - flex-flow: column; - flex: 1; - min-width: 150px; - &:empty { - display: none; - } - .cp-notif-entry { - display: flex; - margin-bottom: 2px; - border-radius: @variables_radius; - background-color: fade(@cryptpad_text_col, 10%); - padding: 0.25rem; - .cp-notif-value { - width: 75%; - display: inline-flex; - line-height: 30px; - vertical-align: middle; - flex-grow: 1; - .cp-before { - flex: 1; - min-width: 0; - } - } - span:not(:last-child) { - margin: 0; - margin-right: 0.3rem; - } - span:first-child { - margin-left: 0.3rem; - } - .btn-danger-outline { - display: block; - margin-right: 0px !important; - background-color: transparent; - color: @cryptpad_text_col; - border-color: @cryptpad_text_col; - &:hover { - color: @cp_buttons-red-color; - background-color: @cp_buttons-red; - border-color: @cp_buttons-red; - } - } - } - } - .cp-notif-empty { - display: none; - margin-bottom: 2px; - border-radius: @variables_radius; - background-color: fade(@cryptpad_text_col, 10%); - padding: 0.25rem 0.5rem; - line-height: 30px; - } - .cp-calendar-notif-list:empty ~ .cp-notif-empty { - display: block; - } - .cp-calendar-notif-form { - align-items: center; - .cp-calendar-notif-form-buttons { - display: inline-flex; - align-items: center; - & > input { - height: 40px; - } - } - // margin-bottom: 20px; - input { - width: 80px; - margin-right: 0.3rem; - } - .fa-plus{ - margin-left:0.3rem; - } - } - } - - .cp-calendar-close { - top: 17px; - right: 17px; - height: auto; - margin-right: 0px; - line-height: initial; - border: 1px solid; - &:not(:hover) { - background: transparent; - } - } - - } - - .cp-calendar-rec-inline, .cp-calendar-rec-block { - &:not(:last-child) { - margin-bottom: 10px; - } - } - .cp-calendar-rec-inline { - display: flex; - flex-flow: row; - align-items: center; - & > *:not(:first-child) { margin-left: 5px; } - .cp-dropdown-container { - position: unset; - } - input[type="number"] { - width: 80px !important; - margin-bottom: 0 !important; - } - .cp-checkmark { - margin-right: 0.5rem; - } - } - .cp-calendar-rec-block { - .cp-calendar-rec-block-title { - margin-bottom: 0.5rem !important; - } - .cp-radio { - margin-bottom: 0.5rem; - } - input[type="radio"]:not(:checked) ~ .cp-checkmark-label { - input { - filter: grayscale(1); - } - } - .cp-checkmark-label { - & > *:not(:first-child) { margin-left: 5px; } - width: 100%; - //height: 26px; - display: flex; - align-items: center; - & > input { - margin-bottom: 0 !important; - } - input { - display: inline; - height: 24px !important; - padding: 0 5px !important; - } - input[type="text"] { - width: 200px !important; - } - input[type="number"] { - width: 80px !important; - margin-bottom: 0 !important; - } - } - } - #cp-calendar-rec-monthly-pick ~ .cp-checkmark-label { - display: flex; - align-items: center; - & > span { - margin-right: 20px; - } - } - button.cp-calendar-pick-el { - display: flex; - align-items: center; - justify-content: center; - &:not(:last-child) { - margin-right: 5px; - } - } - div.cp-calendar-weekly-pick { - button { - width: 50px; - } - } - div.cp-calendar-monthly-pick { - display: flex; - flex-flow: column; - & > div { - display: flex; - &:not(:last-child) { - margin-bottom: 5px; - } - button { - height: 25px; - width: 25px; - &.lastday { - width: 115px; - } - } - } - } - - .tui-full-calendar-ic-repeat-b { - display: none; - & ~ * { - display: none; - } - } - - #cp-toolbar .cp-calendar-browse { - display: flex; - align-items: center; - button { - color: @cp_toolbar-fg; - border-color: @cp_toolbar-fg; - &:hover { - background-color: fade(@cp_toolbar-fg, 50%); - cursor: pointer; - } - } - } - - .cp-calendar-newevent { - &:hover { - cursor: pointer; - } - } - - .cp-toolbar-bottom-right button, .cp-toolbar-user button { - &:hover { - cursor: pointer; - } - } - - #cp-sidebarlayout-leftside { - & > div { - padding: 10px - } - .cp-calendar-new { - display: flex; - align-items: center; - justify-content: space-between; - } - .cp-calendar-list { - overflow-y: auto; - .cp-calendar-team { - height: 30px; - .avatar_main(30px); - .cp-avatar { - margin-right: 10px; - } - .cp-name { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - display: flex; - align-items: center; - justify-content: center; - margin: 5px 0 10px 0; - &:not(:first-child) { - margin-top: 30px; - } - } - .cp-calendar-entry { - display: flex; - align-items: center; - justify-content: space-between; - padding: 5px; - border-radius: @variables_radius; - background-color: @cp_sidebar-left-bg; - &:not(.cp-unclickable) { - cursor: pointer; - } - .cp-dropdown-container { - position: initial; - - .cp-dropdown-content{ - @media screen and (max-width: 600px) - { - left: 50%; - min-width: 45%; - } - } - } - button.cp-calendar-actions { - background-color: transparent; - &:hover { - background-color: @cp_sidebar-left-bg; - } - } - &.cp-ghost { - padding: 0; - button { - .tools_unselectable(); - cursor: pointer; - width: 100%; - display: flex; - justify-content: space-between; - background: transparent; - border: 1px solid @cryptpad_text_col; - border-radius: @variables_radius; - padding: 5px; - height: 36px; - font: @colortheme_app-font; - align-items: center; - color: @cryptpad_text_col; - &:hover { - background-color: @cp_sidebar-left-active; - color: @cp_sidebar-left-active-fg; - border: 0px; - } - i { - margin-left: 5px; - } - } - } - &:not(:last-child) { - margin-bottom: 10px; - } - &:hover { - background: @cp_sidebar-left-item-bg; - } - &.cp-restricted { - color: @cp_drive-header-fg; - } - .cp-calendar-icon { - width: 30px; - display: inline-flex; - height: 30px; - align-items: center; - justify-content: center; - border-radius: @variables_radius; - flex-shrink: 0; - } - &.cp-active { - background-color: @cp_sidebar-left-item-bg; - .cp-calendar-inactive { - display: none; - } - } - &:not(.cp-active) { - .cp-calendar-icon { - background: transparent !important; - } - .cp-calendar-active { - display: none; - } - } - .tools_unselectable(); - .cp-calendar-color { - display: inline-block; - border-radius: 50%; - width: 15px; - height: 15px; - flex-shrink: 0; - } - .cp-calendar-title { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - padding: 0 5px; - } - } - } - } - .cp-calendar-colorpicker { - width: 100px; - height: 25px; - cursor: pointer; - border: 1px solid @cp_forms-border; - } - - @media (max-width: @browser_media-medium-screen) { - .cp-calendar-notif-list-container, .cp-calendar-notif-form { - flex-direction: column; - align-items: unset !important; - } - .cp-calendar-newevent { - i { - margin: 0 !important; - } - span { - display: none; - } - } - .tui-full-calendar-dayname-leftmargin, .tui-full-calendar-timegrid-right { - margin-left: 40px !important; - } - .tui-full-calendar-allday-left, .tui-full-calendar-timegrid-left { - width: 40px !important; - } - .tui-full-calendar-dayname > span { - display: flex; - flex-flow: column; - line-height: 0; - justify-content: center; - align-items: center; - height: 100%; - } - .tui-full-calendar-dayname * { - font-size: 11px; - line-height: initial; - height: auto; - } - .cp-toolbar-bottom-mid > div { - :not(:first-child) { - display: none; - } - :first-child { - display: inline-block; - } - } - } - -} - From 546ccd63f7eaf5f16c974868bb25aa076088a602 Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 10 Jul 2024 16:58:27 +0300 Subject: [PATCH 007/179] Revert "change focus style for inputs on calendar modals #1506" This reverts commit 7c57db6420b40b9daa27ed3b45cdd5a9df262f4f. --- customize.dist/src/less2/include/forms.less | 3 - www/calendar/app-calendar.less | 740 ++++++++++++++++++++ 2 files changed, 740 insertions(+), 3 deletions(-) create mode 100644 www/calendar/app-calendar.less diff --git a/customize.dist/src/less2/include/forms.less b/customize.dist/src/less2/include/forms.less index 5d8b242f1..065b9db1d 100644 --- a/customize.dist/src/less2/include/forms.less +++ b/customize.dist/src/less2/include/forms.less @@ -28,9 +28,6 @@ } &.tui-full-calendar-content { font-size: @colortheme_app-font-size; - &:focus { - outline: @cryptpad_color_brand solid 2px; - } } &[readonly] { //margin-top:1rem; diff --git a/www/calendar/app-calendar.less b/www/calendar/app-calendar.less new file mode 100644 index 000000000..bdf59fb6d --- /dev/null +++ b/www/calendar/app-calendar.less @@ -0,0 +1,740 @@ +/* + * SPDX-FileCopyrightText: 2023 XWiki CryptPad Team and contributors + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +@import (reference) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/sidebar-layout.less'; +@import (reference) '../../customize/src/less2/include/tools.less'; +@import (reference) '../../customize/src/less2/include/avatar.less'; +@import (reference) '../../customize/src/less2/include/variables.less'; + +&.cp-app-calendar { + + .framework_min_main(); + .sidebar-layout_main(); + + display: flex; + flex-flow: column; + + .cp-toolbar-bottom-mid > div { + color: @cryptpad_text_col; + .cp-small { display: none; } + } + + .flatpickr-calendar { + z-index: 100001 !important; // Alertify is 100000 + } + #cp-sidebarlayout-container #cp-sidebarlayout-rightside { + padding: 0; + & > div { + margin: 0; + } + + .cp-forcehide { + display: none !important; + } + + + .tui-full-calendar-confirm { + span, i { + padding: 0.5rem; + } + span { + padding-left: 0; + } + width: unset; + } + + .tui-full-calendar-layout { + background-color: @cp_sidebar-right-bg !important; + color: @cryptpad_text_col; + display: flex; + flex-flow: column; + .tui-full-calendar-week-container { + min-height: 0; + display: flex; + flex-flow: column; + .tui-full-calendar-vlayout-area { + display: flex; + flex-flow: column; + flex: 1; + min-height: 0; + & > div:last-child { + flex: 1; + min-height: 0; + } + } + } + .tui-full-calendar-weekday-filled { + background-color: @cp_dropdown-bg-hover !important; + } + + .tui-full-calendar-timegrid-hourmarker-time { + color: @cp_calendar-now !important; + } + .tui-full-calendar-timegrid-hourmarker-line-left, .tui-full-calendar-timegrid-hourmarker-line-today { + border-color: @cp_calendar-now !important; + } + .tui-full-calendar-timegrid-todaymarker { + background-color: @cp_calendar-now !important; + } + + .tui-full-calendar-month { + display: flex; + flex-flow: column; + & > div:last-child { + display: flex; + flex-flow: column; + flex: 1; + min-height: 0; + overflow: hidden; + } + .tui-full-calendar-today .tui-full-calendar-weekday-grid-date-decorator { + background-color: @cp_calendar-now !important; + color: @cp_calendar-now-fg !important; + } + .tui-full-calendar-weekday-schedule-time .tui-full-calendar-weekday-schedule-title { + color: @cryptpad_text_col !important; + } + .tui-full-calendar-extra-date { + .tui-full-calendar-weekday-grid-date { + color: @cp_sidebar-hint !important; + opacity: 0.5; + } + } + .tui-full-calendar-weekday-grid-date { + color: @cryptpad_text_col !important; + } + .tui-full-calendar-month-dayname-item span { + color: @cryptpad_text_col !important; + } + } + .tui-full-calendar-dayname * { + color: @cryptpad_text_col !important; + } + .tui-full-calendar-month-more { + background-color: @cp_sidebar-right-bg !important; + color: @cryptpad_text_col; + span { + color: @cryptpad_text_col !important; + } + } + + .tui-full-calendar-floating-layer.cp-calendar-popup-flex { + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + justify-content: center !important; + align-items: center !important; + .tui-full-calendar-popup { + width: 540px; + max-width: 100%; + max-height: 100%; + } + } + #tui-full-calendar-popup-arrow { + display: none !important; + } + } + .tui-full-calendar-timegrid-timezone { + background-color: @cp_sidebar-right-bg !important; + .tui-full-calendar-timegrid-hour { + color: @cryptpad_text_col !important; + } + color: @cryptpad_text_col; + } + .tui-full-calendar-timegrid-gridline, .tui-full-calendar-time-date { + border-color: @cp_calendar-border !important; + } + .tui-full-calendar-splitter, .tui-full-calendar-left, .tui-full-calendar-dayname-container, .tui-full-calendar-weekday-grid-line { + border-color: @cp_calendar-border !important; + + } + .tui-full-calendar-popup { + border-radius: @variables_radius_L; + } + .tui-full-calendar-popup-container { + min-width: 100%; + background: @cp_flatpickr-bg; + color: @cryptpad_text_col; + border-radius: @variables_radius_L; + font-weight: normal; + .tui-full-calendar-icon:not(.tui-full-calendar-calendar-dot):not(.tui-full-calendar-dropdown-arrow):not(.tui-full-calendar-ic-checkbox):not(.fa-map-marker) { + display: none; + } + .tui-full-calendar-icon { + text-align:center; + } + .tui-full-calendar-popup-detail-item { + a { + color: @cryptpad_color_link; + text-decoration: underline; + } + } + .tui-full-calendar-section-button-save { + height: 40px; + .btn-primary { // Update button + margin-right: 0px; + } + } + + } + li.tui-full-calendar-popup-section-item { + padding: 0 6px; + height: 32px; + } + .tui-full-calendar-popup-section-item { + height: auto; + margin: 0; + &:not(li):not(button) { + padding: 0; + margin-top: 5px; + } + #tui-full-calendar-schedule-calendar { + width: 179px; + top: 0; + } + &:not(button) { + border: none; + display: inline-flex; + align-items: center; + &:hover { + background-color: @cp_dropdown-bg-hover; + } + .tui-full-calendar-content { + text-overflow: ellipsis; + font: @colortheme_app-font; + padding: 0 10px; + } + input { flex: 1; } + } + } + .tui-full-calendar-section-date-dash { + height: auto; + } + .tui-full-calendar-section-title, .tui-full-calendar-section-location, .tui-full-calendar-section-body { + width: 100%; + } + .tui-full-calendar-dropdown-menu { + top: 38px; + width: 221px; // same as button + background-color: @cp_dropdown-bg; + color: @cp_dropdown-fg; + } + .tui-full-calendar-section-state, #tui-full-calendar-schedule-private { + display: none !important; + } + + .tui-full-calendar-popup:not(.tui-full-calendar-popup-detail) { + .tui-full-calendar-section-calendar { + width: 221px; // 50% + } + .tui-full-calendar-popup-section { + display: flex; + align-items: center; + flex-wrap: wrap; + .tui-full-calendar-section-start-date, .tui-full-calendar-section-end-date { + flex: 1; + } + .tui-full-calendar-section-allday { + width: 100%; + height: 32px; + border-radius: @variables_radius; + input[type="checkbox"].tui-full-calendar-checkbox-square:checked + span { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABbmlDQ1BpY2MAACiRdZHNK0RRGMZ/Zoh8NIqFNItZDFmMEiVLxsJmkgZlsLn3zpe6c93uvZNkq2wspizExtfCf8BW2VJKkZKs/AG+Npqu97hqJM7t3PfXc87zds5zIJQyjZJbPwAly3PSE8nYXGY+1vhEMy20EyaqGa49NjWV4t/xfkOdqtf9qtf/+/4cLdmca0Bdk/CwYTue8KhwasWzFW8KdxpFLSu8L5xw5IDCF0rXA35UXAj4VbEzkx6HkOoZK/xg/QcbRack3CccL5ll4/s86iatOWt2Wmq3zCguaSZIEkOnzBImHv1SLcnsb9/Al2+SZfEY8rdZxRFHgaJ4E6KWpWtOal70nHwmqyr333m6+aHBoHtrEhoefP+lBxq3oFrx/Y8D368eQvgezqyaf1lyGnkTvVLT4nsQWYeT85qmb8PpBnTd2ZqjfUlhmaF8Hp6PoS0DHVfQvBBk9b3O0S3MrMkTXcLOLvTK/sjiJ6CLZ94KREMsAAAACXBIWXMAAAsSAAALEgHS3X78AAABHUlEQVQoFWNkaP//n4EMwESGHrAW6mtkZvz3G2g03BsBagz/nRUQ7sNp49//TJ+Byv6BlMbrMjCsC2Jg3BbKwOAgB9GMolGAg4GBESIOIrmA+A9I03xvFHGwCrhGkDOe5TAw9LvAFbEn6jEwwTT9BtodvJ7h/4FHYH0MLBCKgaHTgYGBE8jLN2FgYAJae+4FA8NcLwZWkAtAmoLWMTBsuYNwECMsHrVEGBj2RzEwiIEciATANgE1bb6DJAgMNLhTr71hYHBcxsDw+htCAQ5NIAU/4RpBPKjmf2++MfwHaQpZD7cJyEMB3+BORRL+rybE8FOEk4Hj2FO4KMgdrFAMitun2DTCVSMxYAkBFFYg9j94qCIpwsZEil5wyDIDAAXIUsnSKmq7AAAAAElFTkSuQmCC); + } + .tui-full-calendar-ic-checkbox { + margin-left: 5px; + border-radius: 2px; + } + } + .CodeMirror { + margin-top: 5px; + background: @cp_forms-bg !important; + color: @cryptpad_text_col; + border: 1px solid @cp_forms-border; + border-radius: @variables_radius; + width: 100%; + height: 80px; + font: @colortheme_app-font; + font-size: 16px; + line-height: initial; + padding-left: 0.3rem; + pre { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; + } + } + .CodeMirror-placeholder { + color: @cp_forms-placeholder; + } + } + } + .tui-full-calendar-popup-detail { + font: @colortheme_app-font; + color: @cryptpad_text_col; + box-shadow: @cryptpad_ui_shadow; + .tui-full-calendar-popup-container { + padding-bottom: 17px; + } + .tui-full-calendar-popup-detail-date { + font-size: 14px; + } + .tui-full-calendar-section-button { + margin-top: 10px; + border: 0; + display: flex; + align-items: start; + button { + flex: 1; + margin: 0; + } + } + .tui-full-calendar-popup-top-line { + border-radius: 10px 10px 0px 0px; + height: 10px; + } + .tui-full-calendar-popup-vertical-line { + visibility: hidden; + width: 10px; + } + } + + .cp-recurrence-label, .cp-notif-label { + color: @cryptpad_text_col; + margin-right: 1rem; + i { + margin-right: 0.5rem; + } + } + + .cp-calendar-recurrence-container { + margin-top: 1rem; + .cp-calendar-rec-translated-str { + margin-top: 0.5rem; + } + } + + .cp-calendar-add-notif { + flex-flow: column; + align-items: baseline !important; + margin: 1rem 0; + * { + font-size: @colortheme_app-font-size; + font-weight: normal; + } + & > div { + display: flex; + } + .cp-calendar-notif-list-container { + width: 100%; + margin-bottom: 10px; + .cp-notif-label { + margin-top: 0.5em; + } + } + .cp-calendar-notif-list { + display: flex; + flex-flow: column; + flex: 1; + min-width: 150px; + &:empty { + display: none; + } + .cp-notif-entry { + display: flex; + margin-bottom: 2px; + border-radius: @variables_radius; + background-color: fade(@cryptpad_text_col, 10%); + padding: 0.25rem; + .cp-notif-value { + width: 75%; + display: inline-flex; + line-height: 30px; + vertical-align: middle; + flex-grow: 1; + .cp-before { + flex: 1; + min-width: 0; + } + } + span:not(:last-child) { + margin: 0; + margin-right: 0.3rem; + } + span:first-child { + margin-left: 0.3rem; + } + .btn-danger-outline { + display: block; + margin-right: 0px !important; + background-color: transparent; + color: @cryptpad_text_col; + border-color: @cryptpad_text_col; + &:hover { + color: @cp_buttons-red-color; + background-color: @cp_buttons-red; + border-color: @cp_buttons-red; + } + } + } + } + .cp-notif-empty { + display: none; + margin-bottom: 2px; + border-radius: @variables_radius; + background-color: fade(@cryptpad_text_col, 10%); + padding: 0.25rem 0.5rem; + line-height: 30px; + } + .cp-calendar-notif-list:empty ~ .cp-notif-empty { + display: block; + } + .cp-calendar-notif-form { + align-items: center; + .cp-calendar-notif-form-buttons { + display: inline-flex; + align-items: center; + & > input { + height: 40px; + } + } + // margin-bottom: 20px; + input { + width: 80px; + margin-right: 0.3rem; + } + .fa-plus{ + margin-left:0.3rem; + } + } + } + + .cp-calendar-close { + top: 17px; + right: 17px; + height: auto; + margin-right: 0px; + line-height: initial; + border: 1px solid; + &:not(:hover) { + background: transparent; + } + } + + } + + .cp-calendar-rec-inline, .cp-calendar-rec-block { + &:not(:last-child) { + margin-bottom: 10px; + } + } + .cp-calendar-rec-inline { + display: flex; + flex-flow: row; + align-items: center; + & > *:not(:first-child) { margin-left: 5px; } + .cp-dropdown-container { + position: unset; + } + input[type="number"] { + width: 80px !important; + margin-bottom: 0 !important; + } + .cp-checkmark { + margin-right: 0.5rem; + } + } + .cp-calendar-rec-block { + .cp-calendar-rec-block-title { + margin-bottom: 0.5rem !important; + } + .cp-radio { + margin-bottom: 0.5rem; + } + input[type="radio"]:not(:checked) ~ .cp-checkmark-label { + input { + filter: grayscale(1); + } + } + .cp-checkmark-label { + & > *:not(:first-child) { margin-left: 5px; } + width: 100%; + //height: 26px; + display: flex; + align-items: center; + & > input { + margin-bottom: 0 !important; + } + input { + display: inline; + height: 24px !important; + padding: 0 5px !important; + } + input[type="text"] { + width: 200px !important; + } + input[type="number"] { + width: 80px !important; + margin-bottom: 0 !important; + } + } + } + #cp-calendar-rec-monthly-pick ~ .cp-checkmark-label { + display: flex; + align-items: center; + & > span { + margin-right: 20px; + } + } + button.cp-calendar-pick-el { + display: flex; + align-items: center; + justify-content: center; + &:not(:last-child) { + margin-right: 5px; + } + } + div.cp-calendar-weekly-pick { + button { + width: 50px; + } + } + div.cp-calendar-monthly-pick { + display: flex; + flex-flow: column; + & > div { + display: flex; + &:not(:last-child) { + margin-bottom: 5px; + } + button { + height: 25px; + width: 25px; + &.lastday { + width: 115px; + } + } + } + } + + .tui-full-calendar-ic-repeat-b { + display: none; + & ~ * { + display: none; + } + } + + #cp-toolbar .cp-calendar-browse { + display: flex; + align-items: center; + button { + color: @cp_toolbar-fg; + border-color: @cp_toolbar-fg; + &:hover { + background-color: fade(@cp_toolbar-fg, 50%); + cursor: pointer; + } + } + } + + .cp-calendar-newevent { + &:hover { + cursor: pointer; + } + } + + .cp-toolbar-bottom-right button, .cp-toolbar-user button { + &:hover { + cursor: pointer; + } + } + + #cp-sidebarlayout-leftside { + & > div { + padding: 10px + } + .cp-calendar-new { + display: flex; + align-items: center; + justify-content: space-between; + } + .cp-calendar-list { + overflow-y: auto; + .cp-calendar-team { + height: 30px; + .avatar_main(30px); + .cp-avatar { + margin-right: 10px; + } + .cp-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + display: flex; + align-items: center; + justify-content: center; + margin: 5px 0 10px 0; + &:not(:first-child) { + margin-top: 30px; + } + } + .cp-calendar-entry { + display: flex; + align-items: center; + justify-content: space-between; + padding: 5px; + border-radius: @variables_radius; + background-color: @cp_sidebar-left-bg; + &:not(.cp-unclickable) { + cursor: pointer; + } + .cp-dropdown-container { + position: initial; + + .cp-dropdown-content{ + @media screen and (max-width: 600px) + { + left: 50%; + min-width: 45%; + } + } + } + button.cp-calendar-actions { + background-color: transparent; + &:hover { + background-color: @cp_sidebar-left-bg; + } + } + &.cp-ghost { + padding: 0; + button { + .tools_unselectable(); + cursor: pointer; + width: 100%; + display: flex; + justify-content: space-between; + background: transparent; + border: 1px solid @cryptpad_text_col; + border-radius: @variables_radius; + padding: 5px; + height: 36px; + font: @colortheme_app-font; + align-items: center; + color: @cryptpad_text_col; + &:hover { + background-color: @cp_sidebar-left-active; + color: @cp_sidebar-left-active-fg; + border: 0px; + } + i { + margin-left: 5px; + } + } + } + &:not(:last-child) { + margin-bottom: 10px; + } + &:hover { + background: @cp_sidebar-left-item-bg; + } + &.cp-restricted { + color: @cp_drive-header-fg; + } + .cp-calendar-icon { + width: 30px; + display: inline-flex; + height: 30px; + align-items: center; + justify-content: center; + border-radius: @variables_radius; + flex-shrink: 0; + } + &.cp-active { + background-color: @cp_sidebar-left-item-bg; + .cp-calendar-inactive { + display: none; + } + } + &:not(.cp-active) { + .cp-calendar-icon { + background: transparent !important; + } + .cp-calendar-active { + display: none; + } + } + .tools_unselectable(); + .cp-calendar-color { + display: inline-block; + border-radius: 50%; + width: 15px; + height: 15px; + flex-shrink: 0; + } + .cp-calendar-title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding: 0 5px; + } + } + } + } + .cp-calendar-colorpicker { + width: 100px; + height: 25px; + cursor: pointer; + border: 1px solid @cp_forms-border; + } + + @media (max-width: @browser_media-medium-screen) { + .cp-calendar-notif-list-container, .cp-calendar-notif-form { + flex-direction: column; + align-items: unset !important; + } + .cp-calendar-newevent { + i { + margin: 0 !important; + } + span { + display: none; + } + } + .tui-full-calendar-dayname-leftmargin, .tui-full-calendar-timegrid-right { + margin-left: 40px !important; + } + .tui-full-calendar-allday-left, .tui-full-calendar-timegrid-left { + width: 40px !important; + } + .tui-full-calendar-dayname > span { + display: flex; + flex-flow: column; + line-height: 0; + justify-content: center; + align-items: center; + height: 100%; + } + .tui-full-calendar-dayname * { + font-size: 11px; + line-height: initial; + height: auto; + } + .cp-toolbar-bottom-mid > div { + :not(:first-child) { + display: none; + } + :first-child { + display: inline-block; + } + } + } + +} + From 471e3954eb0f1da5ee2aebb70f75088687449624 Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 10 Jul 2024 17:01:18 +0300 Subject: [PATCH 008/179] fix error --- customize.dist/src/less2/include/forms.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/customize.dist/src/less2/include/forms.less b/customize.dist/src/less2/include/forms.less index 065b9db1d..5d8b242f1 100644 --- a/customize.dist/src/less2/include/forms.less +++ b/customize.dist/src/less2/include/forms.less @@ -28,6 +28,9 @@ } &.tui-full-calendar-content { font-size: @colortheme_app-font-size; + &:focus { + outline: @cryptpad_color_brand solid 2px; + } } &[readonly] { //margin-top:1rem; From 8c11b8c4c645da78af37b4ee1054d50fb23af68e Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 11 Jul 2024 11:08:44 +0200 Subject: [PATCH 009/179] lint compliance --- lib/crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/crypto.js b/lib/crypto.js index 9219f7c5f..7cac2f33d 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -8,7 +8,7 @@ CPCrypto.init = (cb) => { return Nacl.sign.open(signedMsg, validateKey); }; crypto.detachedVerify = (signedBuffer, signatureBuffer, validateKey) => { - return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer); + return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, validateKey); }; if (plugins.SODIUM && plugins.SODIUM.crypto) { let c = plugins.SODIUM.crypto; From 81f70c6a6722428cf4fb0f06942fa87277b39bbd Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Thu, 11 Jul 2024 13:08:50 +0300 Subject: [PATCH 010/179] Add border to table --- customize.dist/src/less2/include/sidebar-layout.less | 1 + 1 file changed, 1 insertion(+) diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index eeb5da80a..bb037d366 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -199,6 +199,7 @@ .cp-sidebar-table#performance-profiling-table { @media (max-width: 900px) { width: 100%; + border: 1px solid @cp_drive-icon-border; tr { display: flex; From a4171d19ebda7716bf6449d448356e9e66dea5c4 Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 11 Jul 2024 14:28:55 +0300 Subject: [PATCH 011/179] fix focus style on `new calendar` button #1506 --- www/calendar/app-calendar.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/www/calendar/app-calendar.less b/www/calendar/app-calendar.less index bdf59fb6d..d219cfd3f 100644 --- a/www/calendar/app-calendar.less +++ b/www/calendar/app-calendar.less @@ -633,6 +633,9 @@ color: @cp_sidebar-left-active-fg; border: 0px; } + &:focus { + outline: @cryptpad_color_brand solid 2px; + } i { margin-left: 5px; } From 4a289d003d9ceaab50d58a949bdd1954e2359949 Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 11 Jul 2024 14:56:01 +0300 Subject: [PATCH 012/179] fix focus style on drive sidebar #1506 --- customize.dist/src/less2/include/drive.less | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/customize.dist/src/less2/include/drive.less b/customize.dist/src/less2/include/drive.less index 239f73287..3672a540e 100644 --- a/customize.dist/src/less2/include/drive.less +++ b/customize.dist/src/less2/include/drive.less @@ -30,6 +30,11 @@ .cp-unselectable { .tools_unselectable(); } + .btn-primary{ + &:focus { + outline: @cryptpad_color_brand solid 2px; + } + } /* local mixins */ @drive_icon-margin: 10px; @@ -348,6 +353,9 @@ overflow: hidden; text-overflow: ellipsis; } + &:focus { + outline: @cryptpad_color_brand solid 2px; + } } } } @@ -373,6 +381,9 @@ padding-left: 20px; .leftside-menu-category_main(); margin: 0; + &:focus { + outline: @cryptpad_color_brand solid 2px; + } } } } @@ -399,6 +410,9 @@ position: relative; top: -1px; } + &:focus { + outline: @cryptpad_color_brand solid 2px; + } } .cp-app-drive-tree-docs { box-shadow: @cryptpad_ui_shadow; From be807d884a1a027ee2b6decd0e31c8fb73b5d057 Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 11 Jul 2024 15:26:43 +0300 Subject: [PATCH 013/179] fix overlapping focus on drive sidebar --- customize.dist/src/less2/include/drive.less | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/customize.dist/src/less2/include/drive.less b/customize.dist/src/less2/include/drive.less index 3672a540e..a4dca3826 100644 --- a/customize.dist/src/less2/include/drive.less +++ b/customize.dist/src/less2/include/drive.less @@ -334,11 +334,10 @@ overflow: hidden; text-overflow: ellipsis; .leftside-menu-category_main(); - margin: 0; display: flex; align-items: center; cursor: pointer; - margin-left: -5px; + margin: 0 0 2px -5px; padding-left: 5px; .fa, .cptools { display: inline-block; From f82fe763af9b3a766dd0635253be43fab9eea738 Mon Sep 17 00:00:00 2001 From: Fabrice Mouhartem Date: Thu, 11 Jul 2024 14:44:48 +0200 Subject: [PATCH 014/179] =?UTF-8?q?Send=20Pad=E2=80=99s=20plain=20password?= =?UTF-8?q?=20when=20sharing=20ownership?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The password is sent via `Mailbox` and then is still oblivious to the server - Otherwise a bogus file is created (#1522) - Also fix the file stored and fix #1521 --- www/common/outer/mailbox-handlers.js | 1 + www/common/sframe-common-outer.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index cfa749084..a2b2ed08a 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -384,6 +384,7 @@ define([ var channel = content.channel || content.teamChannel; if (content.password) { + content.pw = content.password; var key = ctx.store.driveSecret.keys.cryptKey; content.password = Crypto.encrypt(content.password, key); } diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 6c46ced04..508937e41 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1083,7 +1083,7 @@ define([ Cryptpad.addSharedFolder(null, secret, cb); } else { var _data = { - password: data.password, + password: data.pw || data.password, href: data.href, channel: data.channel, title: data.title, From da63f7d51ed95f5daf985ceeca7b279813e39d27 Mon Sep 17 00:00:00 2001 From: Fabrice Mouhartem Date: Thu, 11 Jul 2024 14:50:19 +0200 Subject: [PATCH 015/179] Minor: fix a typo in comment --- www/common/common-ui-elements.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 5405bf319..f56584e19 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3615,7 +3615,7 @@ define([ // Add the pad to your drive // This command will also add your mailbox to the metadata log - // The callback is called when the pad is stored, independantly of the metadata command + // The callback is called when the pad is stored, independently of the metadata command if (data.calendar) { var calendarModule = common.makeUniversal('calendar'); var calendarData = data.calendar; From 9098823fd72598e0b96eb70e69c742d61cc4c9fb Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 11 Jul 2024 16:11:51 +0300 Subject: [PATCH 016/179] change focus style on elements from Ctrl+E modal #1506 --- customize.dist/src/less2/include/drive.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/customize.dist/src/less2/include/drive.less b/customize.dist/src/less2/include/drive.less index 239f73287..424e12519 100644 --- a/customize.dist/src/less2/include/drive.less +++ b/customize.dist/src/less2/include/drive.less @@ -953,6 +953,9 @@ li, li .fa, li .cptools { cursor: pointer; border-radius: @variables_radius; + &:focus { + outline: @cryptpad_color_brand solid 2px; + } } &> p { display: flex; From f72ed440e63eea8d4ba995079d9fddc819c1aa5e Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 11 Jul 2024 16:48:26 +0300 Subject: [PATCH 017/179] fix focus issues on `Ctrl+E` modal #1558 --- www/common/common-interface.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 2c4d57799..d153b0483 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -670,6 +670,7 @@ define([ $modal: $blockContainer, show: function () { $blockContainer.css('display', 'flex'); + addTabListener($blockContainer); }, hide: hide }; From a29aab157d90a4f0a6dfa0fa52c8c754a67fa84c Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 11 Jul 2024 17:22:35 +0300 Subject: [PATCH 018/179] fix focus issues on modals that use UI.alert #1561 --- www/common/common-interface.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 2c4d57799..9ed80b7e8 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -719,6 +719,7 @@ define([ Notifier.notify(); }); + addTabListener(frame); return { element: frame, delete: close From 09067da34117fc6048072bf76bd0f40dbb1cf29d Mon Sep 17 00:00:00 2001 From: daria Date: Fri, 12 Jul 2024 12:45:41 +0300 Subject: [PATCH 019/179] change focus style on Ctrl+E modals #1561 --- customize.dist/src/less2/include/icons.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/customize.dist/src/less2/include/icons.less b/customize.dist/src/less2/include/icons.less index e3a273a92..bf3e3afc3 100644 --- a/customize.dist/src/less2/include/icons.less +++ b/customize.dist/src/less2/include/icons.less @@ -33,8 +33,8 @@ color: @cp_drive-fg; } &.cp-icons-element-selected { - background: @cp_drive-icon-hover; color: @cp_drive-fg; + outline: @cryptpad_color_brand solid 2px; } .fa, .cptools { display: block; From 1ac0cd3e1d15ed511d98f274012fb8ffd51a29ed Mon Sep 17 00:00:00 2001 From: Fabrice Mouhartem Date: Fri, 12 Jul 2024 17:59:50 +0200 Subject: [PATCH 020/179] Use the correct password when sharing a pad to a contact - Fix #1270; - Force reload option added. --- www/common/cryptpad-common.js | 3 ++- www/common/notifications.js | 1 + www/common/outer/mailbox-handlers.js | 7 +++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 4525c8287..e2d6a3746 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -2619,7 +2619,8 @@ define([ disableCache: localStorage['CRYPTPAD_STORE|disableCache'], driveEvents: !rdyCfg.noDrive, //rdyCfg.driveEvents // Boolean lastVisit: Number(localStorage.lastVisit) || undefined, - blockId: blockId + blockId: blockId, + blockHash: blockHash }; common.userHash = userHash || LocalStore.getUserHash(); diff --git a/www/common/notifications.js b/www/common/notifications.js index 82fb4b45d..8ec80c2e9 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -129,6 +129,7 @@ define([ var obj = { p: msg.content.isTemplate ? ['template'] : undefined, t: teamNotification || undefined, + f: 1, pw: msg.content.password || '' }; common.openURL(Hash.getNewPadURL(msg.content.href, obj)); diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index a2b2ed08a..06de11374 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -8,7 +8,8 @@ define([ '/common/common-hash.js', '/common/common-util.js', '/components/chainpad-crypto/crypto.js', -], function (ApiConfig, Messaging, Hash, Util, Crypto) { + '/common/outer/login-block.js', + ], function (ApiConfig, Messaging, Hash, Util, Crypto, Block) { // Random timeout between 10 and 30 times your sync time (lag + chainpad sync) var getRandomTimeout = function (ctx) { @@ -265,7 +266,9 @@ define([ } if (content.password) { - var key = ctx.store.driveSecret.keys.cryptKey; + var uHash = ctx.store.data.blockHash; + var uSecret = Block.parseBlockHash(uHash); + var key = uSecret.keys.symmetric; content.password = Crypto.encrypt(content.password, key); } From 44aee13a56135063f5ef1ea6448254e18ae8400c Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 15 Jul 2024 12:02:07 +0200 Subject: [PATCH 021/179] Compute new metadata first and fallback to old system if needed --- lib/storage/file.js | 29 +++++++-- .../00000000000000000000000000000000.ndjson | 7 +++ ...00000000000000000000000001.metadata.ndjson | 5 ++ .../00000000000000000000000000000001.ndjson | 7 +++ ...00000000000000000000000002.metadata.ndjson | 1 + .../00000000000000000000000000000002.ndjson | 6 ++ ...00000000000000000000000003.metadata.ndjson | 6 ++ .../00000000000000000000000000000003.ndjson | 6 ++ .../00000000000000000000000000000004.ndjson | 6 ++ scripts/tests/test-metadata.js | 60 +++++++++++++++++++ 10 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 scripts/tests/test-data/00/00000000000000000000000000000000.ndjson create mode 100644 scripts/tests/test-data/00/00000000000000000000000000000001.metadata.ndjson create mode 100644 scripts/tests/test-data/00/00000000000000000000000000000001.ndjson create mode 100644 scripts/tests/test-data/00/00000000000000000000000000000002.metadata.ndjson create mode 100644 scripts/tests/test-data/00/00000000000000000000000000000002.ndjson create mode 100644 scripts/tests/test-data/00/00000000000000000000000000000003.metadata.ndjson create mode 100644 scripts/tests/test-data/00/00000000000000000000000000000003.ndjson create mode 100644 scripts/tests/test-data/00/00000000000000000000000000000004.ndjson create mode 100644 scripts/tests/test-metadata.js diff --git a/lib/storage/file.js b/lib/storage/file.js index 2c2888f7a..d33c42f5f 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -429,7 +429,27 @@ How to proceed */ + let requiresChannel = true; + let all = []; nThen(function (w) { + let first = true; + getDedicatedMetadata(env, channelId, (err, line) => { + if (first && !err) { + if (!Array.isArray(line)) { + requiresChannel = false; + } + first = false; + } + all.push({err, line}); + }, w(function (err) { + if (err) { + // stream errors? + w.abort(); + return void cb(err); + } + })); + }).nThen(function (w) { + if (!requiresChannel) { return; } // returns the first line of a channel, parsed... getChannelMetadata(env, channelId, w(function (err, data) { if (err) { @@ -445,13 +465,10 @@ How to proceed handler(null, data); })); }).nThen(function () { - getDedicatedMetadata(env, channelId, handler, function (err) { - if (err) { - // stream errors? - return void cb(err); - } - cb(); + all.forEach(({err, line}) => { + handler(err, line); }); + cb(); }); }; diff --git a/scripts/tests/test-data/00/00000000000000000000000000000000.ndjson b/scripts/tests/test-data/00/00000000000000000000000000000000.ndjson new file mode 100644 index 000000000..cdbaaefa2 --- /dev/null +++ b/scripts/tests/test-data/00/00000000000000000000000000000000.ndjson @@ -0,0 +1,7 @@ +{"owners":["TestOwner"],"validateKey":"TestKey","channel":"0","created":1721035117462} +[0,"test","MSG","test",1721035117969] +[0,"test","MSG","test2",1721035117969] +[0,"test","MSG","test3",1721035117969] +[0,"test","MSG","test4",1721035117969] +[0,"test","MSG","test5",1721035117969] +[0,"test","MSG","test6",1721035117969] diff --git a/scripts/tests/test-data/00/00000000000000000000000000000001.metadata.ndjson b/scripts/tests/test-data/00/00000000000000000000000000000001.metadata.ndjson new file mode 100644 index 000000000..1cafb44c2 --- /dev/null +++ b/scripts/tests/test-data/00/00000000000000000000000000000001.metadata.ndjson @@ -0,0 +1,5 @@ +["RESTRICT_ACCESS",[true],1721035145090] +["ADD_ALLOWED",["NewAllowedKeyNewAllowedKeyNewAllowedKeyNewAl"],1721035148115] +["ADD_PENDING_OWNERS",["PendingOwner"],1721035151295] +["RESTRICT_ACCESS",[false],1721035155836] +["RESTRICT_ACCESS",[true],1721035156728] diff --git a/scripts/tests/test-data/00/00000000000000000000000000000001.ndjson b/scripts/tests/test-data/00/00000000000000000000000000000001.ndjson new file mode 100644 index 000000000..cdbaaefa2 --- /dev/null +++ b/scripts/tests/test-data/00/00000000000000000000000000000001.ndjson @@ -0,0 +1,7 @@ +{"owners":["TestOwner"],"validateKey":"TestKey","channel":"0","created":1721035117462} +[0,"test","MSG","test",1721035117969] +[0,"test","MSG","test2",1721035117969] +[0,"test","MSG","test3",1721035117969] +[0,"test","MSG","test4",1721035117969] +[0,"test","MSG","test5",1721035117969] +[0,"test","MSG","test6",1721035117969] diff --git a/scripts/tests/test-data/00/00000000000000000000000000000002.metadata.ndjson b/scripts/tests/test-data/00/00000000000000000000000000000002.metadata.ndjson new file mode 100644 index 000000000..7c47d09d3 --- /dev/null +++ b/scripts/tests/test-data/00/00000000000000000000000000000002.metadata.ndjson @@ -0,0 +1 @@ +{"owners":["TestOwner"],"validateKey":"TestKey","channel":"0","created":1721035117462} diff --git a/scripts/tests/test-data/00/00000000000000000000000000000002.ndjson b/scripts/tests/test-data/00/00000000000000000000000000000002.ndjson new file mode 100644 index 000000000..99973c454 --- /dev/null +++ b/scripts/tests/test-data/00/00000000000000000000000000000002.ndjson @@ -0,0 +1,6 @@ +[0,"test","MSG","test",1721035117969] +[0,"test","MSG","test2",1721035117969] +[0,"test","MSG","test3",1721035117969] +[0,"test","MSG","test4",1721035117969] +[0,"test","MSG","test5",1721035117969] +[0,"test","MSG","test6",1721035117969] diff --git a/scripts/tests/test-data/00/00000000000000000000000000000003.metadata.ndjson b/scripts/tests/test-data/00/00000000000000000000000000000003.metadata.ndjson new file mode 100644 index 000000000..ffcb25082 --- /dev/null +++ b/scripts/tests/test-data/00/00000000000000000000000000000003.metadata.ndjson @@ -0,0 +1,6 @@ +{"owners":["TestOwner"],"validateKey":"TestKey","channel":"0","created":1721035117462} +["RESTRICT_ACCESS",[true],1721035145090] +["ADD_ALLOWED",["NewAllowedKeyNewAllowedKeyNewAllowedKeyNewAl"],1721035148115] +["ADD_PENDING_OWNERS",["PendingOwner"],1721035151295] +["RESTRICT_ACCESS",[false],1721035155836] +["RESTRICT_ACCESS",[true],1721035156728] diff --git a/scripts/tests/test-data/00/00000000000000000000000000000003.ndjson b/scripts/tests/test-data/00/00000000000000000000000000000003.ndjson new file mode 100644 index 000000000..99973c454 --- /dev/null +++ b/scripts/tests/test-data/00/00000000000000000000000000000003.ndjson @@ -0,0 +1,6 @@ +[0,"test","MSG","test",1721035117969] +[0,"test","MSG","test2",1721035117969] +[0,"test","MSG","test3",1721035117969] +[0,"test","MSG","test4",1721035117969] +[0,"test","MSG","test5",1721035117969] +[0,"test","MSG","test6",1721035117969] diff --git a/scripts/tests/test-data/00/00000000000000000000000000000004.ndjson b/scripts/tests/test-data/00/00000000000000000000000000000004.ndjson new file mode 100644 index 000000000..99973c454 --- /dev/null +++ b/scripts/tests/test-data/00/00000000000000000000000000000004.ndjson @@ -0,0 +1,6 @@ +[0,"test","MSG","test",1721035117969] +[0,"test","MSG","test2",1721035117969] +[0,"test","MSG","test3",1721035117969] +[0,"test","MSG","test4",1721035117969] +[0,"test","MSG","test5",1721035117969] +[0,"test","MSG","test6",1721035117969] diff --git a/scripts/tests/test-metadata.js b/scripts/tests/test-metadata.js new file mode 100644 index 000000000..30d5ddc8c --- /dev/null +++ b/scripts/tests/test-metadata.js @@ -0,0 +1,60 @@ +const Store = require("../../lib/storage/file"); +const Meta = require("../../lib/metadata"); +const nThen = require('nthen'); + +let chanOld = '00000000000000000000000000000000'; +let chanOldUpdated = '00000000000000000000000000000001'; +let chanNew = '00000000000000000000000000000002'; +let chanNewUpdated = '00000000000000000000000000000003'; +let chanNoMeta = '00000000000000000000000000000004'; + +Store.create({ + filePath: './test-data/' +}, (err, store) => { + if (err) { return void console.error(err); } + + const readMetadata = (channel, cb) => { + const ref = {}; + const h = Meta.createLineHandler(ref, console.error); + store.readChannelMetadata(channel, h, () => { + cb(ref && ref.meta); + }); + }; + + nThen(w => { + readMetadata(chanOld, w(meta => { + if (!meta || meta.validateKey !== "TestKey") { + console.log('OldChanNoUpdate', meta); + throw new Error("Error with old channel without metadata update"); + } + })); + readMetadata(chanOldUpdated, w(meta => { + if (!meta || meta.validateKey !== "TestKey" || !meta.restricted || !meta.allowed.includes('NewAllowedKeyNewAllowedKeyNewAllowedKeyNewAl')) { + console.log('OldChanUpdate', meta); + throw new Error("Error with old channel with metadata updates"); + } + })); + readMetadata(chanNew, w(meta => { + if (!meta || meta.validateKey !== "TestKey") { + console.log('NewChanNoUpdate', meta); + throw new Error("Error with new channel without metadata update"); + } + })); + readMetadata(chanNewUpdated, w(meta => { + if (!meta || meta.validateKey !== "TestKey" || !meta.restricted || !meta.allowed.includes('NewAllowedKeyNewAllowedKeyNewAllowedKeyNewAl')) { + console.log('NewChanUpdate', meta); + throw new Error("Error with new channel with metadata updates"); + } + })); + readMetadata(chanNoMeta, w(meta => { + if (meta && Object.keys(meta).length) { + console.log('NoMetadataChan', meta); + throw new Error("Error with channel without metadata"); + } + })); + }).nThen(() => { + console.log('Success'); + process.exit(1); + }); +}) + From e4da9285d0d840eec2304b1b8cc76541d184cc37 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:40:44 +0300 Subject: [PATCH 022/179] Implement review fixes - change modal constructor and add translation keys --- customize.dist/messages.js | 3 +- www/admin/inner.js | 89 +++++++++++--------------------------- 2 files changed, 27 insertions(+), 65 deletions(-) diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 2459a246f..0e748c98e 100755 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -133,7 +133,8 @@ define(req, function(AppConfig, Default, Language) { return text; } }; - + Messages.admin_mfa_confirm_enable = "Are you sure you want to enable Multi-Factor Authentication?"; // XXX + Messages.admin_mfa_confirm_disable = "Are you sure you want to disable Multi-Factor Authentication?"; // XXX return Messages; }); diff --git a/www/admin/inner.js b/www/admin/inner.js index 5ae30471a..0d66c52c1 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -579,71 +579,32 @@ define([ }, query: function (val, setState) { var isChecked = APP.instanceStatus.enforceMFA; - var confirmationContent = isChecked - ? 'Are you sure you want to disable enforced MFA? This action would lessen the security of your account.' - : 'Are you sure you want to enforce MFA? This action would require to set up an authenticator app.'; - - function showConfirmationModal(callback) { - var modal = UI.dialog.customModal(confirmationContent, { - buttons: [{ - className: 'cancel', - name: Messages.cancel, - onClick: function () { - if (!isChecked) { - sFrameChan.query('Q_ADMIN_RPC', { - cmd: 'ADMIN_DECREE', - data: ['ENFORCE_MFA', [false]] - }, function (e, response) { - if (e || response.error) { - UI.warn(Messages.error); - console.error(e, response); - } else { - APP.updateStatus(function () { - setState(false); - flushCache(); - }); - } - }); - } - //check the checkbox again - else { - APP.updateStatus(function () { - setState(APP.instanceStatus.enforceMFA); - flushCache(); - }); - } - }, - keys: [27] // Esc key to close modal - }, { - className: 'primary', - name: Messages.settings_save, - onClick: function () { - sFrameChan.query('Q_ADMIN_RPC', { - cmd: 'ADMIN_DECREE', - data: ['ENFORCE_MFA', [val]] - }, function (e, response) { - if (e || response.error) { - UI.warn(Messages.error); - console.error(e, response); - } else { - APP.updateStatus(function () { - setState(APP.instanceStatus.enforceMFA); - flushCache(); - }); - } - }); - }, - keys: [13] // Enter key to confirm - }] + function showConfirmation(isChecked, setState) { + const confirmationContent = isChecked ? Messages.admin_mfa_confirm_disable : Messages.admin_mfa_confirm_enable; + UI.confirm(confirmationContent, function (confirmed) { + if (!confirmed) { + // User canceled their changes, restore the checkbox value + setState(isChecked); + return; + } + // User confirmed their changes, call the command and update the state + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: ['ENFORCE_MFA', [val]] + }, function (e, response) { + if (e || response.error) { + UI.warn(Messages.error); + console.error(e, response); + } else { + APP.updateStatus(function () { + setState(APP.instanceStatus.enforceMFA); + flushCache(); + }); + } }); - var $modal = $(modal); - UI.openCustomModal(modal); - $modal.closest('.alertify').on('mousedown', function (e) { - e.stopPropagation(); - }); - } - - showConfirmationModal(); + }); + } + showConfirmation(isChecked, setState); } }); From fe17b416792a753c2040d29a0b0c78160b943341 Mon Sep 17 00:00:00 2001 From: daria Date: Tue, 16 Jul 2024 15:35:51 +0300 Subject: [PATCH 023/179] fix focus issues on modals that use UI.prompt #1561 --- www/common/common-interface.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 9ed80b7e8..42e965685 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -164,12 +164,12 @@ define([ dialog.okButton = function (content, classString) { var sel = typeof(classString) === 'string'? 'button.ok.' + classString:'button.btn.ok.primary'; - return h(sel, { tabindex: '2', }, content || Messages.okButton); + return h(sel, content || Messages.okButton); }; dialog.cancelButton = function (content, classString) { var sel = typeof(classString) === 'string'? 'button.' + classString:'button.btn.cancel'; - return h(sel, { tabindex: '1'}, content || Messages.cancelButton); + return h(sel, content || Messages.cancelButton); }; dialog.message = function (text) { @@ -771,7 +771,7 @@ define([ document.body.appendChild(frame); setTimeout(function () { - $(input).select().focus(); + addTabListener(frame); Notifier.notify(); }); }; From 482e3274542e5280339f8ab23561e120e0fadb3e Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:34:41 +0300 Subject: [PATCH 024/179] Adjust general table styling to flex and make the performance one responsive #1099 --- .eslintrc.js | 2 +- .../src/less2/include/sidebar-layout.less | 32 ++++++------------- www/admin/app-admin.less | 12 +++++++ 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 209a4718e..924eddfc3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -35,7 +35,7 @@ module.exports = { 4 ], 'linebreak-style': [ - 'error', + 'off', // git handles linebreak conversion for us 'unix' ], 'quotes': [ diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index bb037d366..bafc9a77e 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -174,6 +174,9 @@ } .cp-sidebar-table { margin-top: @sidebar_base-margin; + tr { + display: flex; + } pre { margin: 0; } @@ -189,34 +192,17 @@ margin-right: @sidebar_base-margin; } } + th, td { + flex: 1; + word-wrap: break-word; + white-space: normal; + min-width: 13rem; + } tbody { tr:nth-child(odd) { background-color: @cp_sidebar-left-item-bg; } } - - } - .cp-sidebar-table#performance-profiling-table { - @media (max-width: 900px) { - width: 100%; - border: 1px solid @cp_drive-icon-border; - - tr { - display: flex; - flex-wrap: wrap; - align-items: center; - } - - th, td { - border: none; - flex: 1 1 auto; - width: 5rem; - margin-right: 0; - font-size: 13px; - word-wrap: break-word; - white-space: normal; - } - } } .cp-sidebar-input-block { display: inline-flex; diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index fbaaf4b5e..6d9edc132 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -28,6 +28,18 @@ max-height: 250px; } } + #cp-sidebarlayout-container #cp-sidebarlayout-rightside .cp-sidebarlayout-element[data-item] .cp-sidebar-table#performance-profiling-table { + @media (max-width: @browser_media-not-small) { + width: 100%; + tr { + width: 100%; + } + th, td { + margin-right: 0; + min-width: 1rem; + } + } + } .cp-admin-color-current { width: 20px; height: 20px; From 1f3b664bfe6bd0f74da9fc18a9553966935f4ac3 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Wed, 17 Jul 2024 15:26:10 +0300 Subject: [PATCH 025/179] Refactor code #1099 --- customize.dist/src/less2/include/sidebar-layout.less | 9 --------- www/admin/app-admin.less | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index bafc9a77e..5b616e0e8 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -174,9 +174,6 @@ } .cp-sidebar-table { margin-top: @sidebar_base-margin; - tr { - display: flex; - } pre { margin: 0; } @@ -192,12 +189,6 @@ margin-right: @sidebar_base-margin; } } - th, td { - flex: 1; - word-wrap: break-word; - white-space: normal; - min-width: 13rem; - } tbody { tr:nth-child(odd) { background-color: @cp_sidebar-left-item-bg; diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index 6d9edc132..74c71f0cf 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -29,6 +29,15 @@ } } #cp-sidebarlayout-container #cp-sidebarlayout-rightside .cp-sidebarlayout-element[data-item] .cp-sidebar-table#performance-profiling-table { + tr { + display: flex; + } + th, td { + flex: 1; + word-wrap: break-word; + white-space: normal; + min-width: 13rem; + } @media (max-width: @browser_media-not-small) { width: 100%; tr { From c9d5f2c236ae500b413962b0e49bac75f78fb8e1 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:30:28 +0300 Subject: [PATCH 026/179] Add horizontal scrollbar to table #1099 --- www/admin/app-admin.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index 74c71f0cf..ff86dd6c6 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -29,6 +29,10 @@ } } #cp-sidebarlayout-container #cp-sidebarlayout-rightside .cp-sidebarlayout-element[data-item] .cp-sidebar-table#performance-profiling-table { + display: flex; + flex-wrap: wrap; + flex-direction: column; + overflow-x: auto; tr { display: flex; } From 35109ae44698e5ebc35c8ed52e77c0bfd446b694 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:46:59 +0300 Subject: [PATCH 027/179] Make confirm button responsive #1406 --- customize.dist/src/less2/include/alertify.less | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index 0890d8010..c225708aa 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -327,6 +327,8 @@ nav { padding: @alertify_padding-base; text-align: right; + display: flex; + align-items: center; button, div.cp-button-confirm { margin: 0px !important; &:not(:first-child):not(.left) { @@ -339,6 +341,17 @@ div.cp-button-confirm { vertical-align: middle; } + .btn.btn-danger { + overflow-wrap: break-word; + white-space: normal; + } + @media screen and (max-width: @browser_media-medium-screen){ + justify-content: flex-end; + .btn.btn-danger { + width: 100%; + line-height: inherit; + } + } } } } From a1b617f0ca2e0abf09161cde40e3ae3354c8bacc Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:18:56 +0300 Subject: [PATCH 028/179] Wrap table inside a div #1099 --- www/admin/app-admin.less | 8 ++++---- www/admin/inner.js | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index ff86dd6c6..333173927 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -28,11 +28,9 @@ max-height: 250px; } } - #cp-sidebarlayout-container #cp-sidebarlayout-rightside .cp-sidebarlayout-element[data-item] .cp-sidebar-table#performance-profiling-table { - display: flex; - flex-wrap: wrap; - flex-direction: column; + #cp-sidebarlayout-container #cp-sidebarlayout-rightside .cp-sidebarlayout-element[data-item] div { overflow-x: auto; + .cp-sidebar-table#performance-profiling-table { tr { display: flex; } @@ -41,6 +39,7 @@ word-wrap: break-word; white-space: normal; min-width: 13rem; + margin-right: 0px; } @media (max-width: @browser_media-not-small) { width: 100%; @@ -53,6 +52,7 @@ } } } +} .cp-admin-color-current { width: 20px; height: 20px; diff --git a/www/admin/inner.js b/www/admin/inner.js index 7cb627abf..a0be7e2ea 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -3598,6 +3598,10 @@ define([ table.id = 'performance-profiling-table'; + var div = document.createElement('div'); + div.id = 'performance-table-container'; + div.appendChild(table); + const onRefresh = function () { sFrameChan.query('Q_ADMIN_RPC', { cmd: 'GET_WORKER_PROFILES', @@ -3629,7 +3633,7 @@ define([ onRefresh(); onRefreshPerformance.reg(onRefresh); - cb(table); + cb(div); }); From ffebbc6e807bfca12a7e4492a7900d204e1f2df4 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:20:20 +0300 Subject: [PATCH 029/179] More specific div selector #1099 --- www/admin/app-admin.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index 333173927..3845b858e 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -28,7 +28,7 @@ max-height: 250px; } } - #cp-sidebarlayout-container #cp-sidebarlayout-rightside .cp-sidebarlayout-element[data-item] div { + #cp-sidebarlayout-container #cp-sidebarlayout-rightside .cp-sidebarlayout-element[data-item] div#performance-table-container { overflow-x: auto; .cp-sidebar-table#performance-profiling-table { tr { From 11cf84a985511781a673dfeca77808fba9063bb6 Mon Sep 17 00:00:00 2001 From: David Benque Date: Thu, 18 Jul 2024 15:42:56 +0100 Subject: [PATCH 030/179] Update linter rules Prevent line break errors on Windows --- .eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 209a4718e..924eddfc3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -35,7 +35,7 @@ module.exports = { 4 ], 'linebreak-style': [ - 'error', + 'off', // git handles linebreak conversion for us 'unix' ], 'quotes': [ From e1b2be39c0f48f4f9e0234880295ee27ac19758a Mon Sep 17 00:00:00 2001 From: Fabrice Mouhartem Date: Fri, 19 Jul 2024 11:50:37 +0200 Subject: [PATCH 031/179] Fix: old password sent upon updating a password for the first time - Finish to fix #1521 --- www/common/sframe-common-outer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 508937e41..b4031d155 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1359,7 +1359,7 @@ define([ var viewH = Utils.Hash.getViewHashFromKeys(_secret); var href = Utils.Hash.hashToHref(editH, parsed.type); var roHref = Utils.Hash.hashToHref(viewH, parsed.type); - Cryptpad.setPadAttribute('password', password, w(), parsed.getUrl()); + Cryptpad.setPadAttribute('password', pw, w(), parsed.getUrl()); Cryptpad.setPadAttribute('channel', chan, w(), parsed.getUrl()); Cryptpad.setPadAttribute('href', href, w(), parsed.getUrl()); Cryptpad.setPadAttribute('roHref', roHref, w(), parsed.getUrl()); From 727c9d7b8828bf81c1771fe61f16069d83cae046 Mon Sep 17 00:00:00 2001 From: Fabrice Mouhartem Date: Fri, 19 Jul 2024 11:54:10 +0200 Subject: [PATCH 032/179] Fix the 'Preview document' link when sharing ownership - The password should not be asked in this context - Remove deprecated use of the drive secret - Related to #1270 and #1521 --- www/common/common-ui-elements.js | 2 +- www/common/outer/mailbox-handlers.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index f56584e19..10db8c37c 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3559,7 +3559,7 @@ define([ $(link).click(function (e) { e.preventDefault(); e.stopPropagation(); - var obj = { pw: msg.content.password || '' }; + var obj = { pw: msg.content.password || '', f: 1 }; common.openURL(Hash.getNewPadURL(msg.content.href, obj)); }); diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 06de11374..6ecac6a54 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -387,8 +387,10 @@ define([ var channel = content.channel || content.teamChannel; if (content.password) { + var uHash = ctx.store.data.blockHash; + var uSecret = Block.parseBlockHash(uHash); + var key = uSecret.keys.symmetric; content.pw = content.password; - var key = ctx.store.driveSecret.keys.cryptKey; content.password = Crypto.encrypt(content.password, key); } From 750635db4eeaf0ed662ede3f33ab49563136fe90 Mon Sep 17 00:00:00 2001 From: Fabrice Mouhartem Date: Fri, 19 Jul 2024 11:57:40 +0200 Subject: [PATCH 033/179] minor: use of let instead of var - To avoid some secrets to live outside their intended scope. --- www/common/outer/mailbox-handlers.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 6ecac6a54..0b98bbe9f 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -266,9 +266,9 @@ define([ } if (content.password) { - var uHash = ctx.store.data.blockHash; - var uSecret = Block.parseBlockHash(uHash); - var key = uSecret.keys.symmetric; + let uHash = ctx.store.data.blockHash; + let uSecret = Block.parseBlockHash(uHash); + let key = uSecret.keys.symmetric; content.password = Crypto.encrypt(content.password, key); } @@ -387,9 +387,9 @@ define([ var channel = content.channel || content.teamChannel; if (content.password) { - var uHash = ctx.store.data.blockHash; - var uSecret = Block.parseBlockHash(uHash); - var key = uSecret.keys.symmetric; + let uHash = ctx.store.data.blockHash; + let uSecret = Block.parseBlockHash(uHash); + let key = uSecret.keys.symmetric; content.pw = content.password; content.password = Crypto.encrypt(content.password, key); } From 8ceccb678c42e5d2d2fa5ca5a60e3bb8617e15b9 Mon Sep 17 00:00:00 2001 From: Fabrice Mouhartem Date: Fri, 19 Jul 2024 12:10:05 +0200 Subject: [PATCH 034/179] Cleaning code: use a function to encrypt the password - Use a function to encrypt the password for later use in URLs as it is used both to share a password-protected pad and share ownership of a password-protected pad; - related do #1270 and #1522. --- www/common/outer/mailbox-handlers.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 0b98bbe9f..906be2843 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -238,6 +238,14 @@ define([ cb(true); }; + // Encrypt the password under the right key before sending it via URL hash + var encryptPassword = function(ctx, password) { + let uHash = ctx.store.data.blockHash; + let uSecret = Block.parseBlockHash(uHash); + let key = uSecret.keys.symmetric; + return Crypto.encrypt(password, key); + }; + // Hide duplicates when receiving a SHARE_PAD notification: // Keep only one notification per channel: the stronger and more recent one var channels = {}; @@ -266,10 +274,7 @@ define([ } if (content.password) { - let uHash = ctx.store.data.blockHash; - let uSecret = Block.parseBlockHash(uHash); - let key = uSecret.keys.symmetric; - content.password = Crypto.encrypt(content.password, key); + content.password = encryptPassword(ctx, content.password); } // Update the data @@ -387,11 +392,8 @@ define([ var channel = content.channel || content.teamChannel; if (content.password) { - let uHash = ctx.store.data.blockHash; - let uSecret = Block.parseBlockHash(uHash); - let key = uSecret.keys.symmetric; content.pw = content.password; - content.password = Crypto.encrypt(content.password, key); + content.password = encryptPassword(ctx, content.password); } if (addOwners[channel]) { return void cb(true); } From 2a3998a4732fffb534535d01753c22681ea5bc67 Mon Sep 17 00:00:00 2001 From: daria Date: Mon, 22 Jul 2024 14:06:14 +0300 Subject: [PATCH 035/179] fix focus issues on calendar modals #1561 --- www/calendar/inner.js | 2 ++ www/common/common-interface.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/www/calendar/inner.js b/www/calendar/inner.js index 9cac57978..b971b2247 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -2209,6 +2209,7 @@ APP.recurrenceRule = { setFormat(allDay); }); }); + UI.addTabListener(el); }; var onCalendarEditPopup = function (el) { var $el = $(el); @@ -2276,6 +2277,7 @@ APP.recurrenceRule = { $b.closest('.tui-full-calendar-floating-layer').hide(); }); }); + UI.addTabListener(el); }; var onPopupRemoved = function () { var start, end; diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 42e965685..98fd748db 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -577,7 +577,7 @@ define([ return frame; }; - let addTabListener = frame => { + let addTabListener = UI.addTabListener = frame => { // find focusable elements let modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible').filter(':not(:disabled)'); From 86e029d4333f85257065da2cd69d583c8ff2c6e3 Mon Sep 17 00:00:00 2001 From: daria Date: Mon, 22 Jul 2024 15:42:44 +0300 Subject: [PATCH 036/179] add focus to certain calendar modal elements + make changes to focus styling --- www/calendar/app-calendar.less | 13 +++++++++++++ www/calendar/inner.js | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/www/calendar/app-calendar.less b/www/calendar/app-calendar.less index bdf59fb6d..91974d210 100644 --- a/www/calendar/app-calendar.less +++ b/www/calendar/app-calendar.less @@ -157,6 +157,11 @@ border-radius: @variables_radius_L; } .tui-full-calendar-popup-container { + .tui-full-calendar-section-allday{ + &:focus { + outline: @cryptpad_color_brand solid 2px; + } + } min-width: 100%; background: @cp_flatpickr-bg; color: @cryptpad_text_col; @@ -208,6 +213,9 @@ text-overflow: ellipsis; font: @colortheme_app-font; padding: 0 10px; + &:focus{ + outline: @cryptpad_color_brand solid 2px; + } } input { flex: 1; } } @@ -403,6 +411,11 @@ & > input { height: 40px; } + .tui-full-calendar-content{ + &:focus{ + outline: @cryptpad_color_brand solid 2px; + } + } } // margin-bottom: 20px; input { diff --git a/www/calendar/inner.js b/www/calendar/inner.js index b971b2247..f3dac10a4 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -2147,6 +2147,13 @@ APP.recurrenceRule = { $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(); + $el.find('.tui-full-calendar-section-allday').attr('tabindex', 0); + $el.find('.cp-calendar-close').attr('tabindex',-1); + $el.find('.tui-full-calendar-section-allday').keydown(function (e) { + if (e.which === 13) { + $(this).click(); + } + }); var $container = $el.closest('.tui-full-calendar-floating-layer'); $container.addClass('cp-calendar-popup-flex'); From 7d14f80fdb93304337623c674419fe5e6c8c1092 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:14:12 +0300 Subject: [PATCH 037/179] Make admin tables responsive #1099 --- www/admin/app-admin.less | 50 ++++++++++++++++++++++------------------ www/admin/inner.js | 24 +++++++++++-------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index 3845b858e..8bc3c3d85 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -28,30 +28,36 @@ max-height: 250px; } } - #cp-sidebarlayout-container #cp-sidebarlayout-rightside .cp-sidebarlayout-element[data-item] div#performance-table-container { - overflow-x: auto; - .cp-sidebar-table#performance-profiling-table { - tr { - display: flex; - } - th, td { - flex: 1; - word-wrap: break-word; - white-space: normal; - min-width: 13rem; - margin-right: 0px; - } - @media (max-width: @browser_media-not-small) { - width: 100%; - tr { - width: 100%; - } - th, td { - margin-right: 0; - min-width: 1rem; + #cp-sidebarlayout-container { + #cp-sidebarlayout-rightside { + .cp-sidebarlayout-element[data-item] { + div#cp-admin-table-container { + overflow-x: auto; + .cp-sidebar-table#cp-admin-table { + tr { + display: flex; + } + th, td { + flex: 1; + word-wrap: break-word; + white-space: normal; + min-width: 13rem; + margin-right: 0px; + } + @media (max-width: @browser_media-not-small) { + width: 100%; + tr { + width: 100%; + } + th, td { + margin-right: 0; + min-width: 7rem; + } + } + } + } } } - } } .cp-admin-color-current { width: 20px; diff --git a/www/admin/inner.js b/www/admin/inner.js index a0be7e2ea..e606337fa 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -1101,6 +1101,9 @@ define([ "" ]; var list = blocks.table(header, []); + list.setAttribute('id', 'cp-admin-table'); + let div = blocks.block([list]); + div.setAttribute('id', 'cp-admin-table-container'); var nav = blocks.nav([button, refreshButton]); var form = blocks.form([ @@ -1201,7 +1204,7 @@ define([ }); }); - cb([form, list]); + cb([form, div]); }); var getBlockId = (val) => { @@ -1413,6 +1416,9 @@ define([ "" ]; var list = blocks.table(header, []); + list.setAttribute('id', 'cp-admin-table'); + let div = blocks.block([list]); + div.setAttribute('id', 'cp-admin-table-container'); var nav = blocks.nav([button, refreshButton]); @@ -1581,7 +1587,7 @@ define([ }); }); - cb([form, list]); + cb([form, div]); }); // Msg.admin_defaultlimitHint, .admin_defaultlimitTitle @@ -1741,6 +1747,9 @@ define([ Messages.admin_note ]; var table = blocks.table(header, []); + table.setAttribute('id', 'cp-admin-table'); + let div = blocks.block([table]); + div.setAttribute('id', 'cp-admin-table-container'); let $table = $(table).hide(); APP.refreshLimits = function () { @@ -1798,7 +1807,7 @@ define([ }); }; APP.refreshLimits(); - cb(table); + cb(div); }); // Msg.admin_accountMetadataHint.admin_accountMetadataTitle @@ -3595,12 +3604,9 @@ define([ ]; var table = blocks.table(header, []); - - table.id = 'performance-profiling-table'; - - var div = document.createElement('div'); - div.id = 'performance-table-container'; - div.appendChild(table); + table.setAttribute('id', 'cp-admin-table'); + let div = blocks.block([table]); + div.setAttribute('id', 'cp-admin-table-container'); const onRefresh = function () { sFrameChan.query('Q_ADMIN_RPC', { From 6ed9ea3fa331d9ab4107d7271adb7029cbca30c9 Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 24 Jul 2024 12:37:49 +0300 Subject: [PATCH 038/179] fix focus bug on one-time events modal --- www/calendar/inner.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/calendar/inner.js b/www/calendar/inner.js index f3dac10a4..982c22662 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -2252,6 +2252,7 @@ APP.recurrenceRule = { var data = ev.schedule || {}; var id = data.id; + UI.addTabListener(el); if (!id) { return; } if (id.indexOf('|') === -1) { return; } // Original event ID doesn't contain | From 2800e7f4302984bb9e45c5125141e1b1bf8ee080 Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 24 Jul 2024 14:47:09 +0300 Subject: [PATCH 039/179] remove unnecessary line --- www/calendar/inner.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/calendar/inner.js b/www/calendar/inner.js index 982c22662..5dc05b2b8 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -2285,7 +2285,6 @@ APP.recurrenceRule = { $b.closest('.tui-full-calendar-floating-layer').hide(); }); }); - UI.addTabListener(el); }; var onPopupRemoved = function () { var start, end; From b819a5d8278fd283228cc5b684e2ee490328f68e Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 25 Jul 2024 13:34:43 +0300 Subject: [PATCH 040/179] add option to exit description editor on the calendar modal --- www/calendar/inner.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/www/calendar/inner.js b/www/calendar/inner.js index 5dc05b2b8..267b69958 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -2063,6 +2063,15 @@ APP.recurrenceRule = { editor.setOption('readOnly', false); editor.setOption('autoRefresh', true); editor.setOption('gutters', []); + editor.on('keydown', function (editor, e) { + if (e.which === 27) { + let $next = $(e.target).closest('.tui-full-calendar-popup-section').next(); + if ($next.length) { + $next.find('#tui-full-calendar-schedule-start-date').focus(); + } + e.stopPropagation(); + } + }); cm.configureTheme(common, function () {}); editor.setValue(oldEventBody); From bba8bc84a1028b2de352eea45060757a164c94a9 Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:25:26 +0300 Subject: [PATCH 041/179] Make password confirmation button responsive #1406 --- .../src/less2/include/alertify.less | 13 ------------ www/settings/app-settings.less | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index c225708aa..0890d8010 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -327,8 +327,6 @@ nav { padding: @alertify_padding-base; text-align: right; - display: flex; - align-items: center; button, div.cp-button-confirm { margin: 0px !important; &:not(:first-child):not(.left) { @@ -341,17 +339,6 @@ div.cp-button-confirm { vertical-align: middle; } - .btn.btn-danger { - overflow-wrap: break-word; - white-space: normal; - } - @media screen and (max-width: @browser_media-medium-screen){ - justify-content: flex-end; - .btn.btn-danger { - width: 100%; - line-height: inherit; - } - } } } } diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index ee5c1afc9..a3e47ab39 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -38,6 +38,22 @@ margin-left: 0.5rem; } + .alertify { + nav { + display: flex; + justify-content: center; + align-items: flex-end; + @media screen and (max-width: @browser_media-medium-screen) { + .btn-danger { + line-height: inherit; + overflow-wrap: break-word; + white-space: normal; + width: 100%; + } + } + } + } + #cp-sidebarlayout-container { #cp-sidebarlayout-rightside { input[type="checkbox"] { @@ -113,6 +129,11 @@ margin-left: 10px; } } + nav { + display: flex; + justify-content: center; + align-items: flex-end; + } @media (max-width: 840px) { .cp-password-container { From 3eece44804a1b0f97a26fdfff887cbeb435b855d Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Thu, 25 Jul 2024 23:19:26 +0300 Subject: [PATCH 042/179] Generalize solution to install and register confirmation buttons #1406 --- customize.dist/src/less2/pages/page-install.less | 11 +++++++---- customize.dist/src/less2/pages/page-register.less | 11 +++++++---- www/common/common-interface.js | 8 ++++++-- www/install/main.js | 2 +- www/register/main.js | 2 +- www/settings/app-settings.less | 2 +- www/settings/inner.js | 4 ++-- 7 files changed, 25 insertions(+), 15 deletions(-) diff --git a/customize.dist/src/less2/pages/page-install.less b/customize.dist/src/less2/pages/page-install.less index 47579bd12..d2c773adf 100644 --- a/customize.dist/src/less2/pages/page-install.less +++ b/customize.dist/src/less2/pages/page-install.less @@ -45,11 +45,14 @@ display: flex; align-items: center; justify-content: flex-end; - } - @media screen and (max-width: 600px) { - nav .btn-danger { - line-height: inherit; + @media screen and (max-width: @browser_media-medium-screen) { + .btn-confirm { + line-height: inherit; + overflow-wrap: break-word; + white-space: normal; + width: 100%; + } } } diff --git a/customize.dist/src/less2/pages/page-register.less b/customize.dist/src/less2/pages/page-register.less index 9e5d5caee..24216b49e 100644 --- a/customize.dist/src/less2/pages/page-register.less +++ b/customize.dist/src/less2/pages/page-register.less @@ -70,11 +70,14 @@ display: flex; align-items: center; justify-content: flex-end; - } - @media screen and (max-width: 600px) { - nav .btn-danger { - line-height: inherit; + @media screen and (max-width: @browser_media-medium-screen) { + .btn-confirm { + line-height: inherit; + overflow-wrap: break-word; + white-space: normal; + width: 100%; + } } } diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 2c4d57799..e58f04a67 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -775,10 +775,10 @@ define([ }); }; - UI.confirm = function (msg, cb, opt, force) { + UI.confirm = function (msg, cb, opt, force, className) { cb = cb || function () {}; opt = opt || {}; - + console.log('Parameters:', { msg, cb, opt, force, className }); var message; if (typeof(msg) === 'string') { if (!force) { msg = Util.fixHTML(msg); } @@ -791,6 +791,10 @@ define([ var ok = dialog.okButton(opt.ok, opt.okClass); var cancel = dialog.cancelButton(opt.cancel, opt.cancelClass); + if (className) { + ok.classList.add(className); + } + var frame = dialog.frame([ message, dialog.nav(opt.reverseOrder? diff --git a/www/install/main.js b/www/install/main.js index 92d6ddcbc..3eb97bf79 100644 --- a/www/install/main.js +++ b/www/install/main.js @@ -194,7 +194,7 @@ define([ done: function ($dialog) { $dialog.find('> div').addClass('half'); }, - }); + }, false, 'btn-confirm'); }, 150); }; diff --git a/www/register/main.js b/www/register/main.js index b9c7e6565..48e4a6e24 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -180,7 +180,7 @@ define([ done: function ($dialog) { $dialog.find('> div').addClass('half'); }, - }); + }, false, 'btn-confirm'); }, 150); }; diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index a3e47ab39..6c52d14ca 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -44,7 +44,7 @@ justify-content: center; align-items: flex-end; @media screen and (max-width: @browser_media-medium-screen) { - .btn-danger { + .btn-confirm{ line-height: inherit; overflow-wrap: break-word; white-space: normal; diff --git a/www/settings/inner.js b/www/settings/inner.js index e23459d9d..51cb76efb 100644 --- a/www/settings/inner.js +++ b/www/settings/inner.js @@ -812,7 +812,7 @@ define([ done: function($dialog) { $dialog.find('> div').addClass('half'); }, - }); + }, false, 'btn-confirm'); }; $(form).find('button').click(function() { @@ -866,7 +866,7 @@ define([ if (err || obj.error) { return UI.alert(Messages.settings_changePasswordError); } spinner.done(); }); - }); + }, null, null, 'cp-button-confirm'); }; $form.find('button').click(function() { From 72a6c3b5cdfc3aee841694a7c8b11fc43941d09a Mon Sep 17 00:00:00 2001 From: DianaXWiki <139217939+DianaXWiki@users.noreply.github.com> Date: Sun, 28 Jul 2024 19:36:47 +0300 Subject: [PATCH 043/179] Refactor code + fix i and a tags classes mismatch #1567 --- www/common/common-ui-elements.js | 115 ++++++++++++------------------- 1 file changed, 43 insertions(+), 72 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 5405bf319..980076528 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -623,13 +623,19 @@ define([ var appType = (common.getMetadataMgr().getMetadata().type || 'pad').toUpperCase(); data = data || {}; if (!callback && data.callback) { callback = data.callback; } + + function createIconButton(iconClasses, buttonClasses, title, text, ariaLabel) { + return $('