fix(gamification): kill-switch не доходил до учебников (нет ls.css)
Учебники (frontend/textbooks/*.html, 112 шт.) грузят api.js, но НЕ ls.css. api.js ставил
класс .no-gamification на <html>, но сами правила kill-switch (`[data-gamified]`, попап XP)
живут в ls.css → до учебников не доходили, и встроенная XP-механика (бейдж/карточка XP,
ачивки, level-up попап #ach-popup) продолжала отображаться при выключенной геймификации.
Фикс — централизованно в _applyFeatureCss: при gamification=false дублируем правила
`.no-gamification [data-gamified],#ach-popup{display:none}` в инъектируемый <style>, поэтому
kill-switch работает на ЛЮБОЙ странице с api.js, без ls.css. Плюс на страницах без сайдбара
(учебники/embed) теперь авторитетно дёргаем loadFeatures() (только для залогиненных,
in-memory-дедуп) — кэш фич там не обновлялся. Админ по-прежнему видит всё (admin-override).
Verified vm-смоук на реальном api.js 7/7 (student+off → правило инъектится; student+on → нет;
admin → ничего).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -903,7 +903,14 @@ function _applyFeatureCss(feats) {
|
|||||||
JSON.parse(localStorage.getItem('ls_examhide') || '[]')
|
JSON.parse(localStorage.getItem('ls_examhide') || '[]')
|
||||||
.forEach(h => sels.push(`[href="${h}"]`));
|
.forEach(h => sels.push(`[href="${h}"]`));
|
||||||
} catch { /* пусто */ }
|
} catch { /* пусто */ }
|
||||||
const css = sels.length ? sels.join(',') + '{display:none !important}' : '';
|
let css = sels.length ? sels.join(',') + '{display:none !important}' : '';
|
||||||
|
// Геймификация: дублируем kill-switch в инъекцию — для страниц БЕЗ ls.css.
|
||||||
|
// Учебники (frontend/textbooks/*.html) грузят api.js, но НЕ ls.css, поэтому правила
|
||||||
|
// .no-gamification из ls.css туда не доходят, и встроенная XP-механика (data-gamified,
|
||||||
|
// #ach-popup) оставалась видимой. Инъекция работает на любой странице с api.js.
|
||||||
|
if (feats && feats.gamification === false) {
|
||||||
|
css += '.no-gamification [data-gamified],.no-gamification #ach-popup{display:none!important}';
|
||||||
|
}
|
||||||
let el = document.getElementById('ls-feat-hide');
|
let el = document.getElementById('ls-feat-hide');
|
||||||
if (!el) {
|
if (!el) {
|
||||||
el = document.createElement('style');
|
el = document.createElement('style');
|
||||||
@@ -921,6 +928,14 @@ try {
|
|||||||
_applyFeatureCss(_cachedFeats); // применит и кэш фич, и кэш скрытых exam-prep ссылок
|
_applyFeatureCss(_cachedFeats); // применит и кэш фич, и кэш скрытых exam-prep ссылок
|
||||||
} catch { /* нет кэша / приватный режим — просто ждём async */ }
|
} catch { /* нет кэша / приватный режим — просто ждём async */ }
|
||||||
|
|
||||||
|
/* Авторитетно подтянуть фичи на страницах БЕЗ сайдбара (учебники, embed): там
|
||||||
|
sidebar.js/hideDisabledFeatures не вызывают loadFeatures, и кэш мог устареть.
|
||||||
|
loadFeatures() кэширует in-memory (дубль-вызов = один fetch) и сам зовёт _applyFeatureCss.
|
||||||
|
Только для залогиненных — иначе на /login apiFetch поймает 401 и зациклит редирект. */
|
||||||
|
try {
|
||||||
|
if (isLoggedIn()) { loadFeatures().catch(() => {}); }
|
||||||
|
} catch { /* defensive */ }
|
||||||
|
|
||||||
/* Прячет группы сайдбара (.sb-group), у которых не осталось ни одного видимого пункта,
|
/* Прячет группы сайдбара (.sb-group), у которых не осталось ни одного видимого пункта,
|
||||||
чтобы не висел пустой заголовок-аккордеон (напр. «Практика и игры», когда все
|
чтобы не висел пустой заголовок-аккордеон (напр. «Практика и игры», когда все
|
||||||
модули отключены). Зовётся после построения сайдбара и после hideDisabledFeatures. */
|
модули отключены). Зовётся после построения сайдбара и после hideDisabledFeatures. */
|
||||||
|
|||||||
Reference in New Issue
Block a user