Skip to content

Commit 53e92a9

Browse files
committed
Merge branch '5.x' into 6.x
2 parents 042d10c + 31d61c6 commit 53e92a9

20 files changed

Lines changed: 260 additions & 129 deletions

File tree

.tools/psalm/baseline.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,6 @@
784784
</file>
785785
<file src="pages/mailer/checkmail.php">
786786
<MixedArgument>
787-
<code><![CDATA[$str]]></code>
788787
<code><![CDATA[Core::getConfig('phpmailer_test_address')]]></code>
789788
</MixedArgument>
790789
<MixedAssignment>

AGENTS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ All core classes live in the `Redaxo\Core\` namespace, mapped to `src/`. Tests l
7676
- PHPStan level 6 + Psalm level 1, both with baselines in `.tools/phpstan/` and `.tools/psalm/`
7777
- PHPUnit strict mode: warnings, notices, deprecations all fail the build
7878
- In YAML files, prefer single quotes when quoting is needed
79-
- Comments and commit messages in English; commits use conventional commits (`feat:`, `fix:`, `refactor:`, `docs:`, `chore:`, `test:`, `style:`, `ci:`)
79+
- Comments and commit messages in English; commits use conventional commits (`feat:`, `fix:`, `refactor:`, `docs:`, `chore:`, `test:`, `style:`, `ci:`). The same rules (English + conventional commit prefix) apply to PR titles, since they become the commit message on squash merge
80+
- Don't write bare `@name` tokens in commit messages (e.g. annotations like `@internal`/`@deprecated`, or anything that looks like a username): GitHub autolinks them into user mentions and pings a random account. Wrap them in backticks (`` `@internal` ``) — GitHub renders code spans in commit messages and doesn't link mentions inside them
8081
- **Properties**: prefer modern public properties (with `readonly`, asymmetric visibility, property hooks as appropriate) over getter/setter methods
8182

8283
### Baselines
@@ -86,5 +87,6 @@ The static analysis baselines exist to grandfather pre-existing issues. **New co
8687

8788
- `6.x` is actively under development and has not shipped a stable release yet. Breaking changes to public APIs are acceptable while we still can — prefer **fixing the design** over piling on `@deprecated` shims.
8889
- `@internal`-marked symbols may change without notice.
90+
- Mark new classes `@internal` by default. Only omit it when the class is deliberately part of the public API. In that case, review every public property, constant, and method individually and mark `@internal` each one that isn't meant to be a public contract — public visibility alone shouldn't lock you into supporting it.
8991
- DB schema changes belong in the relevant install/update path.
9092
- Behavior that needs to stay aligned with `5.x` (because changes are regularly merged up) should be kept structurally close to its `5.x` counterpart unless the divergence is intentional.

assets/css/redaxo.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/css/styles.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/standard.js

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -450,21 +450,61 @@ jQuery(function($){
450450
$("[autofocus]").trigger("focus");
451451
});
452452

453-
// scroll to anchor element + adjust scroll-padding-top
453+
// scroll to anchor element
454+
// (scrollIntoView honors the CSS scroll-padding-top, so the sticky navbar
455+
// offset is handled automatically — no manual correction needed)
454456
function scrollToAnchor() {
455-
if (window.location.hash) {
456-
var scrollPadding = window.getComputedStyle(document.documentElement).getPropertyValue('scroll-padding-top');
457-
scrollPadding = parseInt(scrollPadding, 10); // so 65px will be 65
458-
if (scrollPadding > 0) {
459-
var anchorItem = document.querySelector(window.location.hash);
460-
if (anchorItem) {
461-
var anchorItemPosition = anchorItem.getBoundingClientRect().top;
462-
if (!isNaN(scrollPadding) && scrollPadding > 0 && anchorItemPosition < scrollPadding) {
463-
window.scrollBy(0, -scrollPadding);
464-
}
465-
}
466-
}
457+
if (!window.location.hash) {
458+
return;
459+
}
460+
var anchorItem = document.querySelector(window.location.hash);
461+
if (!anchorItem) {
462+
return;
467463
}
464+
465+
var scrollToItem = function () {
466+
anchorItem.scrollIntoView({block: 'start'});
467+
};
468+
469+
// Defer to the next frame so the freshly swapped-in pjax content is laid
470+
// out before we scroll, instead of guessing a fixed timeout.
471+
requestAnimationFrame(function () {
472+
requestAnimationFrame(scrollToItem);
473+
});
474+
475+
// Images that are still loading will shift the layout once they arrive and
476+
// push the anchor out of position. Re-scroll whenever one finishes, but
477+
// stop as soon as the user scrolls manually so we don't hijack the page.
478+
var container = anchorItem.closest('[data-pjax-container]') || document;
479+
var pending = Array.prototype.filter.call(container.querySelectorAll('img'), function (img) {
480+
return !img.complete;
481+
});
482+
if (!pending.length) {
483+
return;
484+
}
485+
486+
var remaining = pending.length;
487+
var stop = function () {
488+
window.removeEventListener('wheel', stop);
489+
window.removeEventListener('touchstart', stop);
490+
pending.forEach(function (img) {
491+
img.removeEventListener('load', onImageDone);
492+
img.removeEventListener('error', onImageDone);
493+
});
494+
};
495+
var onImageDone = function () {
496+
scrollToItem();
497+
if (--remaining === 0) {
498+
stop();
499+
}
500+
};
501+
502+
window.addEventListener('wheel', stop, {passive: true});
503+
window.addEventListener('touchstart', stop, {passive: true});
504+
pending.forEach(function (img) {
505+
img.addEventListener('load', onImageDone);
506+
img.addEventListener('error', onImageDone);
507+
});
468508
}
469509

470510
var rex_loader = {

assets_src/scss/_base.scss

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ body:after {
7474
//margin-top: -$navbar-height;
7575
padding-top: $top-navbar-height;
7676
table-layout: fixed;
77+
}
7778

78-
.rex-is-popup& {
79-
padding-top: $top-popup-navbar-height;
80-
}
79+
&.rex-is-popup .rex-page-container {
80+
padding-top: $top-popup-navbar-height;
8181
}
8282

8383
.rex-nav-main {
@@ -347,11 +347,10 @@ body:after {
347347
&, a {
348348
color: $alert-success-text;
349349
}
350-
351-
tr&:hover > th,
352-
tr&:hover > td {
353-
background-color: darken($alert-success-bg, 10%);
354-
}
350+
}
351+
tr.rex-state-success:hover > th,
352+
tr.rex-state-success:hover > td {
353+
background-color: darken($alert-success-bg, 10%);
355354
}
356355
.rex-state-info,
357356
.rex-state-notice {
@@ -360,23 +359,23 @@ body:after {
360359
&, a {
361360
color: $alert-info-text;
362361
}
363-
364-
tr&:hover > th,
365-
tr&:hover > td {
366-
background-color: darken($alert-info-bg, 10%);
367-
}
362+
}
363+
tr.rex-state-info:hover > th,
364+
tr.rex-state-info:hover > td,
365+
tr.rex-state-notice:hover > th,
366+
tr.rex-state-notice:hover > td {
367+
background-color: darken($alert-info-bg, 10%);
368368
}
369369
.rex-state-warning {
370370
background-color: $alert-warning-bg;
371371

372372
&, a {
373373
color: $alert-warning-text;
374374
}
375-
376-
tr&:hover > th,
377-
tr&:hover > td {
378-
background-color: darken($alert-warning-bg, 10%);
379-
}
375+
}
376+
tr.rex-state-warning:hover > th,
377+
tr.rex-state-warning:hover > td {
378+
background-color: darken($alert-warning-bg, 10%);
380379
}
381380
.rex-state-danger,
382381
.rex-state-error {
@@ -385,11 +384,12 @@ body:after {
385384
&, a {
386385
color: $alert-danger-text;
387386
}
388-
389-
tr&:hover > th,
390-
tr&:hover > td {
391-
background-color: darken($alert-danger-bg, 10%);
392-
}
387+
}
388+
tr.rex-state-danger:hover > th,
389+
tr.rex-state-danger:hover > td,
390+
tr.rex-state-error:hover > th,
391+
tr.rex-state-error:hover > td {
392+
background-color: darken($alert-danger-bg, 10%);
393393
}
394394

395395
.rex-primary-id {
@@ -609,13 +609,15 @@ body:after {
609609

610610
// correcting bootstrap vendor regarding Quick fix for badges in buttons
611611
// https://github.com/redaxo/core/blob/120950020f35e9158030513744835c936e527bc6/assets_src/vendor/bootstrap/assets/stylesheets/bootstrap/_badges.scss#L26
612-
.btn & {
613-
position: relative;
614-
top: 0px;
615-
}
612+
.badge {
613+
.btn & {
614+
position: relative;
615+
top: 0px;
616+
}
616617

617-
.btn-xs &,
618-
.btn-group-xs > .btn & {
619-
top: 0;
620-
padding: 1px 5px;
621-
}
618+
.btn-xs &,
619+
.btn-group-xs > .btn & {
620+
top: 0;
621+
padding: 1px 5px;
622+
}
623+
}

assets_src/scss/_helper.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
vertical-align: top;
2525
white-space: nowrap;
2626

27-
.rex-truncate-expandable&:hover,
27+
&.rex-truncate-expandable:hover,
2828
.rex-truncate-expandable > &:hover {
2929
max-width: 10000px !important;
3030
}

assets_src/scss/_navs.scss

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,6 @@ $transitionDuration: 300ms;
260260
height: 22px;
261261
transform: translate(-50%, -50%) rotate(0);
262262
transition: transform $transitionDuration $easeInCubic;
263-
264-
.rex-nav-main-is-visible& {
265-
transform: translate(-50%, -50%) rotate(-180deg);
266-
transition: transform $transitionDuration $easeOutCubic;
267-
}
268263
}
269264

270265
.icon-bar {
@@ -290,22 +285,6 @@ $transitionDuration: 300ms;
290285
&:nth-child(3) {
291286
transform: translate(-50%, 5px);
292287
}
293-
294-
.rex-nav-main-is-visible& {
295-
transition: transform $transitionDuration $easeOutCubic, opacity $transitionDuration $easeOutCubic;
296-
297-
&:nth-child(1) {
298-
transform: translate(-50%, -50%) rotate(45deg);
299-
}
300-
301-
&:nth-child(2) {
302-
opacity: 0;
303-
}
304-
305-
&:nth-child(3) {
306-
transform: translate(-50%, -50%) rotate(-45deg);
307-
}
308-
}
309288
}
310289

311290
@media (min-width: $grid-float-breakpoint) {
@@ -335,37 +314,18 @@ $transitionDuration: 300ms;
335314
transform: translateY(-$navbar-height); // hide above navbar
336315
transition: opacity ($transitionDuration * 2) $easeInOutCubic, transform 0ms linear ($transitionDuration * 2); // fade out and transform afterwards
337316

338-
.rex-nav-main-is-visible& {
339-
display: block;
340-
opacity: 1;
341-
transform: translateY(0); // show at target position
342-
transition: opacity ($transitionDuration * 2) $easeInOutCubic ($transitionDuration * 2), transform 0ms linear 0ms; // fade in and immediately transform
343-
}
344-
345317
> .nav {
346318
margin: 0;
347319
}
348320
}
349321
}
350-
351-
.rex-is-popup& {
352-
z-index: auto;
353-
354-
.navbar {
355-
min-height: $top-popup-navbar-height;
356-
box-shadow: none;
357-
padding-top: 0;
358-
padding-bottom: 0;
359-
}
360-
}
361322
}
362323

363324
.rex-nav-top-is-fixed {
364325
position: fixed;
365326
}
366327

367-
.rex-nav-top-is-elevated,
368-
.rex-nav-main-is-visible& {
328+
.rex-nav-top-is-elevated {
369329
.navbar {
370330
box-shadow: 0 2px 2px 0 rgba($color-a-darker, 0.2);
371331
}
@@ -385,12 +345,61 @@ $transitionDuration: 300ms;
385345
@media (min-width: $screen-lg-min) {
386346
padding-right: $grid-gutter-width;
387347
}
348+
}
349+
350+
&.rex-is-popup {
351+
.rex-nav-top {
352+
z-index: auto;
353+
354+
.navbar {
355+
min-height: $top-popup-navbar-height;
356+
box-shadow: none;
357+
padding-top: 0;
358+
padding-bottom: 0;
359+
}
360+
}
388361

389-
.rex-is-popup& {
362+
.rex-nav-top .container-fluid {
390363
padding-right: floor($grid-gutter-width / 2);
391364
justify-content: flex-start;
392365
}
393366
}
367+
368+
&.rex-nav-main-is-visible {
369+
.rex-nav-top .navbar-toggle .icon-bars {
370+
transform: translate(-50%, -50%) rotate(-180deg);
371+
transition: transform $transitionDuration $easeOutCubic;
372+
}
373+
374+
.rex-nav-top .navbar-toggle .icon-bar {
375+
transition: transform $transitionDuration $easeOutCubic, opacity $transitionDuration $easeOutCubic;
376+
377+
&:nth-child(1) {
378+
transform: translate(-50%, -50%) rotate(45deg);
379+
}
380+
381+
&:nth-child(2) {
382+
opacity: 0;
383+
}
384+
385+
&:nth-child(3) {
386+
transform: translate(-50%, -50%) rotate(-45deg);
387+
}
388+
}
389+
390+
.navbar {
391+
box-shadow: 0 2px 2px 0 rgba($color-a-darker, 0.2);
392+
}
393+
394+
@media (max-width: $grid-float-breakpoint-max) {
395+
.rex-nav-top .rex-nav-meta {
396+
display: block;
397+
opacity: 1;
398+
transform: translateY(0); // show at target position
399+
transition: opacity ($transitionDuration * 2) $easeInOutCubic ($transitionDuration * 2), transform 0ms linear 0ms; // fade in and immediately transform
400+
}
401+
}
402+
}
394403
}
395404

396405
.rex-page-nav {

assets_src/scss/_scaffolding.scss

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@ html {
2424
height: auto;
2525
min-height: 100%;
2626
padding-top: 0;
27-
28-
.rex-is-popup& {
29-
padding-top: 0; // required due to specificity
30-
}
3127
}
3228

3329
.rex-page-main {
@@ -39,19 +35,25 @@ html {
3935
@media (max-width: $grid-float-breakpoint-max) {
4036
padding-top: $top-mobile-navbar-height;
4137
}
42-
43-
.rex-is-popup& {
44-
padding-top: $top-popup-navbar-height;
45-
}
4638
}
4739

4840
.rex-page-main-inner {
4941
@media (min-width: $screen-lg-min) {
5042
padding-left: $grid-gutter-width;
5143
padding-right: $grid-gutter-width;
5244
}
45+
}
46+
47+
&.rex-is-popup {
48+
.rex-page-container {
49+
padding-top: 0; // required due to specificity
50+
}
51+
52+
.rex-page-main {
53+
padding-top: $top-popup-navbar-height;
54+
}
5355

54-
.rex-is-popup& {
56+
.rex-page-main-inner {
5557
padding-left: floor($grid-gutter-width / 2);
5658
padding-right: floor($grid-gutter-width / 2);
5759
}

0 commit comments

Comments
 (0)