Журнал изменений

Официальный сайт SLAED CMS

Журнал изменений

Фильтр и поиск

Всего: 1122 Доступных коммитов | Отфильтровано: 1122 Коммиты | Страница: 1 / 113
Сегодня (19.08.2026)
Docs: three audits close the theme plan's gaps, and the switch that could never have worked
Автор: Eduard Laas | Дата: 00:08 19.08.2026

Three independent reviews found fifty-eight defects in the etalon plan, most of them mine. The gravest was silent: the dark-mode toggle was specified as a script writing a cookie, but setCookies() sets httponly, so it could not have worked at all. Every checkable claim was re-derived from the tree, and every number in the plan now names the command that produces it.

Core changes:

  1. Facts corrected against the tree (docs/THEME-ETALON-2026.md):
  2. --sl-shadow-soft was attributed to the wrong themes

    • admin holds a colour, lite a whole shadow, not the reverse
    • the "ten dead shadows" built on that mistake do not exist; both themes are correct
  3. --sl-color-primary-hover is not dead in lite: four uses in toastui/skin.css
  4. the monitor series are upload, download, CPU and RAM; there is no disk
  5. <html> lives in lite's partials/site-header.html, which opens every public page
  6. RSS carries six locale files and its index renders a real HTML page
  7. Contradictions inside the plan resolved:
  8. component tokens were forbidden literals while being the answer to a unique value
  9. breakpoints cannot be themed at all, which contradicted "edit one block"
  10. the metric claimed every batch lowers it, false for four batches of ten
  11. the ratchet baseline was written once, so a regression passed against an old figure
  12. batch 0 required the tool it builds
  13. Dark mode made buildable rather than described:
  14. the cookie goes through getCookies/setCookies with the $conf['user_c'] prefix
  15. the toggle is a POST with CSRF, because httponly blocks any script
  16. light-dark() returns a colour, so shadows compose from colour tokens instead
  17. admin plumbing lands in batch 4, lite roots and the site toggle in batch 7
  18. Gates made honest about what they can prove:
  19. contrast pairs are crawled from computed styles, not multiplied token by token
  20. the duplicate gate allowlists what a machine cannot judge
  21. theme creation is two gates, static and HTTP, sharing one lifecycle
  22. the markup scan tokenises PHP, since a grep misses concatenation and heredocs

Benefits:

  • Every figure is reproducible: eight audit flags, one per measurement
  • A snap that looks wrong now bends the layout, never the ladder
  • The machine-readable contract moves to tools/, so a clone inherits it

Technical notes:

  • Browser baseline rises to Chrome 123 / Safari 17.5 / Firefox 120
  • Plan compressed from 1085 to 867 lines with no decision dropped
  • No CSS or PHP changed in this commit
Вчера (18.08.2026)
Docs: the theme plan is rebuilt on measurement and gains a dark mode it cannot desynchronise
Автор: Eduard Laas | Дата: 22:30 18.08.2026

The etalon plan was audited against the tree and every number in it either verified, corrected or removed. Three token surfaces it never named turned out to break silently on rename, three numeric families had no axis at all, and the spacing ladder was aimed at the minority rhythm. The showcase pages are dropped from the repository: nothing in the application ever reached them.

Core changes:

  1. Plan corrected against the tree (docs/THEME-ETALON-2026.md):
  2. Rename surface grew from five places to eight

    • error.html holds its own :root of 39 tokens and no screenshot covers it
    • editors/toastui/skin.css consumes tokens in both themes
    • EditorWindowTest asserts a token name that batch 1 moves
  3. Ladders derived from measured peaks instead of a nominal rhythm

    • spacing runs on 5/10, not on 4: 237 sites against 142
    • the measured ladder halves the pixel movement at the same step count
  4. Three numeric families had no axis: font-weight, letter-spacing, animation

    • animation duration is recorded as the one family that gets no ladder
  5. Blind spot of the metric was twice its stated size

    • line-height and font-weight are bare numbers too, 222 further sites
  6. Dark mode designed before the API freeze (docs/THEME-ETALON-2026.md):
  7. Both values live in one declaration through light-dark()

    • no second block, no @media, so the modes cannot drift apart
    • the switch is two selectors keyed by data-theme on <html>
  8. 98 sites carry a name that lies under inversion and now fail the audit

    • --sl-color-on-dark alone is 53 of them
  9. Colour ramp steps carry roles, so a collapse is decided by role, not distance
  10. Enforcement made mechanical rather than advisory:
  11. The audit tool gains a fixture test of its own, run before it may write a baseline
  12. Contrast is gated at AA over pairs that actually meet on an element
  13. The ratchet baseline lives under tools/ so it survives a clone
  14. Showcase pages removed (demo/):
  15. 66 files, no code path reaches them, 6499 token references that would have to follow every rename for no shipped benefit

