| forms | by dg | netteForms: a form whose repeater starts empty validates on submit Removing a repeater item refreshes the toggles. | | | |
| forms | by dg | setSubmissionSource() loads repeaters, so they work in forms anchored to a presenter Their monitor fires before the form is anchored and never loaded the data. Loading may detach surplus items, so membership is re-checked per component. | | | |
| forms | by dg | Repeater: number of items built from a submitted request is capped A forged POST cannot invoke an expensive factory hundreds of times; at most max + reserve containers are built. addRepeater() accepts the bounds, so the cap applies from the start. | | | |
| forms | by dg | DateTimeControl: Equal compares dates and times in the precision of the control It crashed on the string cast of the date object. Like Range, it is decided by the control, so a date ignores the time part and a time compares by the time of day, the same as the client does. | | | |
| application | by dg | Control: flashMessage() does not create the template In the most typical flow - flashMessage() followed by redirect() - the template was created just to be thrown away, which builds a whole Latte\Engine instance. The messages are written to the session first and into the template only if it already exists; a template created later gets them from the template factory, which reads the flashes from the session on its own. | | | |
| application | by dg | AccessPolicy: class-level #[Requires] is inherited from ancestors ReflectionClass::getAttributes() does not return attributes of parent classes, so a rule placed on a common ancestor (a typical #[Requires(sameOrigin: true)] on BaseAdminPresenter) was silently not enforced in its descendants. Attributes are now collected along the whole ancestor chain; a rule explicitly set in a descendant overrides the same rule of its ancestors. | | | |
| application | by dg | Presenter::argsToParams() now distinguish between NULL and '' | | | |
| application | by dg | removed {templatePrint} | | | |
| application | by dg | uses nette/routing 4.0 | | | |
| application | by dg | RoutingPanel: added support for AI agents | | | |
| application | by dg | removed support for @annotations (BC break) | | | |
| application | by dg | Presenter: removed constructor (BC break!) | | | |
| application | by dg | Component: only UI components can be added to presenter/component (BC break) WIP | | | |
| application | by dg | Component: method checkRequirements() is called for createComponent<Name>() methods (BC break) | | | |
| application | by dg | Revert "UI\PresenterComponent: removed references created by loadState() for persistent parameters. [Closes nette/nette#703][Closes nette/nette#703][Closes #69]" (possible BC break) This reverts commit cda17f460d020b0f042364d4e140742022a7e94d. See https://forum.nette.org/cs/35528-stejne-pojmenovany-parametr-akce-presenteru-a-persistentni-odlisne-chovani-v-nette-2-0-oproti-aktualnimu#p221742 BC break: Property must be nullable, ie: #[Persistent] public ?int $foo | | | |
| application | by dg | removed legacy services names (BC break) | | | |
| application | by dg | Presenter::handleInvalidLink() -> processInvalidLink() (BC break) | | | |
| application | by dg | added type hints (BC break) | | | |
| application | by dg | composer: increased dependencies versions | | | |
| application | by dg | opened 4.0-dev | | | |
| application | by dg | UI\Form: adapted to the SubmissionSource model of nette/forms 4.0 The form no longer overrides receiveHttpData(), isAnchored() and beforeRender(); instead it overrides createDefaultSource() to return null and sets the @internal FormSubmissionSource when anchored to a presenter. The source detects submission via the 'submit' signal, reads the application request and installs the hidden signal field in its prepare() render hook; it resolves the presenter from the form lazily, so a form re-anchored to another presenter keeps working. The catch-up pass of setSubmissionSource() replaces the manual loadHttpData() loop in validateParent(). The form owns its cross-origin state (private ?FetchSite $allowedOrigin + allowCrossOrigin()) independently of nette/forms; the same-origin check intentionally stays in signalReceived(), where a failure is reported via Presenter::detectedCsrf(). Requires nette/forms 4.0. | | | |
| application | by dg | UI\Form: compatible with both nette/forms 3.x and the upcoming 4.0 Two forward-compatible additions to the classic presenter form: - The form owns its cross-origin state (private ?FetchSite $allowedOrigin + allowCrossOrigin()) instead of relying on the protected $crossOrigin inherited from Nette\Forms\Form. Forms 3.x declares that property untyped while 4.0 removes it, so no redeclaration can satisfy both; a differently named private property works with either version. - createDefaultSource() returns null, which under forms 4.0 prevents the lazy default HttpSource from materializing (the form is anchored via the presenter). Under 3.x the method is unused; its return type references an interface that only exists in 4.0, which is safe because without a parent method there is no variance check. The classic receiveHttpData()/isAnchored()/beforeRender() overrides double as the documented BC seam of forms 4.0, so a single class works with both major versions. | | | |
| application | by dg | RoutingPanel: fixes lost {else} branch and missing space in tab The conversion of the panel templates to Latte turned a ternary into an {if} without the {else} branch, so non-string defaults and parameters were not rendered at all, while string ones were rendered twice (escaped text plus the full dump). The tab lost the space before the signal name. | | | |
| application | by dg | UIExtension: adds getCacheKey() depending on the snippet attribute SnippetNode::$snippetAttribute affects the generated code, but the extension did not report it in the cache key, so changing it left stale compiled templates with the original attribute. | | | |
| application | by dg | UIExtension: findNonce() accepts a base64url nonce The character class did not include '-', so a base64url nonce (emitted by common CSP middlewares) was matched truncated and n:nonce then rendered a wrong value, silently blocking the scripts. A nonce at the very beginning of the header was not matched at all. | | | |
| application | by dg | ComponentReflection: getActionRenderMethod() caches negative results too The ??= operator never caches a null result, so for actions without an action*() or render*() method the whole reflection lookup was repeated for every generated link. | | | |
| application | by dg | Presenter: detects an infinite loop of switch() calls Two actions switching to each other (actionA() switches to 'b', actionB() switches back to 'a') looped forever. As the target of switch() may depend on request parameters, this was remotely triggerable. | | | |
| bootstrap | by dg | used #Deprecated | | | |
| bootstrap | by dg | renamed PhpExtension -> PhpIniExtension | | | |
| bootstrap | by dg | opened 4.0-dev | | | |
| bootstrap | by dg | added upgrading.md | | | |
| bootstrap | by dg | added AGENTS.md & DOCS | | | |