Официальный сайт SLAED CMS
Журнал изменений
Every live poll kept a number of its own in its script, the cabinet capped every list of the site by a page size of the visitor, the favorites lived as a tab of the users, the database screen repaired tables InnoDB no longer breaks, and the tiles, labels and buttons of the panel screens differed from screen to screen. The polls now read one setting, the page size is the module's, the favorites are a section again, and the screens share tiles, lists and capitals.
Core changes:
- Live intervals (core/system.php, core/user.php, core/monitor.php, admin/modules/config.php, config/global.php, public/plugins/system/dock.js, admin-ui.js, admin lang):
- getLiveEvery('site'|'panel'|'note') is the one source of every timed poll, read from the group live of config/global.php and held to its bounds: site 5-300 s (0 stops them), panel 10-300 s, note 30-600 s
- The settings show three fields in place of live_u; a poll reads its interval from the data-*-every of its box, a notice from data-sl-live-note of the root
- The server sample is retaken once an interval of the panel after its probe began
- Page size of a visitor removed (core/system.php, modules/account/index.php, config/users.php, table.sql, table_update6_3.sql, account lang):
- getUserNews() and the setting «Количество публикаций на страницу» leave; a site list takes the number of its module or the general one
- The column storynum of _users is dropped by the step of 6.3 (delcol), the cookie account no longer carries it
- Favorites as a section of the panel (admin/modules/favorites.php, admin/info/favorites, config/modules.php, modules/account/admin, tests):
- name=favorites is the list and the settings again; the tab of the users and its note in UPGRADING.md leave
- Database screen (admin/modules/database.php, admin/info/database, admin lang):
- The service tab checks and optimises the tables and reports the result of each (sound, fixed, broken, freed); the repair of a table leaves, as InnoDB is not broken by a crash
- Statistic, monitor and summaries (admin/modules/statistic.php, admin/modules/monitor.php, core/monitor.php, fragments metric-list and series of both themes, session-stats, admin theme.css, admin-ui.js):
- A tile of figures carries its change against the month before as an icon of its trend; the visitors summary is three tiles of metric-list in both themes
- The list of days is a panel list of one view (is_one_view: no switch of density); today names itself in place of its weekday
- A browser is counted by its family; the archive of days joins the versions it kept
- A tile of the panel no longer leans to the hand, only its glare follows it
- Update and configuration screens (admin/modules/update.php, admin/modules/config.php, admin/info, docs/UPDATE.md):
- The buttons read «Искать обновления», «Пробная установка», «Сверить файлы»; the main one stands last on the right
- The cache button of the settings stands in their action row and posts a form of its own; the version row leaves
- Labels and site parts (admin/lang, lang, modules lang, blocks/voting.php, lite templates, core/system.php):
- A label, a status and a value start with a capital in all six locales
- The poll of a block takes the dial of the block into its own; the tools of a block stand in its head
- An SVG logo gives the share image of the theme (images/share.png) to the social tags
- Tests and tools (tests/Support, tests/Unit, tools/label-audit, tools/rehearse.php, tools/upload-route-check.php, tools/ui-audit-baseline.json, tools/ui-contrast.json):
- The probes follow the favorites address, the browser family and the capitals
- ui-contrast.json is the walk of the present tree
Benefits:
- One setting tunes every live poll of the site and the panel
- The panel screens read as one product
Technical notes:
- Breaking: the column _users.storynum is dropped; the cookie account changes its layout, so a signed-in visitor signs in again once
- The address of the favorites is admin.php?name=favorites again
- Parts of this work in admin/modules/database.php, both theme.css, docs/TEMPLATES.md, public/plugins/system/slaed.js and tools/ui-contract.php landed in the commit before, which took those files whole
- Known red at this commit: PhpFileFormatTest (core/monitor.php:1132, modules/master/admin/index.php:228) and SeriesPartsTest::aTileCarriesItsChangeBesideItsNote
The forum home showed a 16px state glyph beside a 14px category icon, cramped its last column, broke on a phone and put the moderator's boxes inside the column of the last message; the category list of the panel stepped its first level wider than the rest and printed a word for a missing icon; the sitemap and search settings named every module by its English key. The forum now reads as the catalogues of the site and the lists of the panel, and the live dot of lite pulses on the compositor.
Core changes:
- Forum home and list of topics (modules/forum/index.php, lite fragments forum-category-row, forum-category-table, forum-topic-view, forum-moder, forum-list-info, inline-badge, checkbox, fieldset-panel, theme.css, slaed.js):
- A section opens with the tile sl-icat of its category in the tone of its order; the state is a mark on the corner:
the green live dot for new messages, a lock for a closed section, none for a read one; the key under the home is gone
- getForumSectionRow() builds the row once for a root and a nested section
- The link to the last message is sl-forum-jump, so the rules of the list sl-forum-last no longer fade or recolour it
- The last message keeps each line whole from the left; a cell keeps the inset of its column title, a table of sections stands the gap of the blocks above the next heading, the foot row as much above the next block
- Titles stay on one line and end in an ellipsis (sl-cell-ellipsis), the whole text in the tip
- Both tables sort by Tablesort: a title by its name, the counts as numbers, the last message by its time; a sortable count keeps the lane of its mark on the right of its title and of its cells, as the panel does
- A moderator picks in a last column of boxes with the box that checks all in the head; the actions stand under the
foot row on the right as the bulk panel of a panel list: the count of the checked rows (data-sl-check-count), one
select no wider than --sl-drop-width and one button on a pill surface, under the list and under one topic alike
- getForumModerBar() and getForumModerForm(); the fields of the form are unchanged
- the fieldset sl-moder-mass, is_legacy_check and partials/compact-list.html leave
- The buttons of the foot keep to the right with or without a pager
- Under 768px both tables become cards: the tile or the box beside the title, the counts with the names of their columns, the last message on one wrapping line
- Live dot of lite (theme.css):
- The dot of the user block, of the profile and of a new forum section pulses by a ring on transform and opacity under
an opaque dot instead of sl-live-pulse on box-shadow; the translucent live icon keeps box-shadow
- sixteen forum dots: renderer 122 -> 73 %, GPU 96 -> 45 %, style 600 -> 86 ms/s; the edge of the halo differs up to 37 of 255 in the first tenth of the cycle, taken by the owner
- Table heads of lite (theme.css):
- A short line parts two column titles as in the panel, drawn as a box of its own so the title keeps its background
- Panel lists (core/admin.php, admin fragments th, table-cells, popover, admin theme.css, admin/modules/database.php):
- Every level of the category tree steps one --sl-tree-width; the tip opens without a newline in both themes, so no space of the font widens a gap
- The icon column of categories stands before the status, its head an icon (is_head_icon), a missing icon the grey circle of off through stat with is_mark, which leaves out data-sl-lamp
- The number column of categories, blocks and the query log is is_col_id
- Module names and dock (modules/sitemap/admin, modules/search/admin, admin fragments checkbox and dock, lite dock, demo):
- The module and type lists of the sitemap and search settings name a module in the language of the panel only
- The turn of the dock shows three dots of the position it turns to, as the pair of the menu position does
- Tools and documents (tools/frame-cost.mjs, tools/ui-contract.php, docs/TEMPLATES.md, docs/PERFORMANCE.md):
- The frame rig has the state forum-idle and the parts forum-dot, avatar-dot and profile-dot
- The contract follows the renamed forum selectors
- TEMPLATES.md gains the section Forum List, the icon head and the tree step; PERFORMANCE.md the measurements
Benefits:
- The forum, the catalogues and the panel lists share one tile, one mark, one sort and one foot
- A page of sixteen new sections no longer repaints a shadow every frame
- The forum reads on a phone
Technical notes:
- No schema change; the icons of the categories on the stand were set to Bootstrap Icons names in the database only
- The moderator form posts the same fields: op, cat, id[], tmove, token
Tabs repeated the name of their section in two or three words, service columns stood in a different place in every list and left a cell empty where a row had no value, a special group of a user was invisible in the list, and the support queue filtered by assignment and priority through the query while the other lists of Node filter by type and status. The tabs, the end of a row and the queue now follow one series with the rest of the panel.
Core changes:
- One-word tabs (admin/lang, modules/node lang, admin/modules, modules/*/admin, admin/info and module help):
- A tab names its job in one word, the section already names the subject: «Добавить», «Создать», «Код», «Новые», «Сброс», «Запрос», «Доступ», «OAuth», «Входы», «Локализация», «Замены», «Восстановление», «Модерация», «Отказы», «Оценки», «Система», «Тема», «Шаблоны», «Импорт», «Отправка», «Ресурсы», «Файл», «Ссылки»; the first tab of «RSS-каналы» and «Конструктор сайта» is «Главная»
- No section repeats its tab: the titles «Пределы» and «Импорт» of «Материалы» and «Конфигурации» of «Поиск» are gone
- The help of every touched section names the new tabs
- The end of a row (fragments/table-cells.html, fragments/th.html, every list with a service column):
- Error, status, options close every list in this order; a list without options ends in its status, every column of data stands before them
- A cell of an error or a status is never empty: without a value it draws the grey circle of off with _NO as its tip
- is_head_run (the result of a run of «Планировщик») and is_head_access (the rights of «Администраторы») show their icon in the head; the shield of a super administrator is the accent colour
- A name with a chip (fragments/table-cells.html, fragments/popover.html, admin theme.css, modules/account/admin):
- The cell key chip draws the tip, the name and an accent chip in one line sl-cell-pair; the name keeps its width, the chip ends in its own ellipsis, in the full view and the cards it wraps under the name
- The special group shows at the nick in the list of «Пользователи», and the filter picks the group from a list by grp=<id>
- The «(i)» of a tip stands 4px from its text in a cell, a line with a chip, the cards and beside a label
- Support queue (core/classes/node/ext/support.php, modules/node/admin/index.php, route probe, NodeSupportTest):
- The type and the status of publication stand beside the title as in «Материалы», the state of the request follows; a request out of publication is found again
- Priority and assignment are sorted in their columns, the query no longer reads aid and prio
- «Обновления» and the head of a section (admin/modules/update.php, admin theme.css, slaed.js):
- A failed check says why in a sentence of what happened and what to do; the code shows only for a reason the panel does not know; the note of the settings is one paragraph
- Three choices without a box to type in stand beside the title like two
- A relative date of the panel begins with a capital letter
- Docs and tests (docs/TEMPLATES.md, docs/NODE.md, docs/VERSIONS.md, ConfigFileTest):
- The templates contract, the support API and the changelog describe the series
- ConfigFileTest counts the nine constants of the restore screen, _CONFIG_RECOVER among them
Benefits:
- Every list of the panel reads the same way, the eye finds the status and the options in one place
- Tabs fit their bar without wrapping
Technical notes:
- Breaking: _ADDCATEGORY, _ADDSUBCATEGORY, _ACESS, _ACESSF, _BANNED_USERS, _SEC_PASS, _UPLOADS_SYSTEM, _LAYOUT_FILETAB, _LAYOUT_WHERE, _GEOLOCATION, _NODE_LIMITS and _UPDATE_S_ID, _UPDATE_S_VER, _UPDATE_S_ENV, _UPDATE_S_ERR, _UPDATE_S_HOST, _UPDATE_S_FAIL are gone; _MULTILINGUAL is _LOCALIZATION, _LAYOUT_THEME is _THEME_TAB; _COMMENTS_MOD and _CONFIG_RECOVER are new
- Breaking: NodeSupport::getNodeSupportCount() and getNodeSupportList() drop $aid and $prio and take the status of publication after the state
- The old address search=6&chng=<id> of the user list shows the whole list
The panel always opened its home after a login, so an administrator whose session ran out lost the section. The site returned through the Referer, lost the page after one wrong password and never from the login page itself, and OAuth carried a redirect of its own that no button passed. One field now carries the way back everywhere.
Core changes:
- The way back (core/system.php):
- filterBackUrl() accepts only a path under HOME_PATH: no scheme, no host, no leading "//", no backslash, space or control byte, at most 512 bytes; anything else gives none
- getBackUrl() takes the back a form or a link carries, a refused one included, else the address of the page itself on a plain GET; a POST without the field and an htmx fragment have none
- getLoginUrl() is the login page with that back; it replaces the bare account link of every invitation to log in
- Panel login (admin/index.php, admin/partials/auth-form.html, admin/info/panel/ru.md):
- The login form carries back, kept after a wrong password; checkAdminLogin() redirects to it, else to admin.php
- The end of a session reloads the page it was on, so the administrator lands in the same section; the help says so
- Site login (modules/account/index.php, blocks/login.php, blocks/user_info.php, lite/partials/login-nav.html, public/index.php, core/user.php, core/classes/parser.php):
- The header form, both login blocks and the account page post back instead of refer=1; login() redirects to it, else to the cabinet
- A closed section, a profile for users only, comments closed to guests, [hide] and the header link invite to the login through getLoginUrl(), so the visitor comes back to the page that sent him
- OAuth (core/classes/oauth.php, modules/account/index.php):
- Oauth::getRedirect() leaves for filterBackUrl(); getButtons() passes back to oauth_init, whose row in _oauth_temp keeps it until the callback, and the callback falls back to the home page
- oauthlogin() loses the branch for an empty address that no caller can reach
- Tests and docs (InputFilterTest, contract_probe, OauthTest, ParserFixturesTest, ViewBridgeSmokeTest, route and oauth probes, docs/ARCHITECTURE.md):
- The filter probe asserts the refused addresses and where getBackUrl() takes its value; the OAuth redirect test goes
- The probes store "/" as the way back of a pending OAuth row; the parser fixture stubs getLoginUrl()
- The Security Boundary describes the standard
Benefits:
- One mechanism of return for every login, with no dependence on the Referer or the policy of the server
- No form or link can send the visitor to another host
Technical notes:
- Breaking: Oauth::getRedirect() is gone, Oauth::getButtons() takes no argument, oauth_init reads back instead of redirect, and the template key refer_field of login-nav is back_field
- refer=1 with the Referer stays for the switches that return to the page they were pressed on
The head of a section placed its filter beside the title until it wrapped into a ragged block, a lone action stood as a button beside the title, column titles ran to several words or cut forms, a status was an icon in one list and a word in the next, and a Node type was named as if it were a module of its own. One series now governs the head, the columns and the cells of every list of the site and the panel.
Core changes:
- Section head (partials/module-head.html, admin theme.css, docs/TEMPLATES.md):
- The filter and the settings find are one block after the tabs; one or two fields stand beside the title once the
content column is 960px wide, three or more always in a bar under the tabs
- .sl-admin-content-inner is the container the head measures, so a folded menu counts
- the bar lays its fields in aligned columns of a label and a control, three across, four as two by two, two under 900px of the column and one under 560px; the button closes the first line
- The old flex rules of the subtitle and its narrow-screen overrides leave
- Action tabs (core/helpers.php, modules/forum/admin/index.php, forum lang and help, tests):
- getTplAdminTabs() takes post: a tab named there carries data-sl-post and slaed.js posts its token
- setTplAdminInfoPage() passes it on
- The synchronisation of «Форум» is a tab on all three screens instead of a lone button; _SYNCHINF says so in six languages, the help describes the tab
- The route probe reads the token of the tab, the test is renamed to theForumListReadsAndTheTabRepairs
- Column titles (lang, admin/lang, node, forum and users lang, every list, docs/TEMPLATES.md):
- Every title of a list is one word, the cut forms of cutstr() leave the heads of categories, forum, voting and users
- new one-word constants where the long one still serves a form: _SEC_ROLE, _GEOIP_BASE, _GEOIP_PATH, _MAIL_TRY, _NLRECIP, _SCHEDULER_NEXT, _FIELDS_ON, _ENDS, _VOTING_VOTES, _NODE_LOOK, _FORUM_LAST, _USERS_FROM
- _SWORD, _SEARCHFIELDS, _FIELDS_KEY, _POINTS_LIMIT, _POINTS_PERIOD and _TVIEWS are one word where only a head reads them
- _ADIR, _VIEW and _POINTS_SCOPE leave; the GeoIP path column no longer borrows the image directory constant
- A centred title stands over the middle of its values: equal sides, and in a sortable table a lane for the mark on the right of the title and of every cell; a sortable title keeps 6px from its mark in every state of the sort
- A title too long for its column ends in an ellipsis, slaed.js puts the whole title in its tip on hover
- The column separator of the head reads --sl-text-subtle and shows in the light scheme
- Statuses, errors and options (table-cells.html, th.html, lite table.html and table-row.html, both theme.css, admin-ui.js, every list with a status):
- The cell key stat draws one of four tones: is_on the green check, is_wait the clock, is_fail the red cross, none
the grey dashed circle of off; text is its tip and its screen-reader name, the cell sorts by the tone
- comments, modules, languages, voting, forum, categories, blocks, master, Node, newsletter campaigns and queue, the dead addresses, the journals of actions and logins, the scheduler, ratings, privat, GeoIP, the database optimise and repair, and the logins and materials of the cabinet move onto it
- the lamp of a row turned in place keeps its sort key
- A head with is_head_status or is_head_error shows its icon instead of the word, the options head shows a gear; status and error columns are sortable and as wide as their icon
- The column tokens hold the width of their content: check and actions read the icon ladder, date 128px, id 42px, count 88px; the commit column of the changelog takes the count class
- Honest module name (core/system.php and every list or filter that names the module of a record):
- getModuleTitle() names a Node type as the module and its type («Материалы - Новости») and another module by its name alone, never its key
- comments, categories, search, favorites, voting, ratings, upload rules and the cabinet use it; the profile picker of a new Node type drops the key
- Help and docs (admin/info, modules/*/admin/info, docs/TEMPLATES.md, docs/VERSIONS.md):
- The help of every changed list names its columns and describes the status icons and the honest module name
- TEMPLATES records the head, the action tab, one-word titles, the four tones and the honest module name; VERSIONS states the breaking changes
- Panel spacing (admin theme.css):
- .sl-box drops its bottom margin, the row under a list keeps 8px above and below it, the cockpit 8px below
- Audit baseline (tools/ui-audit-baseline.json, tools/ui-contrast.json):
- The baseline is stored again and the contrast registry was regenerated by the rig after base.css changed
Benefits:
- One look for every head, column and status of the system, readable without hovering and sortable by meaning
- Service columns no wider than their content, filters that never wrap into a ragged block
- No list names a Node type as a module of its own
Technical notes:
- Breaking: module-head.html draws the filter after the tabs, _ADIR, _VIEW and _POINTS_SCOPE are gone, .sl-status-inactive is the grey off circle and the red cross is .sl-status-fail
- The demo pages keep the old head markup by the decision of the owner
The three green dots over a list of the panel came back on every htmx request of the list - a tab, a filter, a page - after the four-dot loader of the live chart had left. The loader goes as a whole: the class, its keyframes, its markup in the list and the file manager, the dots of a site button under its request, and its six tokens in both themes, struck from the frozen API as a recorded exception.
Core changes:
- Lists of the panel (admin-list.html, admin-ui.js, admin theme.css):
- The hidden .sl-list-busy mark leaves the canon list; setListBusy() only writes aria-busy
- A request on its way dims the rows of tbody, as before; the positioning rules of the mark leave
- .sl-table-shell lost the position the mark gave it; no element of the lists moved, measured in the browser
- File manager (file-manager-templates.html and theme.css of admin and lite):
- The fm-busy template is the dimmed cover alone, without the dots
- The cover drops the flex centring it kept for the dots and still fills its tile or row
- Site button (lite theme.css, plugins/system/slaed.js):
- A button whose htmx request is on its way keeps its label and takes no repeat click; the dots and the transparent label leave
- The comment of setPressBurst() says it lifts the button itself for its sparks
- Theme API (base.css of admin and lite, tools/ui-contract.php, tools/ui-audit-baseline.json):
- .sl-loading, the keyframes sl-loading-dots and the tokens --sl-loading-dur, --sl-loading-width, --sl-loading-height, --sl-loading-dot-width, --sl-loading-dot-height and --sl-loading-dot-gap leave both themes
- The contract records the fifth exception of the freeze and drops the components loading and loading-dot, with drift and drift-dot that had no token left since 2026-11-04
- The baseline roster under api loses the six names, and the baseline is stored again
- Demo and docs (public/demo/admin, docs/VERSIONS.md):
- The demo list dims without the mark, Э28 is described as it now works
- The versions log states the breaking change
Benefits:
- No motion on a list that loads in a fraction of a second
- No dead token, class or rule left behind in either theme
Technical notes:
- Breaking: a theme of its own that overrides the six --sl-loading-* tokens or styles .sl-loading is no longer read
- No schema, URL or PHP API change
Follow-up of the fact rows: the value of field-value was a span, so the paragraphs of a text area stood inside an inline element; the campaign list read $afile without declaring it and built its reset and add links from nothing.
Core changes:
- Value row (fragments/field-value.html of admin and lite, docs/TEMPLATES.md):
- The value of .sl-value-row is a div, which may carry the paragraphs of a text area
- The Templates guide names the div value beside the span caption
- Newsletter campaign list (admin/modules/newsletter.php):
- newsletter() declares $afile, read by reset_url and add_url of the list
- Node list (modules/node/index.php):
- The empty state of setNodeList() breaks its long condition over two lines, as the branch under it
Benefits:
- Valid markup for a multi-paragraph value in both themes
- The reset and the add button of the campaign list lead to the panel page again
Technical notes:
- No schema, URL or API change
- Backward compatible: .sl-value-text keeps its class and its rules
The panel and the site told facts in four ways - alerts, sentences glued to a value, heading rows, windows round a single list. A fact is now a row of kv-list (panel) or field-value and the profile cards (site), its state a chip beside the value and the reason of a bad state a warning under the list; a window of a board no longer wraps a list or a page, and a post button carries the weight of its step.
Core changes:
- Facts of a page (kv-list.html, admin/modules/update.php, config.php, blocks.php):
- kv-list takes an optional chip with a tone (success, warn, danger, neutral) after the value
- On a page the list lines up with the rows of the form: two halves, the same padding and solid rule
- Inside a board window it keeps its narrow form: value to the right, dashed rule, small text
- The updater lists its facts with chips: check refused, no unpacker, rollback, self-check of the last run,
staged package, refused archive, integrity; each sentence of a cause is a warning under the list
- getUpdateWarn() escapes the words of the master or the archive once
- The space a test needs is a meter, not an alert
- Optimization lists cache folders by full path without a heading row
- A block form drops the info alert with the absolute path; the block edit page names the block in a row with the chip of its kind
- New and reworded UPDATE* constants in the six admin locales
- Facts on the site (modules/account/index.php, account-profile.html, lite theme.css):
- The extra fields of the public profile are a fifth card among Profile and Personal; a text area stands under the cards as field-value rows in a wide panel, so its paragraphs stay whole
- field-value draws a rule between two rows, a muted caption and a weighed short value; paragraphs of a text area keep the weight of text (both themes, the reason of the layout difference written into tools/ui-contract.php)
- Panel window and button weight (admin-list.html, helpers.php, post-button.html, database, newsletter, search, sitemap, monitor):
- getTplAdminList() drops its pane option: a list draws no window, its tiles stand above the table
- Database, newsletter, search and sitemap show their tiles without a window; sitemap names its address in a row
- Database counts its tables in a tile; _TOTALSPACE and _TOTALFREE give way to _DB_TOTAL and _DBFREE
- getTplPostButton() takes the look main, check or risk, which the updater uses; the setup, the layout field and the icon picker draw their buttons by the same weight
- Monitor tiles and the demo use outline icons; tile icon width of the panel is 32px
- One empty face (empty.html, file-browser-props.html, file-manager.html, privat-view.html, core/admin.php, user.php):
- An empty file manager, empty file properties and the blank private message pane use fragments/empty.html with the new is_pane variant; the file manager reset button carries its icon
- _UPLOADS_EMPTY* and _UPLOADS_FAIL* give way to the shared EDITOR* words
- The pager hides its "Page" caption visually and keeps it for a screen reader
- Documentation and tests (docs/TEMPLATES.md, admin/info, tests):
- docs/TEMPLATES.md: sections Panel Window, Button Weight and Facts Of A Page
- Help of update, config, blocks, database, newsletter, privat, search and sitemap describes the current page
- SeriesPartsTest checks the chip and its escaping; PanelPartsTest checks that a list draws no window
Benefits:
- One way to tell a fact, a state and its cause everywhere
- Fewer alerts: an alert is a message or the permanent note of a page again
- A list or a page reads as one table with its form
Technical notes:
- getTplAdminList() no longer reads 'pane'; getUpdatePack() takes a third argument $look
- The account profile part drops has_field/field and takes field_html
- No schema or URL change
Nothing to show was told four ways: a grey line in the lists of the panel, a blue alert, a yellow warning on the search of the site, and blocks of their own in the files, the mailbox, the profile feed and the favorites. One fragment now draws it in both themes, in three kinds, while an alert is left to messages: saved, refused, failed.
Core changes:
- The fragment (public/templates/*/fragments/empty.html, assets/css/base.css, assets/css/theme.css):
- One identical fragment of both themes: an icon, a title, an optional line and an optional button
- is_found: "Ничего не найдено" with "Сбросить фильтр"; is_calm: "Всё проверено: очередь пуста." in a calm green
- Without either: "Нет информации", with "Добавить" where the caller passes a form of a new entry
- is_small for a block, a column or a tab; act_target swaps a part with htmx instead of a link
- sl-empty replaces sl-fm-empty and sl-profile-empty; the new token --sl-empty-width, the component empty in tools/ui-contract.php, whose two allowlist entries now name the new selectors
- The window of files keeps --sl-fm-empty-width for the line under its title; sl-list-calm is gone
- The lists of the panel (core/helpers.php, partials/admin-list.html and their callers):
- getTplAdminList() draws the fragment from none_text, is_calm, reset_url and add_url
- A caller no longer picks the words: it passes the address of the list without its filter when one is set
- A type or a tab of a status is a place, not a condition: the trash of a Node type is empty, not "nothing found"
- "Добавить" on an empty list of Node (draft and published only), polls, campaigns, groups and categories
- The single alerts of config, groups, logs, master, search and the categories are the fragment
- The file browser of the panel draws its empty catalogue and its failed list with the same face
- The site (modules/node, users, voting, sitemap, forum, search, changelog, account, core/user.php, core/system.php):
- The lists of Node, users, polls, forum topics and the sitemap; the search without a hit offers the search page
- A Node list empty under a letter, "new" or favorites offers the reset, in the archive of events as well; an empty type offers its form of a new entry to whom checkNodeFlow() allows it
- The comments of a material, a poll that is gone from its block, the profile feed: the small kind
- The mailbox, the favorites, "Мои материалы" and the logins of the cabinet: the fragment in place of the list, no longer an info note in the slot of the cabinet
- The changelog says the fragment when no commit came and keeps the alert for an error of loading
- Documents, help and tests (docs/TEMPLATES.md, admin/info, modules/*/admin/info, tests):
- docs/TEMPLATES.md, section Empty State: the keys, the three kinds, where a button stands, what is no empty state
- The help of newsletter, privat, voting, changelog and account names the reset and the add button
- AdminListRowTest holds reset_url on every list under a filter bar and is_calm on the queues; FileManagerCatalogTest and the profile feed of contract_probe.php read the new keys
Benefits:
- One look and one wording for nothing to show, so an empty place no longer reads as a message or a warning
- An empty result always offers the way back; an empty section offers the next step where the reader may take it
- One rule in place of a ternary of texts in thirty callers
Technical notes:
- Removed constants, all six locales: _UPLOADS_NOFIND, _NOMATCHES, _PRNOHIT, _FAVOR_NONE
- The partial keys empty_alert, empty_title, empty_icon, empty_text, none_text (favorites) and is_empty (file list) give way to one array for the fragment
- The value placeholder "Нет информации" in a cell or a card, the live filter of a picker and the narrow panes of the layout screen stay as they were
Every module counted its pages its own way: six sizes of a page (10 to 100) and four windows of numbers (5, 8, 10 or every page), settings with seven names, numbers written into code and two settings nothing read. The standard is now one section of the general config that every list inherits, as "Use Global" of other systems does; a module of the site may keep its own number where its place needs one, the panel has one number for all its lists.
Core changes:
- The general numbers (config/global.php, admin/modules/config.php, core/helpers.php):
- pager: rows 15 and span 8 for the site, arows 50 and aspan 10 for the panel, four fields of the general settings screen
- getPageRows($own, $key) answers the own rows of a module, else the general one, capped by the own number of a visitor from the cabinet (getUserNews(), 3-20)
- getPageSpan($own) answers aspan in the panel, the own span of a module or the general span on the site
- getListLimit(int|Closure $total) takes the general arows; getTplAdminList() takes arows and aspan itself and loses the keys base and maxpg; getTplPager() and getPageNumbers() take the general numbers when none is passed
- The lists of the panel (admin/modules/.php, modules//admin/index.php, core/classes/comment.php, privat.php, mail.php):
- comments, privat, search, voting, users, favorites, changelog, groups, logs, ratings, master, newsletter and the Node lists take the general rows and window; the own numbers 50, 25, 20 and 10 and the windows 8 and 10 leave
- The pager of the language editor shows the general window in place of every page
- The lists of the site (core/user.php, modules/*/index.php, modules/changelog/common.php):
- comments, privat, search, voting, forum and changelog read getPageRows() and getPageSpan() of their section
- The members list, the logins and "My materials" of the cabinet take the general numbers in place of 50 and 20
- The Node list caps the list.limit of its type by the own number of the visitor, which the hint of that setting always promised; the window is the general one in place of 8
- The topics of the forum keep their own listnum (50), the private messages their own span (5)
- The settings of the modules (core/admin.php, the config forms of six modules, config/*.php):
- getTplPagerFields() draws the two fields rows and span, empty for the general number shown as its placeholder; getPagerPost() reads them; both replace the same fields of six forms
- anum, anump, num, nump, snum, snump, pnum and perpage leave the configs and the forms; favorites.num and favorites.nump, read by nothing, leave with them
- Texts, help and documents (admin/lang, modules/account/lang, modules/changelog/admin/lang, admin/info, modules/*/admin/info, docs/):
- _C_33 to _C_36 name the four numbers plainly, _PAGER_OWN says that an empty field takes the general number, _ADM_ROWSDEF and _ADM_ROWSNOTE name the general default, _ACCOUNT_STORYNOTE names every list of the site; _SEARCHNUM and _CHLOG_PER_PAGE leave; six locales
- The help of config, panel, comments, privat, account, changelog, search, forum and voting describes the fields
- docs/TEMPLATES.md (Admin List Contract, Rows per page, Pager), POINTS.md, RATINGS.md, VERSIONS.md
- Tests (tests/Support/*.php, tests/Unit/AdminListRowTest.php, PointOwnersTest.php):
- The probes of rows, comments, privat, search, account and changelog post and read the new keys
- The list canon test defines the texts of the rows chip, which every paged list now draws
Benefits:
- One place decides the density of all lists; a module states only what differs
- The own number of a visitor works on every list of the site, not on the forum alone
- 434 lines leave, 271 come
Technical notes:
- Breaking: the config keys above are removed; a site updated by the merge of config/ gets pager, rows and span and keeps the old keys unread
- config/local.php must be deleted after the files arrive, or the site runs on the cached old keys and the defaults in code
- A Node type keeps list.limit as before; no URL, schema or API contract changes
A pass over the frame cost of /presentation: the half of a tall section below the window no longer runs, the dashes of the block scene no longer raster the whole scene every frame, and the pulse line stops redrawing once it reached its aim. The picture stays within the pixel tolerance of the rig on every touched part.
Core changes:
- The off-screen pause by part (public/plugins/presentation/presentation.js):
- setOffScreen() watches each scene and block (.sl-pres-scene, a child of .sl-pres-body or of the hero) beside the
sections, so data-sl-pres-off marks the part that left the window
- an SVG pauses its SMIL while any part round it is off, under still motion as before
- an arc in a part still off waits for that part and fills from zero when it first comes into view
- The development screen ran the PDO packet of the section above it on left, a refused animation; it now stands
- The block wires on a layer (public/templates/lite/assets/css/presentation.css):
- .sl-pres-blocks-stage > .sl-pres-wires takes will-change: transform: the dashes running by stroke-dashoffset repaint on their own layer instead of the scene under them
- The map keeps its wires in the scene: its core stands on a half pixel and rastered 90 of 255 apart on a layer (owner, 2026-11-07)
- The pulse strip (public/plugins/presentation/presentation.js):
- setPulse() sleeps by a timer until the next step once the largest move of a frame is under 0.005 of the scale, about 0.03 px; at 60 Hz the line never reaches it and draws every frame as before
- The rig and the documents (tools/frame-cost.mjs, docs/PERFORMANCE.md, docs/TEMPLATES.md):
- States for every section of the presentation (pres-workbench, pres-runtime, pres-dev, pres-live, pres-dna, pres-archive, pres-showcase, pres-voices, pres-pulse) and the part blocks for the pixels
- The pair of the pass, the forms measured and not taken, the memory of the new layer and the share of the cockpit lamp in PERFORMANCE.md; the laws of the part pause and of the running dash in TEMPLATES.md
Benefits:
- System screen: GPU 119 -> 61 %, renderer 50 -> 48 % (medians of 5 rounds against HEAD)
- Development screen: renderer 51 -> 35 %, layout 17 -> 11 ms/s
- Guard screen: renderer 82 -> 78 %, style 69 -> 61 ms/s; top: script 13 -> 10 ms/s
Technical notes:
- Pixels within 16 of 255 in both schemes on hero, system, blocks, guard, runtime, development; pipeline differs by 20 on 2 pixels in the light scheme, under its own noise of 27
- The new layer costs 14 layers and about 9 MB of compositor resources; the raster scratch of Skia falls from about 170 to 130 MB; heap, nodes and listeners stand still over a minute
- No markup, URL or template key changed
Three things the Node types still lacked before 8.0: a dated listing with an archive, ads that do not stay forever, and two profiles built on them. The extension event keeps a start, an end and a place per material in a table of its own and orders the list of its type; workflow.lifetime ends an author's publication after a set number of days and the cabinet lets the author renew it.
Core changes:
- The extension event (core/classes/node/ext/event.php, core/classes/node/ext/load.php, core/classes/node/extension.php, core/classes/node/ext/support.php, core/classes/node/ext/sync.php, core/classes/node/query.php):
- NodeEvent stores the start, an optional end and the place of a material in the new table _node_event
- the list of its type shows the upcoming events, the nearest first; an event stays upcoming until its end, or without one until the end of the day it starts
- the argument archive shows the past ones, the newest first, in place of the sort and the direction
- The interface NodeExtension takes ten methods: getNodeScope() receives the list arguments, getNodeOrder() is new
- NodeQuery::setNodeArgs() hands the arguments of the list to the extension of the single selected type; getExtOrder() and the column check RANK keep the order of the extension trusted
- support and sync return no order and keep the order of their type
- The display mode event is in NodeQuery::MODES and belongs to the type of that extension alone (EXTMODES)
- The lifetime of a publication (core/classes/node/service.php, core/classes/node/query.php, config/node.php, modules/node/admin/index.php, modules/node/admin/lang/*.php, modules/node/admin/info/ru.md):
- The key workflow.lifetime, days from 0 to NodeQuery::LIFEMAX (3650), checked with the workflow section; 0 keeps the old behaviour and is the default of config/node.php
- NodeService sets the end of a material one lifetime after its publication when an author who is no moderator
publishes it directly, or when a moderator approves it from «На проверке», each only while no end is set
- a moderator's own material keeps the end the moderator gives
- an edit of a type without scheduling keeps the stored end
- NodeService::updateNodeTerm() renews a published material of the signed-in author from the clock of the database, a repeat sets the same end, never a sum
- The form of a type has the field «Срок показа, дней»; the help describes it
- The cabinet screen «Мои материалы» (modules/account/index.php, modules/account/lang/*.php, core/user.php, core/system.php, core/classes/route.php):
- materials() lists the author's published materials of active types with a lifetime, shown and expired, with their end, through NodeQuery::getNodeTermList()
- renew() is a POST with the token through checkSitePost('account') and calls updateNodeTerm()
- getUserNavItems() adds the item while an active type has a lifetime; getIconName() knows renew and terms; Route::OPS of account carries materials and renew
- The forms, the public module and the lite theme (modules/node/index.php, modules/node/admin/index.php, modules/node/lang/*.php,public/templates/lite/partials/node/head.html, public/templates/lite/partials/node/event/view.html, public/templates/lite/fragments/node/event/card.html, public/templates/lite/assets/css/theme.css):
- The list of an event type reads archive, keeps it in the pager, the canonical address and the sort links, and the header shows the switch «Архив»
- The forms of the panel and the site show the start, the end and the place; a refused form of the panel names a changed event field among the differences
- The mode event draws the start as a calendar leaf on the card and the page
- The profiles (modules/node/profiles/.json, lang/.php, tools/node-profile.php):
- events: the extension event with a cover and a gallery of up to 20 images, categories, comments, favorites, the home page, pinning and moderated submissions
- jobs: salary, city, employment (full-time, part-time, remote), e-mail and address, a cover for the logo and the switches of board
- board and jobs take workflow.lifetime 30; every other profile carries lifetime 0; seven constants in six languages
- The load profile fills _node_event for event types
- The schema (storage/update/sql/table.sql, storage/update/sql/table_update6_3.sql):
- CREATE TABLE _node_event (nid, starts, ends, place) with the key starts, a cascade from _nodes and the check that an end lies after the start; the update creates it and converts its collation
- Tests and documentation (tests/Unit/NodeEventTest.php, tests/Unit/NodeTest.php, tests/Unit/RequestWatchTest.php, tests/Support/_probe.php, docs/NODE.md, docs/VERSIONS.md):
- NodeEventTest checks the extension, the writes and reads through NodeService and NodeQuery, the routes and the statement budget of the list
- NodeServiceTest checks the publication, the approval, the moderator's own material and the renewal; NodeProfileTest and the installation probe check the sixteen profiles through a real installation, an event written through the panel included
- docs/NODE.md describes the extension event, the lifetime, «Author's materials» and the import of an older file
Benefits:
- A calendar of events and classifieds that expire come with the installation, without a module of their own
- The order of a list stays in the query: an extension gives one trusted column, never a sort key of the visitor
Technical notes:
- New table _node_event: a stand that has the code runs its CREATE TABLE from table.sql with its prefix, and rebuilds config/local.php for the new key of config/node.php
- A profile file without workflow.lifetime imports with 0 and stays format version 1
- Breaking: the interface NodeExtension changes getNodeScope() and gains getNodeOrder(); the factory is closed, so only the extensions of the core implement it
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