Официальный сайт SLAED CMS
Журнал изменений
The run of the panel and the site in a real browser found small classes, sizes and lists that each had a look of their own. This change moves them onto the shared parts of the two themes: one height for a field, one copy button for code, one file door, one list canon, one segmented switch and one drawer. The type form of Node becomes tabs of one form, and config/points.php ships in the shape the panel writes.
Core changes:
- The changelog in the panel (modules/changelog/admin/index.php, modules/changelog/common.php, modules/changelog/index.php, modules/changelog/admin/lang/*.php, modules/changelog/admin/info/ru.md):
- changelog() draws a table of getTplAdminList(), one row per commit: hash, title, author, changes and files (with
statistics on a local Git), and date as a moment
- the "i" of a row holds the body through $prs->filterDoc(), the e-mail and the per-file +/- lines; the search word is marked by filterTextHighlight() in the title and the body
- the filter is fragments/list-filter.html in the tab head (word, author, file except for GitHub, date from/to); the pager reads num and the per-page choice through getListLimit(), with perpage as the base
- an error of loading or an empty result goes to none_text (_NONE_FOUND under a filter, else _NO_INFO)
- rendpage() is gone; the panel no longer groups by date and no longer makes the canonical redirect
- chlogCanonicalRedirect() drops its $base argument and serves only the site
- The help describes the table, its columns, the filter, the pager and "Группировать по дате" acting on the site alone
- The forums in the panel (modules/forum/admin/index.php, modules/forum/admin/info/ru.md):
- forum() builds its list with getTplAdminList() instead of a bare table in a box: the description sits in the "i" of the row, the status is a lamp, every column sorts, and the view switch and key tip of the canon stand above it
- Node in the panel (modules/node/admin/index.php, modules/node/admin/lang/*.php, modules/node/admin/info/ru.md):
- add() opens the form of the first type the user moderates right away; a select "Тип" (list-filter, is_now) in the tab head switches the type, which replaces the page of links that listed the types
- getNodeTypeRows() becomes getNodeTypeTabs(): the type form is six runtime sub-tabs of one form (_GENPREF, _LIST,
_NODE_FEATURES, _NODE_FLOW, _NODE_ROLES, _NODE_INTEG), and the form carries is_valid
- each on/off setting (alphabet, every feature and integration, guestok, report, canlink, active of a role) is a Yes/No radio group of getTplRadioGroup() with its own caption, in place of a checkbox labelled "Да"
- the sort direction has its own row (_NODE_ORDDIR new); minimum and maximum of a role are two labelled rows
- each resource role is a partials/toggle-form-block.html block with its key in the cap, in place of the repeat fragment; _NODE_ROLEOPTS is gone
- The profile of a new type is a select "Профиль" in the tab head with an empty choice, in place of a row of links
- import() takes the file through getFormFileField()
- The help describes the "Добавить" type selector, the tabs of the type form, the profile selector and the role blocks
- The file door of an ordinary form (core/helpers.php, public/templates/{admin,lite}/fragments/file-field.html, public/plugins/system/slaed.js, admin/modules/update.php, lang/*.php):
- getFormFileField() prints fragments/file-field.html with is_form: a button names the action by _FILEPICK, a chip
shows the name and size of the picked file, a cross clears it
- the form door carries data-sl-file-form and no data-editor, prints no path or address carrier, and keeps a required file field out of sight (sl-visually-hidden, tabindex -1), so the browser refusal points at the door
- setFileDoors() and setFileDoor() of slaed.js open the browser picker, show the name and size, clear the field and return the focus to the button
- "Загрузить архив" of update is now a pane of its own (fragment pane, icon cloud-upload) and takes the door
- getTplUserSearchInput() no longer marks its input as required
- The drawer menu of the site on a phone (public/plugins/system/slaed.js, public/templates/admin/assets/js/admin-ui.js, public/templates/lite/partials/site-header.html, public/templates/lite/assets/css/theme.css, lang/*.php):
- setDrawer() moves from admin-ui.js into slaed.js and finds its menu by the aria-controls of the toggle, so one
drawer serves #sl-menu of the panel and #hmenu of lite
- the page goes inert while the drawer is open; Esc, the scrim, the cross or a window opened from the menu close it, and it closes once the toggle is hidden; the focus returns to the toggle
- The header of lite gets the toggle sl-menu-btn with _MENU, the scrim sl-menu-scrim, and #hmenu as a nav with the cross sl-menu-close; below 900 px the menu and the search form one column of the drawer, above it the bar is unchanged
- Sizes and small classes of both themes (public/templates/{admin,lite}/assets/css/{base,theme}.css, public/templates/{admin,lite}/fragments/code-block.html, public/templates/admin/partials/{layout-screen,statistic-cockpit,toggle-form-block}.html, admin/modules/statistic.php, admin/info/fields/ru.md):
- base.css of admin gives every one-line input and single select the height --sl-size-control
- The copy button of a code head and of the link window of the builder is .sl-code-copy in both themes, a quiet square of --sl-size-chip, larger on a touch screen, in place of the borrowed .sl-modal-act
- "Сейчас" and "Вчера" of the statistic cockpit are a plain sl-seg with its knob (rail stat-day); the server sets the active cell from is_now and admin-ui.js toggles sl-is-active with aria-pressed; .sl-cockpit-set is gone
- partials/toggle-form-block.html puts the name with the + toggle in a cap and its rows under it at the full width of the box; the side panel of the builder keeps them stacked; the help of the additional fields follows
- A list filter whose only fields are is_now selects shows its OK button only without scripts (@media (scripting: enabled))
- The chips of the private messages take --sl-size-chip, their bulk bar field --sl-size-control
- The changelog CSS of the admin theme is removed
- Points config (config/points.php, docs/POINTS.md):
- config/points.php ships in the shape setConfigFile() writes: actions before active, one key per line, so an unchanged save of the panel leaves the file as it is
- Tests (tests/Support/config_probe.php, tests/Support/route_probe.php, tests/Unit/{ConfigFileTest,EditorWindowTest,PointTest,AdminSecretTest,ListPickTest}.php):
- getProbeShipped() finds every setConfigFile('<name>.php') of admin, modules and core, saves each shipped file unchanged and reports any file that moves, ignoring the header year; anUnchangedSaveKeepsEveryShippedFile checks it
- anOrdinaryFormSendsItsFileThroughTheSameDoor checks the form door in both themes, getFormFileField(), _FILEPICK in six locales, update and Node import on the builder, and setFileDoors() started by slaed.js
- PointTest expects the key order actions, active
- route_probe and aDelegatedAdministratorWritesNoSecret: a changelog post of a delegated administrator that names the GitHub fields is refused whole, and the same form without them saves perpage and keeps the token and the source
- ListPickTest: a comment names the clear form by its op
- UI tools (tools/ui-contract.php, tools/ui-shots.json, tools/ui-contrast.json, tools/ui-audit-baseline.json):
- ui-contract drops pmf-filter, the exceptions of the admin changelog classes and of fragments/changelog-commit.html, and adds the theme differences of .sl-menu-btn, .sl-menu-btn .bi and the 900 px .sl-menu-close
- ui-shots captures drawer-open on the front page (optional step)
- The contrast list and the audit baseline are regenerated
- Docs (docs/TEMPLATES.md, docs/WINDOW.md, docs/UPDATE.md, docs/VERSIONS.md):
- TEMPLATES: the toggle form block, the is_now select of a list filter, the drawer of a phone, the screen switch as the plain sl-seg
- WINDOW: .sl-modal-act only for window actions and .sl-code-copy for code; the form door of getFormFileField()
- UPDATE: the changelog*.html templates and the changelog CSS stay only in lite
- VERSIONS: the sections of 2026-11-05 and 2026-11-06, including this change under "The look is one system"
Benefits:
- One field height, one copy button, one file door, one list canon and one drawer across both themes, so a fix lands in one place
- The changelog and the forums of the panel sort, switch views and page like every other list
- A shipped config the panel writes no longer changes on its first unchanged save
Technical notes:
- No database change
- Removed templates: admin partials/changelog.html, partials/changelog-body.html and fragments/changelog-commit.html, changelog-date-header.html, changelog-stats.html
- Breaking for a custom theme: the tokens --sl-pmf-filter-height (lite) and --sl-changelog-width, --sl-changelog-body-border, --sl-changelog-files-height, --sl-changelog-stat-width (admin) and the class .sl-cockpit-set are gone; the admin theme has no .sl-changelog-* rules
- The admin changelog list pages by num instead of page, and its filter no longer redirects to a canonical address
- New constants: _FILEPICK and _MENU in lang/.php, _NODE_ORDDIR in modules/node/admin/lang/.php
- Removed constants: _NODE_ROLEOPTS; _CHLOG_FILTER, _CHLOG_SEARCH_PH, _CHLOG_AUTHOR_PH, _CHLOG_FILE_PH, _CHLOG_FILTER_BTN, _CHLOG_RESET_BTN, _CHLOG_TOTAL, _CHLOG_FILTERED, _CHLOG_PAGE, _CHLOG_COMMITS, _CHLOG_COMMITS_REPO, _CHLOG_ERR_NO_COMMITS of the changelog admin
- The on/off settings of the Node type form now post 1 or 0 from a radio group under the same names
- getNodeTypeRows() is replaced by getNodeTypeTabs(); setDrawer() leaves admin-ui.js for slaed.js
- config/points.php changes only its layout and key order; its values are the same
php tools/node-profile.php stopped at "Invalid node input: name" before measuring anything, and two of its limits had fallen behind the code. The full run of 100000 materials in fourteen types now passes without a failure.
Core changes:
- The scratch configuration (tools/node-profile.php):
- setProfileConfig() drops the types the committed config/node.php names, with their fields, upload rules and rating
rules, as deleteSetupTypes() of setup.php drops them before the profiles are imported
- the committed config names the types of the stand, so every profile met its name taken in checkNewName()
- The budgets (tools/node-profile.php, docs/NODE.md, tests/Unit/NodeServiceTest.php):
- A physical delete costs six Node statements: getNodeHead() reads the head with the name of the type and then the type, before the locks of type, material and resources and the DELETE; PBUDGET 'delete' and the table of docs/NODE.md say 6, as the description of the delete there already listed
- A row of a list page passes six reads, not four: the two paths of NodeQuery::getPathSql() joined the page on 2026-10-14, after the bound was written; getProfileBound() and the formula in docs/NODE.md take 6 x page size
- The comment of NodeServiceTest names six Node statements of a delete
Benefits:
- The load profile of Node can be run again before the release
- Its limits fail on a real regression, not on the code that was accepted
Technical notes:
- No change of the core, the database or a URL; the tool runs by hand only
- Result: list docs 488 of 550 rows, list media 1100 of 1178, delete news 6 of 6 statements, no budget overrun and no full scan
An audit of the shipped types against the modules sites use most found four types a profile alone can make. A clean installation now creates and activates fourteen types; the events, vacancies and a lifetime of a classified ad need the core and wait in their own plan.
Core changes:
- The profiles (modules/node/profiles/album.json, portfolio.json, board.json, reviews.json):
- album: view default with tiles and cards, a cover and a gallery of up to 100 images, every feature of pages
- portfolio: view article, a cover and a gallery of up to 30 images, the fields client, year, site and services; no submit, no comments, no rating
- board: view default, a cover and a gallery of up to 10 images, the fields price (decimal, scale 2), city, phone and e-mail; submit by users with moderation and schedule, so a moderator may set an end of the ad
- reviews: view default, the required field stars (int 1-5), workflow access all, so a guest may post, with moderation
- the field is stars, not score: score is a column of _nodes and no field may take its name
- Sorts 110 to 140 after the ten profiles; uploads and rating empty, as every shipped profile
- Language (lang/*.php):
- _BOARD, _PORTFOLIO, _REVIEWS as titles of the types; _NODE_CITY, _NODE_CLIENT, _NODE_PHONE, _NODE_PRICE, _NODE_SCORE, _NODE_SERVICES as labels of the fields, in six languages; the gallery takes the existing _ALBUM
- Tests (tests/Unit/NodeProfileTest.php, tests/Support/install_probe.php):
- NodeProfileTest checks fourteen profiles: names, the order of sort, settings, roles, fields, the guest access of reviews; the clean installation, the exports, the panel offer and the write and view of a material of every type
- The probe keeps IPROFS as the ten profiles that stand for modules of 6.2, which the update rehearsal reads, and adds ISHIP, every shipped profile, for the installation checks; it writes the fields of the new types
- Docs and help (docs/NODE.md, docs/ARCHITECTURE.md, modules/node/admin/info/ru.md, tools/node-profile.php):
- NODE.md lists the four in "Replaced modules" and in the tables of "Shipped profiles" with their fields
- The help of Node names fourteen types; the comments of the load profile no longer count ten types
Benefits:
- A new site has a gallery, a portfolio, classifieds and reviews without building a type
- The four take one click in "Новый тип" on an existing site
Technical notes:
- No database or URL change; a clean installation creates four more types and their routes
- The board shows the phone and the e-mail of an ad publicly, as a classified ad needs them
The modules news, faq, files and the others are Node types since 8.0, and the panel showed only the card "Материалы": a newcomer did not find "Новости". Every type an administrator moderates is now a section of the panel, shown apart from the modules, since a type is no module.
Core changes:
- The sections of the panel (core/system.php, core/admin.php):
- getAdminSectionList() adds the Node types after the site modules: keyed by the name, opening name=node&type=<name>,
the icon of getIconName(), the type itself under 'node'
- a super administrator sees every type, a module administrator the types of their rights node-<name>, as the list of materials does
- getModuleLabel() answers the title of a type, so a pin and "Все разделы" no longer show the raw key
- getAdminQueues() gives a queue of a type the type as its module, so its count stands on the card of the type
- getAdminSectionData() answers the types as a third group "Типы материалов", always last
- The home and the menu of the panel (admin/index.php):
- getAdminMenu() takes the row of the section; a type opens its list, carries its key as subtitle and the dial of the
type: edit, categories when on, site when active, help of Node, pin
- a type is turned on and off in the types of Node only, the card carries no switch
- getAdminPanel() draws the panel "Типы материалов сайта, созданные в модуле «Материалы»" after the site modules
- getAdminPanelBlocks() draws the block "Типы материалов" after "Модули" and marks the open type, not Node, as current
- setAdminOption() takes an order of the menu as long as the modules and the types together
- Language and help (admin/lang/*.php, admin/info/panel/ru.md, docs/ARCHITECTURE.md):
- _ADM_TYPES (menu, all sections) and _ADM_TYPESPANEL (home) in six languages
- The help of the panel describes the block, its queue and its dial; ARCHITECTURE names the types in the one list of the sections
- Tests (tests/Unit/AdminGuardTest.php):
- The guard of the menu order checks the limit of modules plus types
Benefits:
- A newcomer finds "Новости", "Каталог файлов" and their own types on the home of the panel
- The home, the menu, the pins, Ctrl+K and the site menu read one list and agree
- The queue of a type stands on the type that waits
Technical notes:
- No database, URL or configuration change
- The card "Материалы" keeps no queue chip; the queues of the types stand on their cards
The form of a forum post without a category answered 500: add() read no row of _categories and handed null to is_acess(). A category that is not there, or one of another module, now counts as none in the form and in the three writers of the forum, as the list of forum() already does.
Core changes:
- The forum (modules/forum/index.php):
- add() answers setError(404) for no category, a missing one, a missing post and a post whose category is gone or belongs to another module, as view() does for a missing topic
- send(), move() and delete() take such a category as none and go back to the forum writing nothing
- a category of another module took the form of a new topic (rights 0|0) and its post, move and delete ended in an SQL error of IN (), as catids() names no category of another module
- The four reads of a category ask modul = :mod
- Tests (tests/Support/route_probe.php, tests/Unit/FileAccessTest.php):
- The run files of route_probe.php asks the form with no category, a missing category, post and topic, a post whose category is gone and one of a category of news, and posts send, move and delete naming them
- aForumOfNoCategoryAnswersNotFound: six forms 404 and the writers 303 with the rows unchanged; red on the old code with nine answers 500, two forms 200 and three SQL errors
Benefits:
- No 500 and no SQL error from an address of the forum a visitor can type or a stale form can post
- The forum reads only its own categories, in the list and in every handler alike
Technical notes:
- No database, URL or language change
- A forum address with a category of another module now answers 404 instead of a form
Two pieces of work land together by the word of the owner. The buttons, chips and forms of both themes get one look: an icon before the words, a burst on press, a named value in every chip, captions at the top of their field, and the material form of the site reads its categories, resources and downloads in one place. The step BROWSER-QA.21 brings the system and the modules of the panel onto one standard: a setting that is a part of a Node type, a manual run of a job, a write of search, the modules a form offers, a confirmation and the part of the super administrator.
Core changes:
- Buttons and chips (public/templates/{admin,lite}/fragments/.html, public/templates/{admin,lite}/partials/.html, public/templates/lite/sections/.html, public/templates/{admin,lite}/assets/css/.css, public/plugins/system/slaed.js, core/{helpers,system,user}.php, admin/index.php, admin/modules/.php, modules//index.php, modules/*/admin/index.php):
- fragments/button.html of the panel is always a <button>, never an <input>, so a bi glyph stands before its words; every button, form submit and navigation link passes its icon_name
- setPressBurst() of slaed.js gives each .sl-but* and .sl-but-mini the burst of the favourite star on the tokens --sl-fav-*
- Every chip that shows a size, a count, a date, a status, a module or a rating carries a title of an existing constant
- A caption stands at the top of its field in .sl-form-row, .sl-value-row and .sl-div-item
- form-submit.html takes a list acts of named submit buttons: the forms of forum and node send Preview and Send as two buttons instead of the select posttype and OK
- The material form and view of the site (modules/node/{index.php,admin/index.php,admin/info/ru.md,lang/.php}, public/templates/lite/fragments/{check-list,repeat}.html, public/templates/lite/fragments/node/download.html, public/templates/lite/partials/node//view.html, public/plugins/system/slaed.js):
- The main and the additional categories are one tree of checkboxes; the starred row is the main one, setCategoryMain() keeps the star on a checked row and the server takes the first checked row when none is starred
- _NODE_MAINCAT and _NODE_SUBCAT in six locales; the select cid is gone
- getNodeAssetFields() gives each resource role its own form row with the add control before its label; the role of a download is labelled _NODE_ATTACH
- The related materials are offered to a moderator alone
- getNodeAssetView() answers the downloads apart, and the view shows them at the foot beside the rating with the chips _SIZE and _NODE_DLOADS
- The cabinet and the comments (modules/account/{index.php,lang/.php}, public/plugins/system/sound.js, core/user.php, lang/.php, public/templates/lite/partials/account-*.html):
- Each sound zone of the profile is a Yes/No switch with its own caption (_ACCOUNT_SNDMSG new, _ACCOUNT_SOUND gone); sound.js keeps the zone on this device from the checked radio
- The avatar field of the profile is the file manager field itself, without a row of its own
- A comment awaiting review is answered by _COMMENTS_WAIT as a success note in #repcstat, and the moderation note stands in #repcstat instead of above the form
- A setting that is a part of a Node type, a manual run and the writes of search (core/admin.php, admin/modules/{fields,ratings,uploads}.php, modules/{search,sitemap}/admin/index.php):
- updateNodeTypeParts() is the one answer of a section that owns a part of every Node type: its config result is taken first, so a refused write moves no type
- fields, ratings, uploads, search and sitemap call it; search and sitemap no longer write the types before the config or skip a type without its version
- add() of sitemap checks the answer of addSchedulerRun() as run() of the scheduler does and names the reason of a run that did not happen
- editsave() of search says success only after its write, refuses an empty word by _CERROR with is_required on the field
- clear() of search runs the one query of its mode; 0 days, no module, a module out of the list and an unknown or missing mode delete nothing and answer _ERROR
- The modules a form offers, confirmations and the super administrator (modules/{search,voting,master,sitemap,changelog}/admin/index.php):
- getSearchModList() is the one list of search for its filter, its selects, the edit and the clear; an edit keeps the module its row already names
- getVotingModList() is the one list of voting for its select and its save, with the module the poll already names
- The edit form of a poll only saves: the select posttype with its delete is gone, a poll is deleted from the list with its undo window
- The moves to beta and to stable of a release and the accept of a note in master ask a confirmation
- xsledit() and xslsave() of sitemap send a delegated administrator back to the tab with _ACCESSDENIED instead of die(); configsave() of changelog refuses a save that carries the GitHub fields from a delegated administrator
- Help, docs and tests (modules/{search,sitemap,voting,changelog,master}/admin/info/ru.md, docs/TEMPLATES.md, config/layout.php, lang/ru.php, tests/Unit/.php, tests/Support/.php):
- The help of search, sitemap, voting, changelog and master describes the modes, the refusals, the confirmations and the one list
- docs/TEMPLATES.md: the caption at the top, the named chip, the burst and the icon of every button
- The shipped layout names the current version 8.0.0; _PREVIEW reads "Предпросмотр"
- ListPickTest: a clear deletes only what its mode names, an edit keeps the module of its row; ConfigFileTest: a type part follows its config through one helper
- AdminGuardTest, AdminLogTest, LayoutTest, NodeRouteSeoTest and route_probe follow the flash of sitemap, the delete of a poll from the list, the icon of a link, the category tree and the related field of a moderator
Benefits:
- One look of a control across the site and the panel, and one place for the categories and the files of a material
- No save of a module claims success it did not have, and a type part never moves apart from its config
Technical notes:
- No database or URL change
- The post field posttype of the poll form and the select cid of the material form are no longer sent; the server of node still reads cid from the starred row
- New constants: _COMMENTS_WAIT, _ACCOUNT_SNDMSG, _NODE_MAINCAT, _NODE_SUBCAT, _NODE_ATTACH, _NODE_DLOADS; _ACCOUNT_SOUND removed
The batches BROWSER-QA.17 to 20 bring the duplicates the browser run found onto one standard each: the right of a module on the site, the token of a site write, the unlink of an OAuth login, the ban list, the login mail and the password rule, one writer of a block row for both screens, one owner of the block columns, one check of the site name and logo, the language files written whole, and one split of a replacement rule. Two reds of the full run and the disk of the monitor are corrected on the way.
Core changes:
- The site (modules/{account,contact,forum,node,recommend,rss}/index.php, core/security.php, core/classes/comment.php, core/user.php, core/system.php, public/plugins/system/slaed.js, public/templates/{admin,lite}/fragments/button.html):
- A closed profile, its private rows and checkProfileFile(), getProfileLastView() and Comment::getMode() open to is_moder('account') instead of any administrator
- getRssView() refuses an empty address itself; the page of rss calls it only for a sent feed form
- An empty comment is refused by the server alone in #repcstat and cleared by a stored one
- the alert() of setComShow() and the branch hx_on_click of both button.html are gone
- checkSitePost() in core/security.php checks every write of forum, contact, recommend, account and node with the token of the module scope; checkForumPost() is gone
- The captcha of recommend follows the switch contact, _CAPTCHA_CONTACT in six locales
- People and safety (core/classes/oauth.php, core/admin.php, core/security.php, admin/modules/{admins,security,logs,groups}.php, modules/account/admin/index.php, lang/.php, modules/account/lang/.php):
- Oauth::deleteLink() is the one writer of an unlink: the panel passes force for the last login method, the site names a provider not linked by _ACCOUNT_NOLINK
- the forced unlink of the panel clears a link whose user row is gone
- A ban of an address goes through getBanList() (expired rows dropped, a manual one kept past the cap); both ban forms are told by kind
- addFormMail() in core/admin.php is the one writer of the login mail of admins and account and of the ban mail, sent only with a new password
- the login mail of a user of the panel no longer joins the nick and the password by a literal \n
- checkPassRule() checks minpass for the registration, the password change of the cabinet, admins, account and the first administrator; _CHARMIN moves to lang/*.php and the swapped _NOPASS of de and en is set right
- Every credential field of the site and the panel has the type password or email
- The date filters of logview(), logins() and getPointsJournal() read getVar(..., 'date', '')
- The blocks (core/admin.php, core/classes/layout.php, admin/modules/{blocks,layout,modules}.php, admin/lang/*.php):
- setBlockRow() is the one writer of a row of _blocks for blocks and the publication of the builder: the room of the text, a feed that fails at a new address refused with _RSSFAIL, an empty HTML block refused, bkey never taken from a post, bpos and weight left to setBlockOrder()
- A system block is neither offered for deletion nor deleted on both screens (_BLOCKS_SYSKEEP); a refused publication names its block (_LAYOUT_BLKBAD)
- getBlockSpec() is the one spec of the block fields read by both forms and the writer
- Layout::getPageColumns() answers null for the page of a module: the builder shows its columns with a link to their owner form (_LAYOUT_COLSOWN, _LAYOUT_COLSEDIT) and stores none; _BLOCKS_PAGEHINT is gone
- The site in the panel (core/admin.php, admin/modules/{config,layout,lang}.php, core/classes/parser.php, admin/lang/*.php):
- filterSiteBrand() is the one check of the site name and logo for the settings and the builder: a name of up to 255 signs without control signs kept as typed, a logo that is in images/logos/ of the theme; the settings refuse by _ADM_BADVAL with the label of the field
- save() of config writes global.php on the file as it stands and no longer copies webroot, editor.code, geoip_asn, geoip_country and mtemp
- save() of lang writes each locale through setConfigSource() and names a locale it could not write (_LANG_NOWRITE); fileedit() shows the warning of checkPerms()
- A | in the word or the replacement of a rule is refused with the numbers of its fields (_REPLACE_BAR); Parser::replaceText() splits a rule once, like the form
- The monitor (core/monitor.php, admin/modules/monitor.php, admin/lang/*.php):
- The disk is measured at BASE_DIR, not the working directory, and its scale is labelled _ADM_DISKUSED, as free space excludes the blocks reserved for root
- Help, docs and tests (admin/info//ru.md, modules/account/admin/info/ru.md, docs/ARCHITECTURE.md, docs/NODE.md, tests/Unit/.php, tests/Support/*.php):
- The help of admins, account, blocks, config, lang, layout, modules, monitor and security describes the current state; ARCHITECTURE and NODE describe the delivery of the layout and the owners of the block columns
- ReplaceRuleTest: a | in a rule is refused, the parser splits a rule once; MailConfigTest: the settings write global.php on the base
- BlocksTest, LayoutTest, LayoutDraftTest, LayoutPublishTest, EditorBreakTest, OauthLinkTest, ListPickTest, RequestWatchTest, RouteWriterTest, FeedTest, CommentTransportTest, UploadIntegrationTest and AdminGuardTest on the new standards
- LayoutTest follows the shipped layout of slaed.net with shipped false; the long line of AdminListRowTest is split
Benefits:
- One mechanism per job across the site and the panel, so a fix lands once and both screens agree
- A refusal names its field, locale or block instead of a silent save or a cut rule
Technical notes:
- No database or URL change
- The site name saved by the settings is no longer HTML-escaped in config/global.php; every page escapes it on output
- New constants in six locales: _ADM_DISKUSED, _BLOCKS_SYSKEEP, _LAYOUT_COLSOWN, _LAYOUT_COLSEDIT, _LAYOUT_BLKBAD, _LANG_NOWRITE, _REPLACE_BAR, _ACCOUNT_NOLINK; _BLOCKS_PAGEHINT removed, _CHARMIN moved to lang/*.php
- checkForumPost() is removed in favour of checkSitePost()
A config write that fails is no longer reported as saved: every setConfigFile() of the panel reads its result and writes only the changed keys on the base. The answers of the panel follow one standard each: a missing token and a gone record go back to the form or the list with a flash, the refusals of a form are a list over the form again with what was typed, and a count after a POST travels in the flash.
Core changes:
- A config write (admin/modules/.php, modules//admin/index.php, core/security.php):
- The result of every setConfigFile() is read; a refused save says getConfigJournal() ? _CONFIG_PENDING : _ERROR_UP
- the writes of getSecret() and addHackReport() are logged when they fail
- the admin file of security is moved back when its write fails, the ban mail is queued only after its write
- bansave() and passsave() of security, save() of update and rss, reindex() and modadd() of search, replacesave() of config, status() and save() of modules write the changed keys on the base
- A missing token (admin/modules/blocks.php, admin/modules/database.php, modules/account/admin/index.php, modules/forum/index.php, admin/index.php, admin/lang/*.php):
- filecode() of blocks, dump() of database, addsave() of account (an empty page before), send(), move() and delete() of the forum and the logout answer the flash _TOKENMISS back to the form or the list
- The literal of a run of dump() that is already active is _DB_RUNBUSY in six locales
- A record that is not there (admin/modules/{admins,blocks,comments,groups,lang,modules,newsletter}.php, modules/{account,master,search,sitemap,voting}/admin/index.php):
- add() and delete() of admins, add() of account, groups, voting and newsletter, edit() and filecode() of blocks, edit() of comments and search, fileedit() of lang, edit() of modules and share() of master go back to their list with _NONE_FOUND
- no empty form from a missing row, no alert in place of the form, no redirect without a word
- edit() of layout answers the editor window of the builder and keeps _NONE_FOUND inside it
- A folder of xslsave() of sitemap that cannot be made is named _ERROR_UP
- The refusals of a form (admin/modules/blocks.php, admin/modules/groups.php, admin/modules/newsletter.php, admin/modules/uploads.php, admin/index.php):
- The refusals are a list in messages, never a joined text: groups, newsletter, the login and the first administrator of the panel
- addsave() and editsave() of blocks answer their form again with what was typed instead of a bare page with a back link
- The alert of uploads() that nothing fed is gone
- A count after a POST (modules/search/admin/index.php, admin/modules/security.php, admin/lang/*.php):
- reindex() and modadd() of search flash their count by sprintf(): _SEARCHAUTODONE with %d, _SEARCH_ADDED in six locales; the flags &reindex= and &pick= are gone
- The ban list flashes _SUCCSAVE or _MAIL_SEND instead of an empty flash and &send=1
- Help and tests (admin/info/blocks/ru.md, modules/search/admin/info/ru.md, tests/Unit/{ConfigFileTest,AdminGuardTest,BlocksTest,GroupFormTest,RouteWriterTest}.php, tests/Support/{pick_probe,route_probe}.php):
- The help of blocks and search describe the form again and the count in the flash
- ConfigFileTest: no writer drops its result, a refused save is named, the part writers write on the base
- AdminGuardTest: the missing token, the gone record, the refused form and the count, each on its standard
- BlocksTest: a refused block shows its form again with the typed title and the reason; RouteWriterTest: a user save without the token goes back to its form and writes no row
- GroupFormTest reads the refusals as a list
Benefits:
- No save of the panel claims success it did not have, and a refusal always names its reason where the work was
- One answer per situation across all sections of the panel
Technical notes:
- No database or URL change; the query flags reindex, pick and send of the panel are no longer read
- _SEARCHAUTODONE takes a count placeholder in all six locales
The key tip of the lists stands once per list after the view switch and now also ends the bar of the catalogue and of the file window of the editor, with the keys of the file desk. The properties column of both file screens starts closed and gives its width to the list. The action log is read in "Журналы" by its module filter instead of a link in every section head, and the Russian language files lose their punctuation and spelling slips.
Core changes:
- Key tip of the file screens (core/helpers.php, core/admin.php, public/templates//fragments/pager-keys.html, public/templates/admin/partials/file-browser.html, public/templates//partials/file-manager.html, public/plugins/system/filemanager.js, lang/*.php):
- getFileKeysView() builds the branch is_desk of pager-keys.html: arrows, Home and End, Space or Ctrl with a click, Shift for a range, Enter, the right button
- Enter opens in the catalogue (_UPLOADS_OPEN) and inserts in the window (_EDITOR_INSERT); Esc is listed in the window alone
- _EDITOR_DESKKEYS, _EDITOR_DESKARROW, _EDITOR_DESKWALK, _EDITOR_DESKEDGE, _EDITOR_DESKCLICK, _EDITOR_DESKMARK, _EDITOR_DESKSPAN, _EDITOR_DESKRMB, _EDITOR_DESKMENU in six locales
- The catalogue keys of the window step aside for the tip, a role="button", as for the other controls of its bar
- The tip is hidden on a touch screen in both themes
- Properties and dates of the file screens (public/templates//partials/file-.html, public/templates/admin/fragments/file-browser-row.html, public/templates//assets/css/theme.css, core/admin.php, lang/.php):
- A button "Свойства" at the end of the bar opens and folds the properties column through data-sl-toggle, closed by default and remembered by the browser
- A closed column gives its width to the list; each row keeps one line and cuts a long name with an ellipsis
- The date of a row is shown to the minute (_TIMESHORT), the full time in its title
- Lists of the panel (core/helpers.php, public/templates/admin/partials/admin-list.html, public/templates/*/fragments/pager.html, public/templates/admin/assets/css/theme.css):
- getTplAdminList() passes the scope keys; the tip stands once after the view switch with pages or without, and the pager of a list leaves it out
- The row under the table stands only for a pager or a bulk action
- A key plate keeps its width and line, so a narrow tip wraps the words beside it
- One journal of the panel (core/helpers.php, admin/info/logs/ru.md, admin/info/update/ru.md, modules/master/admin/info/ru.md, docs/ARCHITECTURE.md):
- getTplAdminTabs() no longer adds "Журнал действий" to the head of a module; the actions of one module are read in "Журналы" by the filter "Модуль"
- Language files (admin/lang/.php, lang/ru.php, modules//lang/ru.php):
- Russian values corrected: commas, dashes, hyphenated compounds (IP-адрес, HTML-блок), spelling and the full stop at the end of a sentence
- _SETUP_STEP starts with a capital in English
- Reference, contract and tests (docs/TEMPLATES.md, admin/info/uploads/ru.md, tools/ui-contract.php, tests/Unit/PagerKeysTest.php, tests/Unit/AdminLogTest.php, tests/Unit/DeskKeysTest.php, tests/Unit/RouteParseTest.php, tests/Support/route_probe.php):
- The key tip of the file screens and of the lists in "Admin List Contract" and the pager table; the catalogue in the help of "Файловый менеджер"
- The divergence of .sl-pager-tip kbd between the themes carries its reason: the panel shares the plate with its rows picker
- PagerKeysTest holds the tip of both file screens in both themes and its constants in six locales; AdminLogTest that no module head links the journal
- The forms probe writes one journal, since the list of "Журналы" no longer reads as filled through the link of the head
- RouteParseTest expects the corrected title "Топ пользователей"
Benefits:
- One key tip explains every screen with keys, on the same fragment and the same constants
- The file list gets the width it needs, and the journal has one place to be read
Technical notes:
- No database or URL change; admin.php?name=logs&op=logview with modul= stays the address of a module's actions
- _SEC_STAT_A stays as the name of the admin journal in logs.php
The version, the data marks and the texts of the product move from 6.3 to 8.0. Both themes share one run of a figure and one light round a frame, the entry animations of the panel are gone, and the waiting queues of the admin menu are counted in one statement for all Node types. Several panel handlers stop reporting success for what they did not do.
Core changes:
- Version 8.0.0 (core/version.php, core/helpers.php, core/system.php, public/setup.php, public/update.php, admin/modules/fields.php, admin/modules/groups.php, admin/modules/ratings.php, tools/node-profile.php, .gitignore, README.md, CONTRIBUTING.md, SECURITY.md, UPGRADING.md, docs/.md, admin/lang/.php):
- SL_VERSION is 8.0.0; the marks fields, points, ratings and modules of config/update.php are 8.0.0, written by setup.php and update.php and read by the core behind every gate of extra fields, points and ratings
- The texts of the product, the update page and the NOMARK warnings name 8.0; docs/VERSIONS.md records the move
- SECURITY.md supports 8.0.x alone
- Admin menu queues and Node counts (core/system.php, core/classes/node/query.php, core/classes/node/ext/support.php, modules/node/admin/index.php):
- NodeQuery::getNodeCountList() counts the selection per type in one UNION ALL statement
- The category pre-read loads the categories of every selected type not yet known in one statement
- NodeSupport::getNodeSupportCount() answers the total of the queue without a page; the bell and the pager use it
- getAdminQueues() counts the waiting materials of all non-support types at once; getSessionCounts() is memoised
- The admin dock keeps the two last admin logins in the session instead of reading the login log every page
- Panel lamp and dial (core/admin.php, core/helpers.php, admin/modules/comments.php, admin/modules/modules.php, modules/node/admin/index.php, public/templates/admin/assets/js/admin-ui.js, public/templates/admin/fragments/*.html):
- The status lamp of a canon list is a mark, its switch is an item of the dial of the row; getTplAdminList() appends the stat action of the row to its dial
- "lamp act" turns the mark, its words and the title of the dial item at once
- One running figure and one light round a frame (public/plugins/system/slaed.js, public/templates/admin/assets/css/base.css, public/templates/admin/assets/css/theme.css, public/templates/lite/assets/css/base.css, public/templates/lite/assets/css/theme.css, tools/ui-contract.php):
- setFigureRun(), getFigureText(), getFigureParts() and getFigureValue() of slaed.js run a figure to its goal for as long as --sl-figure-dur of the theme, swollen and green, ending on the server text; voting uses them
- The aurora: a turning cone cut to the frame of every framed block, drawn by the --sl-aurora-* tokens only under the hand; one glow share of its tone for bars, rings, the lamp and traces
- The panel drops its entry animations (home tiles, ground parts, charts, rows of a list) and the four-dot loader; the six --sl-drift-* names and --sl-d-order leave the contract, the class figure enters it
- Presentation (modules/presentation/index.php, modules/presentation/lang/.php, public/plugins/presentation/presentation.js, public/templates/lite/assets/css/presentation.css, public/templates/lite/partials/presentation-.html, public/templates/lite/fragments/presentation-ring.html):
- The request strip prints the figures of this request through getLoadMark(), which getTimedHtml() fills from the final snapshot, so the page agrees with the foot
- The cockpit moves as the panel: the scan, the aurora, arcs filling from zero once on screen, the lamp halo
- Figures count up by setFigureRun(); texts corrected in six locales
- Head and assets (core/system.php, public/templates/*/fragments/head-link.html):
- getIconFont() finds the woff2 of the theme icon stylesheet; setHead() preloads it at the same address
- Handlers that refused nothing (admin/index.php, admin/modules/database.php, admin/modules/privat.php, admin/modules/monitor.php, modules/master/admin/index.php, modules/sitemap/admin/index.php, modules/voting/admin/index.php, modules/search/admin/index.php):
- A module whose tables are not installed shows _DB_NOTABLES instead of running its admin
- Database truncate and drop check the table and report an error when the statement fails; an empty dump warns
- Master share reports an error for a release that does not exist; an empty XSL save is an error, not a success
- Voting lists every stop message; clearing the search log asks for confirmation; addAdminAccount() reads getVar()
- Private messages show their state as an icon with the state in the details
- ALTCHA 3.5.0 (public/plugins/altcha/, core/classes/captcha.php, lang/.php):
- The vendor build and the same-origin worker updated; the captcha texts shortened in six locales
- Help, tests and baselines (admin/info//ru.md, modules//admin/info/ru.md, tests/Support/.php, tests/Unit/.php, tools/ui-audit-baseline.json, tools/ui-contrast.json, public/robots.txt):
- The help pages describe the lamp, the dial and the new refusals
- Tests follow the 8.0.0 marks, the lamp in the dial and the new Node counts
- The UI audit and contrast baselines are recaptured; robots.txt names the sitemap
Benefits:
- One version number for code, data marks and texts
- The admin menu reads all waiting queues in a fixed number of statements
- One motion vocabulary for figures and frames across the panel and the site
Technical notes:
- The data marks are 8.0.0: a site of the development tree needs its config/update.php marks at 8.0.0
- Theme API: --sl-drift-* (panel) and --sl-d-order removed, decision of 2026-11-04 recorded in tools/ui-contract.php
- No schema change