Benefits:

  • Every figure in the plan is reproducible from the tree or marked as derived by the tool
  • Dark mode costs no extra token names and cannot desynchronise from light
  • A wrong classifier in the audit tool is now caught by fixtures instead of by luck

Technical notes:

  • Browser baseline rises to Chrome 123 / Safari 17.5 / Firefox 120 for light-dark()
  • Theme rules and the token contract live in .rules/theme.md, which git does not track
  • No CSS or PHP changed in this commit
Fix: a window is placed by the layout it has and not by the animation still playing over it
Автор: Eduard Laas | Дата: 18:02 18.08.2026

The window canon read its geometry through getBoundingClientRect(), which returns the transformed box while the entry animation still holds the window at scale(0.97). Every placement, pin and clamp now reads offsetWidth, offsetLeft and offsetTop, which ignore transforms. The same class of defect is fixed where editor JavaScript wrote inline geometry over the phone sheet rule of the canon, and the last duplicate of the canon foot is gone.

Core changes:

  1. The canon engine (plugins/system/slaed.js):
  2. setWindowPlace centres on the layout width instead of the drawn one

    • an 880px window was written to left 293px instead of 280px, measured at 1440
    • the error was always the width times 1.5%, and invisible under prefers-reduced-motion
  3. The drag pins the layout position rather than the transformed one

    • grabbing the head during the opening animation jumped the window 13.2px by X and 24.0px by Y
    • the jump then stuck, because data-sl-moved stops the canon re-centring the window
  4. setWindowBounds clamps against the layout width for the same reason
  5. The emoji panel (plugins/editors/toastui/assets/editor-emoji.js):
  6. place() and sizePanel() stand down on a phone

    • both wrote inline geometry that beat the sheet rule of the canon and pushed the panel past the edge
    • the owner is now written before that turn is taken, or a second press stops closing the panel
  7. The editor fullscreen (plugins/editors/toastui/assets/editor-tags.js):
  8. Escape reaches the fullscreen only when no window stands in front of it

    • one press used to close the file manager and drop the fullscreen at once
  9. The window foot (templates//assets/editors/toastui/skin.css, templates//partials/editor-toastui-files.html):
  10. The file manager takes the canon foot, buttons and status line

    • 74 lines per theme that restated the canon values under sl-fm-* names are deleted
    • the foot now follows --sl-modal-pad, so on a phone it agrees with every other window
  11. The canon gains :hover:not([disabled]) on both foot buttons

    • the guard existed only in the deleted copy, so a disabled button lit up in every other window
  12. Sizes and names (templates/*/assets/css/theme.css, templates/lite/fragments/window-share.html):
  13. sl-modal-md is deleted: it restated the default 560px and the default needs no class
  14. Documentation (docs/WINDOW.md, demo/window-canon.html):
  15. docs/WINDOW.md describes the window as it is: structure, four axes, tokens, data attributes, JavaScript API, naming, where each window lives, traps and a check list

  16. docs/WINDOW-CANON-2026.md is removed; it was a work plan and its work is done
  17. The reference page drops a dead sl-toastui-shot class, draws its gallery with the shipped sl-shot-* rules instead of an inline grid, and states what is rather than what was

Benefits:

  • A window opens where it is meant to, and a hand that reaches for it at once is not punished
  • One declaration of the foot, so a change to the canon reaches the file manager too
  • The reference page cannot show a layout the system does not ship

Technical notes:

  • Visible change in the admin theme: the primary foot button of the file manager now darkens on hover (#076698) where it used to lighten (#207fb6), because the canon derives the hover from --sl-modal-tone while the deleted copy used --sl-color-primary-hover. It now behaves as every other canon button in that theme

  • .sl-modal-info collapses when empty, which the deleted .sl-fm-foot-info did not; the foot keeps its right alignment either way

  • .sl-fm-foot in the admin theme is untouched: it belongs to the file browser, which is not a window
  • Verified in both themes at 1440x900 and 390x844: 37 checks green, centring error 0px, drag jump 0x0, console clean; 829 tests pass

Refactor: nine dialogs of the system become one window with four axes
Автор: Eduard Laas | Дата: 15:23 18.08.2026

Every dialog of the project is now the same native <dialog> under one set of class names, so a window is described once and every theme only sets its own values for it. The program is recorded in docs/WINDOW-CANON-2026.md, which now describes what ships rather than what to do.

Core changes:

  1. The canon (templates/*/assets/css/theme.css):
  2. One block, byte-identical in both themes, replaces five different chromes

    • head plate 42px, ghost action cluster, body with its own scroll, foot with a status line
    • values copied from the editor file manager, which is the window that already worked
  3. Four axes and nothing else

    • size sm 420 / md 560 / lg 880 / xl 1120 / full
    • presentation: modal by default, data-sl-window stands beside the page
    • tone: danger, warn, success paint the icon, the stripe and the primary button
    • foot: present or simply not written
  4. .sl-modal-close and .sl-modal-wide are gone with the markup that needed them
  5. The engine (plugins/system/slaed.js):
  6. The focus trap, the top layer and the return of the focus are the browser's work now
  7. What the platform does not give is written once: setWindowOpen, setWindowClose, setWindowFront, setWindowPlace, setWindowExpand, setWindowBounds, setWindowRelease, setFirstFocus, setPageLock, isWindowModal

  8. Three Escape handlers became one, and it still lets an open speed dial win
  9. The page under a modal window stops scrolling and does not shift sideways
  10. One gallery instead of four (templates/*/partials/window-gallery.html):
  11. The editor gallery of two themes, the admin browser gallery and the lightbox built as a string in JavaScript are now one fragment with three renders

  12. Three sets of data attributes became the data-sl-shot family
  13. core/admin.php and plugins/editors/toastui/driver.php pass data to the same fragment
  14. The file manager and the emoji panel (plugins/editors/toastui/):
  15. Both are dialogs beside the page; the manual aria-hidden, the manual focus return, the manual drag and the fixed z-index ladder 31 / 10020 / 10050 are deleted

  16. skin.css keeps no sl-toastui-window-* rule at all
  17. The panel of the emoji opens above its button when there is no room below it
  18. Windows renamed to one rule (templates//fragments, templates//partials):
  19. confirm-modal, share-dialogs and icon-picker-modal become window-confirm, window-share, window-qr and window-icons

  20. The id sl_icon_modal becomes sl-icon-window; no id of the canon uses an underscore

Benefits:

  • A window is one structure, so a new one costs markup and no CSS
  • The gallery is one file, so a fix to it reaches the editor, the browser and the site
  • Themes stay independent: the block is shared, the values come from tokens

Technical notes:

  • --sl-space-xl is declared in base.css of both themes; .sl-toast consumed it undeclared, which left the toast at its static position and out of sight

  • DeskKeysTest follows the focus and Escape rule into the canon it moved to
  • demo/window-canon.html is one file with no stylesheet and no script of its own, so it cannot drift from what ships

  • No behaviour of the file manager changed except its placing, which the canon owns
Эта неделя (17.08.2026)
Docs: the theme etalon plan gives every visual decision one address
Автор: Eduard Laas | Дата: 15:33 17.08.2026

The two shipped themes become reference etalons for hundreds of independent copies, so the plan fixes the only thing that travels between them: convention. It replaces the wish for consolidation with one machine-checked metric and records the architecture decisions that are now closed.

Core changes:

  1. Theme etalon plan (docs/THEME-ETALON-2026.md):
  2. Records the closed decisions so they are not re-litigated

    • Themes stay independent: no inheritance in Template, no shared core.css
    • No PHP changes: the theme path boundary and the engine grammar stay as they are
    • One canon of names and semantics, values per theme
    • Three CSS files per theme: tokens.css, base.css, theme.css
  3. Carries the measured baseline the audit tool has to reproduce

    • 1164 literal visual declarations in lite/theme.css, 655 in admin
    • 236 selectors shared by both themes, 121 of them divergent
    • 33 same-named templates carrying different markup
    • gradients, transition and z-index are tokenised nowhere at all
  4. Defines ten batches, each with its cause, its steps and its own check

    • admin reaches zero literals first, lite mirrors it afterwards
    • token hygiene runs before the scales, while renaming is still free
    • the public token API is frozen last, once both themes reach zero

Benefits:

  • One address per visual decision, verified by a tool instead of by eye
  • A new theme is created by editing tokens.css and nothing else
  • The etalon stops contradicting itself before hundreds of themes inherit it

Technical notes:

  • No code, no CSS and no template changes in this commit
  • The audit tool, the strict rule file and the baseline screenshots are batch 0
  • Utilities and a shared core were dropped on purpose: a 6% gain against theme independence
Эта неделя (14.08.2026)
Fix: the monitor tells an empty answer apart from a question it was never allowed to ask
Автор: Eduard Laas | Дата: 17:10 14.08.2026

The extension field of the dashboard answered one and the same string whether it had found every module of the directory loaded or had never been able to read that directory at all, so an installation whose extension_dir lies outside open_basedir was told that nothing was missing. The same commit writes down the plan for the journals and for the data around them.

Core changes:

  1. Three states where there were two (admin/modules/monitor.php):
  2. Whether the module directory can be read at all is decided before it is walked

    • extension_dir is not set, lies outside open_basedir, or is not a readable directory
    • The reason travels with the verdict and names both paths, so the answer can be acted on
  3. None now means every module on disk is loaded, and N/A means the directory was never read
  4. The block follows the rules of the project again: names without underscores, no single line if and else in braces, no blank line inside the body

  5. A plan for the journals and the data around them (docs/PRIVATE-DATA-2026.md):
  6. Batch 1: no secret reaches a journal

    • The login report stops printing the password it is handed on a failed attempt
    • The request dump passes through the masking rule Logger already owns, and records the key
names of the session and the cookies instead of their content
  • Batch 2: the installation proves its private directories are private

    • A marker fetched over its own address and judged by the body, because a status code decides
nothing where errors are mapped onto a page
  • Three verdicts and never two: closed, open, and a transport that could not run
  • Batch 3: a server configuration in the delivery, held to the tree by a test that enumerates the directories declaring themselves private and demands the fragment cover each of them

  • Batch 4: the runtime tree out of the document root, as the migration of a major release
  • Batch 5: one prefix per meaning in the journal names

    • error_ is what the system could not do, log_ is what happened
    • The file journal splits into log_file.log for every operation and error_file.log for the
error level alone, hack.log becomes log_hack.log and warn.log becomes log_warn.log
  • The routing follows the levels that are already set, so no record is classified twice

Benefits:

  • A field of the dashboard stops answering a question nobody asked it
  • The decisions taken about the journals are written down with their reasons instead of living in a conversation

Technical notes:

  • No behaviour of the site changes: the monitor reports differently and the document adds no code
  • The plan names functions, files and constants rather than line numbers, so it survives the next edit of the files it points at

  • The label map of the security section keeps the retired keys, so journals already on disk do not lose their names when batch 5 lands

Fix: a long container is judged by what its walk proved instead of refused for its length
Автор: Eduard Laas | Дата: 14:49 14.08.2026

The structural validators of the upload service walk a container to a bounded depth, and three of them refused a file the moment that bound was reached. An ordinary tar of 300 members, a fragmented MP4 and a gzip file of concatenated members were rejected on a build without Fileinfo, while the magic database accepted all three.

Core changes:

  1. Bounded walks that answer at their bound (core/classes/upload.php):
  2. checkTarBody() reads the two closing zero blocks from the end of the file

    • Where the walk reaches the marker it still reads both blocks itself, so a half marker followed
by junk, a missing marker and data running past the end of the file all stay refused
  • The bound alone ends the walk, so the member count of an archive no longer decides its type
  • checkBoxBody() answers the declared track at the bound, so a file of more boxes than the walk visits is proven by its file type box, its brands and the handler of its track

  • checkGzipBody() walks a gzip file member by member

    • getGzipHead() reads the RFC 1952 header of one member at any offset of the file
    • getGzipStop() takes the end of a stream from inflate_get_read_len(), holds the member against
its own checksum and length and returns the offset the next member begins at
  • Bytes behind the last member that open no header are refused, as is a member whose trailer
disagrees with its stream
  1. Regression fixtures (tests/Support/upload_probe.php, tests/Unit/UploadFallbackTest.php):
  2. New bulky scenario: a 300 member tar, a padded archive, a 403 box MP4 and a concatenated gzip are published, each under its own extension and with the canonical type of its format

  3. Their corrupt counterparts stay refused: a broken header inside the walk, a missing end of archive, a half marker, no marker at all, many boxes without a track, a broken second member and trailing bytes behind the last one

  4. Help revision (admin/info/uploads/ru.md):
  5. New section on how the type of an upload is decided

    • Fileinfo is the preferred reader and belongs on the server; the structural walk answers only
where it is absent, does not open or cannot name the file
  • A type the database named against the extension is refused rather than asked a second time
  • One table of what each of the 21 formats has to prove, one of the components a server needs,
and one of the four capability reasons error_file.log distinguishes
  • Two corrections of the catalogue description

    • The upload rule belongs to the module of the open directory, not to the record of all, and the
quota of that module does not limit the administration
  • The template variables list [quot] and the real order behind [width], [height], [tsrc] and [rel]
  1. Task file (docs/UPLOAD-FILEINFO-PLAN-2026.md):
  2. Removed, because the plan it carried is implemented and verified

Benefits:

  • An ordinary long archive is published again on a build without Fileinfo
  • A disguised, truncated or corrupted container is still refused by the structure it claims
  • One page names the preferred reader, the components a server needs and the two different reasons an upload can be refused for

Technical notes:

  • Routes, JSON, the eight key result shape and the database are unchanged
  • No new required extension: inflate_get_read_len() belongs to ext-zlib, which stays a suggestion
  • Verified on a build with the extension and on one without it: the suite, every one of the 21 formats, real world archives, and the HTTP flows of the catalogue, the editor and the frontend

Feature: an upload without a magic database is judged by the structure of its own format
Автор: Eduard Laas | Дата: 12:20 14.08.2026

The upload service gains one structural validator per format, so a PHP build compiled without Fileinfo publishes every one of the 21 allowed types by walking the container instead of trusting a name. The same commit carries the word limit of comments, private messages and the forum, where zero now bounds no word instead of refusing every body.

Core changes:

  1. Content validation without Fileinfo (core/classes/upload.php):
  2. The magic database stays the first reader and the fallback answers only where it cannot

    • Bounded fopen, fread and fseek, so a file of any size is judged without being held in memory
    • Fifteen validators: image type marker, two consecutive MPEG frames, RIFF chunk chain, FLAC
metadata blocks, Ogg page checksum and codec, ISO BMFF brands with the track handler that
separates m4a from mp4, EBML doctype, PDF header and trailer, zip central directory, RAR block
chains, gzip stream against its own CRC and length, 7z start header, tar header checksums
  • A type the database did name is answered unchanged, so a conflict with the extension is refused
rather than asked a second time
  • The check order is fixed: missing, size, transfer and extension answer before anything is read
  • getTypeReader() becomes protected, which is the seam a test closes while every other extension of the machine stays available

  • One validator for both flows (core/classes/upload.php):
  • getFileMime() takes the verified extension and answers the canonical type of the format
  • addRemoteFile() no longer refuses a whole build over the type reader; cURL keeps its own check
  • A missing capability told apart from a refused file (core/system.php, modules, lang):
  • unsupported gets the neutral _ERROR_SERV text in all six locales
  • The three inline mappings of the modules now read the one getUploadFailText() resolver
  • error_file.log distinguishes fileinfo_missing, fileinfo_init_failed, decoder_missing, curl_missing
  • Word limit of zero (core/classes/comment.php, core/classes/privat.php, modules/forum):
  • Zero bounds no word instead of refusing every body, and the longest word is counted in characters
  • The forum setting becomes a number field with its hint instead of a yes or no switch
  • Tests (tests/Support/upload_probe.php, tests/Unit/UploadFallbackTest.php):
  • Every non-image fixture is structurally complete now, checksums included
  • New scenarios: each format without a magic database, the matrix of one body under every foreign extension, corrupted and polyglot bodies, the refusals that come first, and the remote half

Benefits:

  • A production build without Fileinfo publishes uploads again without weakening content validation
  • A disguised, truncated or corrupted file is refused by the structure of the format it claims
  • One mapping explains a refused upload on every screen

Technical notes:

  • Routes, JSON, the eight key result shape and the database are unchanged
  • ext-fileinfo, ext-zip and ext-zlib move from require to suggest in composer.json
  • The suite passes on a build with the extension and on one without it
Docs: the Fileinfo upload plan becomes a task with a named cause and a check per format
Автор: Eduard Laas | Дата: 00:14 14.08.2026

The document stopped being a briefing that asks the reader to confirm a problem and became the task itself: the cause is named, the four points that produce it are given with file and line, and every one of the twenty-one allowed types gets the structural check its fallback must pass.

Core changes:

  1. Statement of the task (docs/UPLOAD-FILEINFO-PLAN-2026.md):
  2. the constraint is stated first: a clean SLAED without Composer or vendor

    • routes, JSON, result shape and the database stay as they are
    • content validation is not weakened, and GD and cURL stay required where they already were
  3. the cause is named: production PHP 8.4.22 built with --disable-fileinfo
  4. The points that produce the refusal:
  5. checkUploadInput() answers unsupported before input, size and extension are looked at
  6. the same read blocks remote upload
  7. getFileMime() answers null when finfo is absent or cannot be created
  8. the route shows unsupported as a format error
  9. The filename contract:
  10. the extension comes from the submitted name and the content from the temporary path

    • the fallback never reads the type off the name the file is finally stored under
  11. The work itself:
  12. the order of checks is fixed so a missing Fileinfo cannot mask missing, size or transfer
  13. one content validator serves local and remote upload, reading through fopen/fread/fseek
  14. a table gives the required structural check and the canonical MIME for each allowed type

Benefits:

  • the reader of the plan can start writing code instead of first reproducing the fault
  • a per-format table makes the acceptance of the change checkable rather than arguable

Technical notes:

  • documentation only: no code, schema or configuration is touched by this commit
Style: the private message strings say the shortest true thing and stop starting in lower case
Автор: Eduard Laas | Дата: 00:14 14.08.2026

Every string this page shows stands in a chip, a shelf note, a card or a counter, and never inside a sentence, so each one begins with a capital and drops the words its box cannot carry. The forward prefix stops being an untranslated abbreviation and becomes the noun each locale really uses, the way the reply prefix already did.

Core changes:

  1. The chips of the compose header (lang/*.php):
  2. _PRWAIT reads «Интервал 60 сек.» where it read «интервал между отправками 60 секунд»
  3. _PRLIMTO and _PRLIMSUB name the field and the bound and nothing else

    • «Имя, до 25 символов» and «Заголовок, до 100 символов»
    • all three now stand on one line at 1240 and 800 and on two at 390, where they wrapped
  4. The recipient card (lang/*.php):
  5. _PRBOXFULL, _PRBOXNEAR and _PRBOXROOM drop «получателя»

    • the name of the account stands one line above them in the same card
  6. The forward prefix (lang/*.php):
  7. _PRFWD was the untranslated Fwd in all six locales

    • it becomes «Пересылка», Forwarded, Weitergeleitet, Transfert, Przekazane, «Пересилання»
    • a forwarded subject now reads «Пересылка: …» the way a reply reads «Ответ: …»
  8. Capitals where a string stands alone (lang/*.php):
  9. _PRFREE, _PRSHOWN and _PRNOLIMIT, plus the Polish _PRFOCUSN

    • an outbox holding nothing prints _PRNOLIMIT with no counter before it, so it starts a line
    • the counter prints _PRSHOWN alone whenever no search is running

Benefits:

  • a chip says what it means without being cut or wrapped
  • nothing in the interface is left in an abbreviation only one language reads

Technical notes:

  • values only: no constant is added, renamed or retired, and every placeholder is preserved
  • all six locales carry the same wording in the same change
  • docs/PRIVATE-MESSAGES-2026.md records the pass and the widths it was measured at

Всего: 1122 на 113 страницах по 10 на каждой странице

1 2 3 4 5 6 7 8 9 10 113
Хотите опробовать SLAED CMS в действии?
Идеи и предложения
Обратная связь
Подтверждение

Поделиться
QR-код