Ошибка рендеринга шаблонизатора

Обнаружена проблема при обработке шаблона.

Сообщение об ошибке

An exception has been thrown during the rendering of a template ("Call to undefined method PDOException::fetchAll()").
Файл:
/home/emerland/web/emerland.su/public_html/src/component/plugins/sphere_forum/tpl/categories.html
Строка:
987
Тип:
Twig\Error\RuntimeError
Шаблон:
index.html
  1. </ul>
  2. <div class="tab-content">
  3. <div class="tab-pane show active text-muted" id="last-messages" role="tabpanel">
  4. {% for i, lastMessage in getLastMessagesForum() %}
  5. {% set user = getUser(lastMessage.getUserId()) %}
  6. <div class="message-block border-0 bg-transparent mb-2">
  7. <div class="d-flex">
  8. <div class="me-3">
  9. <span class="avatar avatar-md avatar-rounded bg-light text-muted">
  1. {%extends 'struct.html'%}
  2. {%block title%}{{ phrase('personal account') }}{%endblock%}
  3. {%block content%}
  4. <div class="container-fluid">
  5. {%if config().enabled().isEnableEmulation()%}
  6. <div class="alert alert-dark" role="alert">
  7. {{ phrase('func_emulation_server_desc_enable')|raw }}
  8. </div>
  9. {%endif%}
  10. {%if get_session('super-user')%}
  11. <div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12">
  12. <div class="card bg-white border-0">
  13. <div class="alert custom-alert1 alert-secondary">
  14. <button type="button" class="btn-close ms-auto close_download_auth_panel" data-bs-dismiss="alert"
  15. aria-label="Close"><i class="bi bi-x"></i></button>
  16. <div class="text-center px-0 pb-0">
  17. <svg class="custom-alert-icon svg-secondary" xmlns="http://www.w3.org/2000/svg" height="1.5rem"
  18. viewBox="0 0 24 24" width="1.5rem" fill="#000000">
  19. <path d="M0 0h24v24H0z" fill="none" />
  20. <path
  21. d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
  22. </svg>
  23. <h5>Файл для авторизации</h5>
  24. <p class="">Вы успешно всё сделали, теперь можете загрузить файл, сохраните его, и на сайтах движка SphereWeb
  25. можете использовать для быстрой регистрации и авторизации, просто перенесите на странице авторизации данный
  26. файл.</p>
  27. <div class="">
  28. <button class="btn btn-sm btn-success m-0 download_file_auth">Нажмите чтоб загрузить файл</button>
  29. </div>
  30. </div>
  31. </div>
  32. </div>
  33. </div>
  34. <script>
  35. $('.download_file_auth').on('click', function () {
  36. var link = document.createElement('a');
  37. link.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent("{{get_session('super-user')}}");
  38. link.download = '{{getUser().getEmail()}} Auto Login.txt';
  39. document.body.appendChild(link);
  40. link.click();
  41. document.body.removeChild(link);
  42. });
  43. { { delete_session('super-user') } }
  44. </script>
  45. {%endif%}
  46. {# Если нет серверов, то показываем сообщение, что нужно зарегистрировать сервер #}
  47. {%if getUser().isAdmin() and getServerCount() == 0%}
  48. <div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 col-sm-12">
  49. <ul class="list-unstyled mb-0 notification-container">
  50. <li>
  51. <div class="card mb-3">
  52. <div class="d-flex p-2 border-bottom-0">
  53. <div class="d-sm-flex">
  54. <div class="">
  55. <svg class="me-4 bg-danger-transparent alt-notify" xmlns="http://www.w3.org/2000/svg"
  56. viewBox="0 0 24 24">
  57. <path fill="#ff9ea7"
  58. d="M20.057 22H3.943a3.023 3.023 0 0 1-2.618-4.534L9.382 3.511a3.023 3.023 0 0 1 5.236 0l8.057 13.955A3.023 3.023 0 0 1 20.057 22Z">
  59. </path>
  60. <circle cx="12" cy="17" r="1" fill="#dc3545"></circle>
  61. <path fill="#dc3545" d="M12 14a1 1 0 0 1-1-1V9a1 1 0 0 1 2 0v4a1 1 0 0 1-1 1Z"></path>
  62. </svg>
  63. </div>
  64. <div class="mt-0 text-start">
  65. <p class="fs-14 text-muted mb-0">{{phrase('no_registration_servers')}}<br>
  66. <a href="/admin/server/add/new" class=" text-primary d-inline-flex">{{phrase('register_server')}}</a>
  67. </p>
  68. </div>
  69. </div>
  70. </div>
  71. </div>
  72. </li>
  73. </ul>
  74. </div>
  75. {%endif%}
  76. {# Панель с предложением для неавторизованных пользователей #}
  77. {%if getUser().isAuth() == false%}
  78. <div class="row">
  79. <div class="col-xl-12">
  80. <div class="row">
  81. <div class="col-xl-4">
  82. <div class="card custom-card">
  83. <div class="card-body">
  84. <p class="card-text">{{phrase('log_in_crt_gm_acc')}}</p>
  85. <a href="/login" class="btn btn-success">{{phrase('authorization')}}</a>
  86. </div>
  87. </div>
  88. </div>
  89. <div class="col-xl-4">
  90. <div class="card custom-card">
  91. <div class="card-body">
  92. <p class="card-text">{{phrase('reg_crt_gm_accs')}}</p>
  93. <a href="/signup" class="btn btn-dark">{{phrase('registration')}}</a>
  94. </div>
  95. </div>
  96. </div>
  97. <div class="col-xl-4">
  98. <div class="card custom-card">
  99. <div class="card-body">
  100. <p class="card-text">{{phrase('forgot_pwd_recover_email')}}</p>
  101. <a href="/forget" class="btn btn-info">{{phrase(67)}}</a>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. {%endif%}
  109. {%if getUser().isAuth() and getServerCount() > 0%}
  110. <div class="row">
  111. <div class="col-xl-12">
  112. <div class="card custom-card">
  113. <div class="card-header d-flex justify-content-between align-items-center">
  114. <h5 class="card-title mb-0">{{phrase(43)}}</h5>
  115. </div>
  116. <div class="card-body">
  117. <div class="row mb-4">
  118. <div class="col-12">
  119. <form action="/registration/account" method="POST">
  120. <div class="row mb-3">
  121. <div class="col-12">
  122. <div
  123. class="alert alert-primary alert-dismissible fade show custom-alert-icon shadow-sm d-flex justify-content-between">
  124. {{ phrase(40) }} - {{ getServer().getName() }} x{{ getServer().getRateExp() }} ({{
  125. getServer().getChronicle() }})
  126. <span data-bs-toggle="modal" data-bs-target="#syncAccount">
  127. <label role="button" data-bs-toggle="tooltip" data-bs-placement="top"
  128. data-bs-original-title="{{phrase('sync_accounts_question_missing_account')}}">
  129. {{ phrase('Do you already have an account?') }}
  130. </label>
  131. </span>
  132. </div>
  133. </div>
  134. </div>
  135. <!-- Поля ввода в ряд -->
  136. <div class="row align-items-end mb-3">
  137. <!-- Поле логина -->
  138. <div class="col-md-4">
  139. <label for="accountRegistration" class="form-label">{{phrase(480)}}</label>
  140. <div class="input-group">
  141. {%set maxChars = config().registration().getMaximumNumberOfCharactersRegistrationAccount()%}
  142. {%set prefixEnabled = config().registration().getEnablePrefix()%}
  143. {%set prefixType = config().registration().getPrefixType()%}
  144. {%if prefixEnabled and prefixType == 'prefix'%}
  145. <button class="btn btn-light account_prefix" type="button">
  146. <span class="prefix-text">{{ prefix }}</span>
  147. </button>
  148. {%endif%}
  149. <input type="text" class="form-control" name="login" id="accountRegistration"
  150. minlength="{{ config().registration().getMinimumNumberOfCharactersRegistrationAccount() }}"
  151. maxlength="{{ maxChars }}" placeholder="{{ phrase(480) }}" aria-label="Login input"
  152. aria-describedby="accountCharCounter" autocomplete="off">
  153. {%if prefixEnabled and prefixType == 'suffix'%}
  154. <button class="btn btn-light account_prefix" type="button">
  155. <span class="prefix-text">{{ prefix }}</span>
  156. </button>
  157. {%endif%}
  158. </div>
  159. <div class="d-flex justify-content-between mt-1">
  160. <small class="form-text text-muted">
  161. {{ phrase('minMaxCharacters',
  162. config().registration().getMinimumNumberOfCharactersRegistrationAccount(),
  163. config().registration().getMaximumNumberOfCharactersRegistrationAccount()
  164. )}}
  165. </small>
  166. <small id="accountCharCounter" class="form-text text-muted">
  167. {{ phrase(312) }}: {{ maxChars }}
  168. </small>
  169. </div>
  170. </div>
  171. <!-- Поле пароля -->
  172. <div class="col-md-4">
  173. <label for="passwordRegistration" class="form-label">{{phrase('password')}}</label>
  174. <div class="input-group">
  175. <input type="password" minlength="4" maxlength="32" class="form-control" name="password"
  176. id="passwordRegistration" autocomplete="new-password" placeholder="{{phrase('password')}}">
  177. <button class="btn btn-link btn-sm toggle-password" type="button" id="togglePassword">
  178. <i class="bi bi-eye-fill"></i>
  179. </button>
  180. </div>
  181. <div class="form-check mt-1">
  182. <input checked class="form-check-input" type="checkbox" value="" name="password_hide"
  183. id="password_hide">
  184. <label class="form-check-label" for="password_hide" data-bs-toggle="tooltip"
  185. data-bs-placement="top" data-bs-original-title="{{phrase(483)}}">
  186. {{phrase(482)}}
  187. </label>
  188. </div>
  189. </div>
  190. <!-- Кнопки действий -->
  191. <div class="col-md-4">
  192. <div class="d-flex flex-column gap-2">
  193. <button type="submit" data-func="messageRegistrationAccount"
  194. class="btn btn-success shadow-success btn-wave waves-effect waves-light">
  195. {{phrase('reg_new_acc')}}
  196. </button>
  197. <div data-bs-toggle="tooltip" data-bs-placement="top"
  198. data-bs-original-title="{{phrase('sync_accounts_question_missing_account')}}">
  199. <span data-bs-toggle="modal" data-bs-target="#syncAccount"
  200. class="btn btn-info shadow-info btn-wave waves-effect waves-light w-100">
  201. {{phrase('bind_game_account')}}
  202. </span>
  203. </div>
  204. </div>
  205. </div>
  206. </div>
  207. <!-- Сообщение об ошибке -->
  208. <div class="row">
  209. <div class="col-12">
  210. <div id="registrationDataMessage" class="d-none">
  211. <span id="registrationMessage" class="badge border bg-danger-transparent rounded-1">
  212. {{ phrase(214) }}
  213. </span>
  214. </div>
  215. </div>
  216. </div>
  217. </form>
  218. </div>
  219. </div>
  220. <!-- Список аккаунтов -->
  221. <div class="row">
  222. <div class="col-12">
  223. <div
  224. class="alert alert-primary alert-dismissible fade show custom-alert-icon shadow-sm d-flex justify-content-between align-items-center mb-3">
  225. <div>{{ phrase(43) }}</div>
  226. <span>{{ getUser().getAccounts()|length }} / {{ config().other().getMaxAccount() }}</span>
  227. </div>
  228. {%if statusSphereServer() is same as(false)%}
  229. <div class="alert alert-danger alert-dismissible fade show" role="alert">
  230. <strong>{{phrase('fail_conn_sphereapi_srv')}}</strong>
  231. <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
  232. </div>
  233. {%else%}
  234. <div class="table-responsive">
  235. <table class="table text-nowrap table-bordered table-sm" style="table-layout: fixed;">
  236. <thead>
  237. <tr>
  238. <th>{{phrase('account')}}</th>
  239. <th>{{phrase('password')}}</th>
  240. <th>{{phrase(203)}}</th>
  241. </tr>
  242. </thead>
  243. <tbody id="player_account_list">
  244. {%for account in getUser().getAccounts()%}
  245. <tr class="account-row">
  246. <td>{{ account.getAccount()|raw }}
  247. {%if config().other().getIsAllowDeleteAccount()%}
  248. <i data-account="{{account.getAccount()|raw}}" role="button"
  249. class="bi bi-person-dash deleteAccount" data-bs-toggle="tooltip" data-bs-placement="top"
  250. data-bs-title="{{phrase('account_deletion')}}"></i>
  251. {%endif%}
  252. </td>
  253. <td>
  254. <i role="button" class="fe fe-settings btn-change-password"
  255. data-account="{{account.getAccount()|raw}}" data-bs-toggle="modal"
  256. data-bs-effect="effect-slide-in-right" data-bs-target="#changepassword">
  257. {%if account.isPasswordHide()%}
  258. * * * * * *
  259. {%else%}
  260. {{ account.getPassword() }}
  261. {%endif%}
  262. </i>
  263. </td>
  264. <td class="text-nowrap" role="button">
  265. {%if account.getCharactersCount() > 0%}
  266. <div class="toggle-characters" data-account="{{account.getAccount()|raw}}">
  267. <div class="avatar-list-stacked">
  268. {%for i, character in account.getCharacters()%}
  269. <span class="avatar avatar-sm me-2">
  270. <img
  271. src="{{tempate}}/uploads/images/race/{{ sex(character.getSex()) }}/{{ get_class_race(character.getClassId()) }}.jpg"
  272. alt="img">
  273. </span>
  274. </a>
  275. {%endfor%}
  276. </div>
  277. </div>
  278. {%else%}
  279. <i class="bi bi-people ms-2 text-muted" data-bs-toggle="tooltip" data-bs-placement="top"
  280. data-bs-title="{{phrase('no_chars_acc')}}"></i>
  281. {%endif%}
  282. </td>
  283. </tr>
  284. {%if account.getCharactersCount() > 0%}
  285. <tr class="character-container character-row-{{account.getAccount()|raw}}" style="display: none;">
  286. <td colspan="3" class="p-0">
  287. <div class="p-2 bg-light">
  288. <div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-2">
  289. {%for i, character in account.getCharacters()%}
  290. <div class="col">
  291. <div class="card border h-100 overflow-hidden">
  292. <div class="card-body p-1 border-top-card border-top-danger rounded-0">
  293. <div class="d-flex align-items-start">
  294. <!-- Аватар персонажа -->
  295. <div class="flex-shrink-0 me-2">
  296. <img
  297. src="{{tempate}}/uploads/images/race/{{ sex(character.getSex()) }}/{{ get_class_race(character.getClassId()) }}.jpg"
  298. alt=""
  299. class="avatar avatar-xl img-thumbnail {%if character.getOnline()%}online{%else%}offline{%endif%}">
  300. </div>
  301. <!-- Информация о персонаже -->
  302. <div class="flex-grow-1 min-w-0">
  303. <h6 class="card-title mb-1 text-truncate">
  304. <span class="badge bg-dark text-white">{{character.getPlayerName()}}</span>
  305. </h6>
  306. <div class="d-flex flex-column" style="line-height: 1.1;">
  307. <small class="text-muted text-truncate mb-0">
  308. <i class="ri-building-line me-1"></i>Lv: {{character.getLevel()}}
  309. </small>
  310. <small class="text-muted text-truncate mb-0">
  311. <i class="ri-building-line me-1"></i>Class:
  312. {{get_class(character.getClassId())}}
  313. </small>
  314. <small class="text-muted text-truncate mb-0">
  315. <i class="ri-building-line me-1"></i>PvP / PK: {{character.getPvp()}} /
  316. {{character.getPk()}}
  317. </small>
  318. <small class="text-muted text-truncate mb-0">
  319. <i class="ri-building-line me-1"></i>Online Time:
  320. {{timeHasPassed(character.getTimeInGame(),true)}}
  321. </small>
  322. {%if character.getClanName()%}
  323. <small class="text-muted">
  324. <i class="ri-map-pin-line me-1"></i>Clan:
  325. <span class="d-inline-flex align-items-center">
  326. {{clan_icon(character.getClanCrest())|raw}}
  327. <span class="text-truncate d-inline-block"
  328. style="max-width: 120px; vertical-align: middle;">{{character.getClanName()}}</span>
  329. </span>
  330. </small>
  331. {%endif%}
  332. </div>
  333. </div>
  334. </div>
  335. <!-- Аккордеон с функциями -->
  336. <div class="accordion accordion-customicon1 accordions-items-seperate mt-2"
  337. id="accordion_open_list_{{character.getPlayerId()}}">
  338. <div class="accordion-item">
  339. <h2 class="accordion-header" id="open_list_{{character.getPlayerId()}}">
  340. <button class="accordion-button collapsed py-2 text-wrap" type="button"
  341. data-bs-toggle="collapse"
  342. data-bs-target="#collapse_open_list_{{character.getPlayerId()}}"
  343. aria-expanded="false"
  344. aria-controls="collapse_open_list_{{character.getPlayerId()}}">
  345. <span class="text-truncate">{{phrase('stuck_crit_err')}}</span>
  346. </button>
  347. </h2>
  348. <div id="collapse_open_list_{{character.getPlayerId()}}"
  349. class="accordion-collapse collapse"
  350. aria-labelledby="open_list_{{character.getPlayerId()}}"
  351. data-bs-parent="#accordion_open_list_{{character.getPlayerId()}}" style="">
  352. <div class="accordion-body py-2 text-wrap">
  353. <p class="small mb-2 text-break">{{phrase('emerg_send_char_town')}}</p>
  354. <hr class="my-2">
  355. <form method="post" action="/player/relocation">
  356. <div class="mb-2 form-check">
  357. <input name="account" type="hidden" value="{{account.getAccount()|raw}}">
  358. <input name="player" type="hidden" value="{{character.getPlayerName()}}">
  359. {%if getServer().isResetItemsToWarehouse() == true%}
  360. <input checked name="itemsToWarehouse" type="checkbox"
  361. class="form-check-input" id="check_{{character.getPlayerId()}}">
  362. <label class="form-check-label small text-wrap"
  363. for="check_{{character.getPlayerId()}}">{{phrase('send_items_wh')}}</label>
  364. {%endif%}
  365. </div>
  366. <button type="submit" class="btn btn-success btn-sm w-100 text-nowrap">
  367. <span class="d-inline-block text-truncate"
  368. style="max-width: 85%;">{{phrase(364)}}</span>
  369. <i class="ri-send-plane-fill ms-1"></i>
  370. </button>
  371. </form>
  372. </div>
  373. </div>
  374. </div>
  375. {%if getServer().isResetHWID() == true%}
  376. <div class="accordion-item">
  377. <h2 class="accordion-header" id="hwid_remove_{{character.getPlayerId()}}">
  378. <button class="accordion-button collapsed py-2 text-wrap" type="button"
  379. data-bs-toggle="collapse"
  380. data-bs-target="#collapse_hwid_remove_{{character.getPlayerId()}}"
  381. aria-expanded="false"
  382. aria-controls="collapse_hwid_remove_{{character.getPlayerId()}}">
  383. <span class="text-truncate">{{phrase('reset_hwid')}}</span>
  384. </button>
  385. </h2>
  386. <div id="collapse_hwid_remove_{{character.getPlayerId()}}"
  387. class="accordion-collapse collapse"
  388. aria-labelledby="open_list_{{character.getPlayerId()}}"
  389. data-bs-parent="#accordion_open_list_{{character.getPlayerId()}}" style="">
  390. <div class="accordion-body py-2 text-wrap">
  391. <p class="small mb-2 text-break">{{phrase('reset_hwid_emerg_fn')}}.</p>
  392. <button type="submit"
  393. class="btn btn-success btn-sm w-100 removeHWID text-nowrap"
  394. data-obj="{{character.getPlayerId()}}"
  395. data-account="{{account.getAccount()}}">
  396. <span class="d-inline-block text-truncate"
  397. style="max-width: 85%;">{{phrase('reset_hwid')}}</span>
  398. <i class="ri-lock-unlock-line ms-1"></i>
  399. </button>
  400. </div>
  401. </div>
  402. </div>
  403. {%endif%}
  404. </div>
  405. </div>
  406. </div>
  407. </div>
  408. {%endfor%}
  409. </div>
  410. </div>
  411. </td>
  412. </tr>
  413. {%endif%}
  414. {%endfor%}
  415. </tbody>
  416. </table>
  417. </div>
  418. {%endif%}
  419. </div>
  420. </div>
  421. </div>
  422. </div>
  423. </div>
  424. </div>
  425. {%if config().other().getIsAllowDeleteAccount()%}
  426. <div class="modal fade" id="deleteAccountModal" tabindex="-1" aria-labelledby="deleteAccountModalLabel"
  427. aria-hidden="true">
  428. <div class="modal-dialog modal-dialog-centered">
  429. <div class="modal-content">
  430. <div class="modal-header">
  431. <h5 class="modal-title" id="deleteAccountModalLabel">{{phrase('confirm_delete')}}</h5>
  432. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
  433. </div>
  434. <div class="modal-body">
  435. {{phrase('delete_account_confirm')}} <span class="fw-bold" id="accountToDelete"></span>?
  436. <p class="font-13 text-muted">{{phrase('delete_account_desc')}}</p>
  437. </div>
  438. <div class="modal-footer">
  439. <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{phrase('no')}}</button>
  440. <button type="button" class="btn btn-danger" id="confirmDeleteAccount">{{phrase('yes')}}</button>
  441. </div>
  442. </div>
  443. </div>
  444. </div>
  445. <script>
  446. $(document).ready(function () {
  447. // Обработчик клика по иконке удаления аккаунта
  448. $(document).on('click', '.deleteAccount', function () {
  449. var accountName = $(this).data('account');
  450. $('#accountToDelete').text(accountName);
  451. $('#confirmDeleteAccount').data('account', accountName);
  452. $('#deleteAccountModal').modal('show');
  453. });
  454. // Обработчик подтверждения удаления
  455. $(document).on('click', '#confirmDeleteAccount', function () {
  456. var accountName = $(this).data('account');
  457. // Отправка AJAX запроса на удаление аккаунта
  458. AjaxSend('/player/account/delete', 'POST', {
  459. account: accountName
  460. }, true).then(function (response) {
  461. $('#deleteAccountModal').modal('hide');
  462. responseAnalysis(response);
  463. if (response.ok) {
  464. $('tr.account-row').has('i[data-account="' + accountName + '"]').remove();
  465. $('tr.character-row-' + accountName).remove();
  466. }
  467. }).catch(function (error) {
  468. $('#deleteAccountModal').modal('hide');
  469. });
  470. });
  471. });
  472. </script>
  473. {%endif%}
  474. <form action="/player/account/change/password" method="POST">
  475. <div class="modal fade" id="changepassword">
  476. <div class="modal-dialog modal-dialog-centered text-center" role="document">
  477. <div class="modal-content modal-content-demo">
  478. <div class="modal-header">
  479. <h6 class="modal-title">{{phrase(1)}}</h6>
  480. <button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"></button>
  481. </div>
  482. <input name="login" type="hidden" class="account_new_change_password_input" value="">
  483. <div class="modal-body text-start">
  484. <h6 class="text-center">{{phrase('new_password')}} <span
  485. class="text-danger account_new_change_password">{{getUser().getName()}}</span></h6>
  486. <div class="form-floating">
  487. <input name="password" type="password" class="form-control" id="floatingPassword" placeholder="Password">
  488. <label for="floatingPassword">{{phrase('password')}}</label>
  489. </div>
  490. <div class="col-sm-10">
  491. <div class="form-check">
  492. <input name="password_hide" class="form-check-input" type="checkbox" id="hidePassword">
  493. <label class="form-check-label" for="hidePassword">
  494. {{phrase('lv_pwd_vis')}}
  495. </label>
  496. </div>
  497. </div>
  498. </div>
  499. <div class="modal-footer">
  500. <button type="button" class="btn btn-light" data-bs-dismiss="modal">{{phrase(80)}}</button>
  501. <button type="submit" class="btn btn-primary">{{phrase(89)}}</button>
  502. </div>
  503. </div>
  504. </div>
  505. </div>
  506. </form>
  507. {%endif%}
  508. {%for include_file in get_plugins_include("PLACE_IN_SPACE_MAIN_1")%}
  509. {%include include_file%}
  510. {%endfor%}
  511. {%if forum().isEnabled() and forum().showForumSphereMainPage()%}
  512. <div class="row">
  513. <div class="col-xxl-12 col-md-12">
  514. <div class="card">
  515. <div class="card-header">
  516. <h4 class="card-title fw-semibold">{{phrase('last_act_forum')}}</h4>
  517. </div>
  518. <div class="card-body pb-0">
  519. {%if forum().isNotError()%}
  520. <div class="list-group">
  521. {%if forum().getSort() == "threads"%}
  522. {%for forum in forum().lastThreads()%}
  523. <a href="{{ forum.thread_url }}" class="list-group-item list-group-item-action">
  524. <div class="d-flex align-items-center">
  525. <div>
  526. <span class="avatar cover-image avatar-sm bg-white text-default avatar-rounded me-2">
  527. <img src="{{ forum.avatar }}" alt="img" class="avatar-img">
  528. </span>
  529. </div>
  530. <div class="ms-2 w-100 d-flex justify-content-between align-items-center">
  531. <div>
  532. <span class="fw-semibold me-1">{{ forum.username }}</span>
  533. <span class="text-muted fs-12">:</span>
  534. <span class="text-truncate" >{{ forum.title }}</span>
  535. </div>
  536. <div class="text-muted fs-11 ms-3">{{ forum.last_post_date|date('h:m:s d.m.Y') }}</div>
  537. </div>
  538. </div>
  539. </a>
  540. {%endfor%}
  541. {%else%}
  542. {%for forum in forum().lastMessage()%}
  543. <a href="{{ forum.thread_url|default('javascript:void(0)') }}" class="list-group-item list-group-item-action">
  544. <div class="d-flex align-items-center">
  545. <div>
  546. <span class="avatar cover-image avatar-sm bg-white text-default avatar-rounded me-2">
  547. <img src="{{ forum.avatar }}" alt="img" class="avatar-img">
  548. </span>
  549. </div>
  550. <div class="ms-2 w-100">
  551. <div class="d-flex justify-content-between align-items-center">
  552. <div>
  553. <span class="fw-semibold me-1">{{ forum.username }}</span>
  554. <span class="text-muted fs-12">:</span>
  555. <span class="text-truncate" >{{ forum.title }}</span>
  556. </div>
  557. <div class="text-muted fs-11 ms-3">{{ forum.last_post_date|date('h:m:s d.m.Y') }}</div>
  558. </div>
  559. <div class="text-muted fs-12 mt-1">{{ truncateWord(forum.message, 220) }}</div>
  560. </div>
  561. </div>
  562. </a>
  563. {%endfor%}
  564. {%endif%}
  565. </div>
  566. {%else%}
  567. {{ forum().getMessageError() }}
  568. {%endif%}
  569. </div>
  570. </div>
  571. </div>
  572. </div>
  573. {%endif%}
  574. {{ include('other/startpack.html') }}
  575. </div>
  576. {%endblock%}
  577. {%block js%}
  578. <script>
  579. $(document).on('click', '.removeHWID', function () {
  580. var obj = $(this).data('obj');
  581. var account = $(this).data('account');
  582. AjaxSend('/player/reset/hwid', 'POST', {
  583. player_id: obj,
  584. account: account
  585. }).then(function (response) {
  586. console.log(response);
  587. });
  588. });
  589. $(document).on('click', '.btn-open-shop', function () {
  590. var startpackId = $(this).data('startpack-id');
  591. var itemList = $('#item_list_startpack_' + startpackId);
  592. var startpackName = itemList.closest('.p-4').find('.startpack_name').text();
  593. var startpackCost = itemList.closest('.p-4').find('.startpack_cost').text();
  594. var itemListHtml = '<h5>' + startpackName + '</h5>';
  595. itemList.find('li').each(function () {
  596. var itemSrc = $(this).data('item-src');
  597. var itemName = $(this).data('item-name');
  598. var itemEnchant = $(this).data('item-enchant');
  599. var itemCount = $(this).data('item-count');
  600. itemListHtml += '<div class="item">';
  601. itemListHtml += '<img src="' + itemSrc + '" alt="" class="avatar avatar-sm ">';
  602. itemListHtml += '<span class="text-muted">';
  603. if (itemEnchant > 0) {
  604. itemListHtml += '<span class="badge bg-danger text-white ms-1">+' + itemEnchant + '</span>';
  605. }
  606. itemListHtml += ' ' + itemName;
  607. itemListHtml += '</span>';
  608. itemListHtml += '</div>';
  609. });
  610. $('.StartPackCostBuy').text(startpackCost);
  611. $('#Startpackpurchase').attr('data-startpack-id', startpackId);
  612. $('#StartpackWarehouse').attr('data-startpack-id', startpackId);
  613. // Вставка списка предметов в модальное окно
  614. $('#itemListSellStartpack').html(itemListHtml);
  615. });
  616. $(document).on('click', '#Startpackpurchase', function () {
  617. const $startpackTab = $('#StartpackSendItemsToPlayer');
  618. const canSendItemsNow = $startpackTab.data('canSend') !== false;
  619. if (!canSendItemsNow) {
  620. const lockMessage = $startpackTab.data('lockMessage') || 'Отправка предметов временно недоступна. Попробуйте позже.';
  621. if (typeof noticeError === 'function') {
  622. noticeError(lockMessage);
  623. } else {
  624. alert(lockMessage);
  625. }
  626. return;
  627. }
  628. var startpackId = $(this).attr('data-startpack-id');
  629. var selectedOption = $('#StartpackPlayer option:selected');
  630. var account = selectedOption.attr('data-account');
  631. var player = selectedOption.val();
  632. AjaxSend('/startpack/purchase', 'POST', {
  633. account: account,
  634. player: player,
  635. startpackId: startpackId,
  636. }).then(function (response) {
  637. $('#openShopStartpack').modal('hide');
  638. $('.StartPackCostBuy').text(response.sphereCoin);
  639. });
  640. });
  641. $(document).on('click', '#StartpackWarehouse', function () {
  642. var startpackId = $(this).attr('data-startpack-id');
  643. var selectedOption = $('#StartpackPlayer option:selected');
  644. var account = selectedOption.attr('data-account');
  645. var player = selectedOption.val();
  646. AjaxSend('/startpack/purchase/warehouse', 'POST', {
  647. account: account,
  648. player: player,
  649. startpackId: startpackId,
  650. }).then(function (response) {
  651. $('#openShopStartpack').modal('hide');
  652. $('.StartPackCostBuy').text(response.sphereCoin);
  653. });
  654. });
  655. </script>
  656. <script>
  657. $(document).on('click', '.btn-change-password', function () {
  658. var account = $(this).data('account');
  659. $('.account_new_change_password').text(account);
  660. $('.account_new_change_password_input').val(account);
  661. });
  662. </script>
  663. <script>
  664. function transliterate(text) {
  665. const layoutMap = {
  666. 'й': 'q', 'ц': 'w', 'у': 'e', 'к': 'r', 'е': 't', 'н': 'y', 'г': 'u', 'ш': 'i', 'щ': 'o', 'з': 'p', 'х': '[', 'ъ': ']',
  667. 'ф': 'a', 'ы': 's', 'в': 'd', 'а': 'f', 'п': 'g', 'р': 'h', 'о': 'j', 'л': 'k', 'д': 'l', 'ж': ';', 'э': "'",
  668. 'я': 'z', 'ч': 'x', 'с': 'c', 'м': 'v', 'и': 'b', 'т': 'n', 'ь': 'm', 'б': ',', 'ю': '.',
  669. 'і': 's', 'ї': ']', 'є': "'",
  670. 'Й': 'Q', 'Ц': 'W', 'У': 'E', 'К': 'R', 'Е': 'T', 'Н': 'Y', 'Г': 'U', 'Ш': 'I', 'Щ': 'O', 'З': 'P', 'Х': '[', 'Ъ': ']',
  671. 'Ф': 'A', 'Ы': 'S', 'В': 'D', 'А': 'F', 'П': 'G', 'Р': 'H', 'О': 'J', 'Л': 'K', 'Д': 'L', 'Ж': ';', 'Э': "'",
  672. 'Я': 'Z', 'Ч': 'X', 'С': 'C', 'М': 'V', 'И': 'B', 'Т': 'N', 'Ь': 'M', 'Б': ',', 'Ю': '.',
  673. 'І': 'S', 'Ї': ']', 'Є': "'",
  674. 'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h', 'θ': 'u', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm',
  675. 'ν': 'n', 'ξ': 'j', 'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'ς': 's', 'τ': 't', 'υ': 'y', 'φ': 'f', 'χ': 'x', 'ψ': 'c', 'ω': 'v',
  676. 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z', 'Η': 'H', 'Θ': 'U', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M',
  677. 'Ν': 'N', 'Ξ': 'J', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y', 'Φ': 'F', 'Χ': 'X', 'Ψ': 'C', 'Ω': 'V',
  678. 'á': 'a', 'é': 'e', 'í': 'i', 'ó': 'o', 'ú': 'u', 'ý': 'y',
  679. 'à': 'a', 'è': 'e', 'ì': 'i', 'ò': 'o', 'ù': 'u',
  680. 'â': 'a', 'ê': 'e', 'î': 'i', 'ô': 'o', 'û': 'u',
  681. 'ã': 'a', 'õ': 'o', 'ñ': 'n', 'ç': 'c', 'ë': 'e', 'ï': 'i', 'ü': 'u',
  682. 'Á': 'A', 'É': 'E', 'Í': 'I', 'Ó': 'O', 'Ú': 'U', 'Ý': 'Y',
  683. 'À': 'A', 'È': 'E', 'Ì': 'I', 'Ò': 'O', 'Ù': 'U',
  684. 'Â': 'A', 'Ê': 'E', 'Î': 'I', 'Ô': 'O', 'Û': 'U',
  685. 'Ã': 'A', 'Õ': 'O', 'Ñ': 'N', 'Ç': 'C', 'Ë': 'E', 'Ï': 'I', 'Ü': 'U',
  686. 'ß': 'ss'
  687. };
  688. let result = '';
  689. for (let i = 0; i < text.length; i++) {
  690. const char = text[i];
  691. result += layoutMap[char] || char;
  692. }
  693. return result;
  694. }
  695. function updateCounterUI() {
  696. const $input = $('#accountRegistration');
  697. const $counter = $('#accountCharCounter');
  698. const $prefixButton = $('.account_prefix');
  699. if ($input.length === 0 || $counter.length === 0) {
  700. return;
  701. }
  702. const maxChars = parseInt($input.attr('maxlength'), 10);
  703. const prefixLen = $prefixButton.length > 0 ? $prefixButton.text().trim().length : 0;
  704. const currentLen = $input.val().length;
  705. const remaining = maxChars - prefixLen - currentLen;
  706. $counter.text('{{ phrase(312) }}: ' + remaining);
  707. if (remaining < 0) {
  708. $counter.removeClass('text-muted').addClass('text-danger');
  709. } else {
  710. $counter.removeClass('text-danger').addClass('text-muted');
  711. }
  712. }
  713. function enforceCharacterLimit() {
  714. const $input = $('#accountRegistration');
  715. if ($input.length === 0) return;
  716. const maxChars = parseInt($input.attr('maxlength'), 10);
  717. const prefixLen = $('.account_prefix').text().trim().length;
  718. const allowedInputLength = maxChars - prefixLen;
  719. if ($input.val().length > allowedInputLength) {
  720. const truncatedValue = $input.val().substring(0, allowedInputLength);
  721. $input.val(truncatedValue);
  722. }
  723. }
  724. $(document).on('input', '#accountRegistration', function () {
  725. const originalValue = $(this).val();
  726. let newValue = transliterate(originalValue);
  727. newValue = newValue.replace(/[^a-zA-Z0-9_]/g, '');
  728. if (originalValue !== newValue) {
  729. const start = this.selectionStart;
  730. const end = this.selectionEnd;
  731. $(this).val(newValue);
  732. this.setSelectionRange(start, end);
  733. }
  734. enforceCharacterLimit();
  735. updateCounterUI();
  736. });
  737. $(document).on('input', '#passwordRegistration', function () {
  738. const originalValue = $(this).val();
  739. let newValue = transliterate(originalValue);
  740. newValue = newValue.replace(/[^a-zA-Z0-9_]/g, '');
  741. if (originalValue !== newValue) {
  742. const start = this.selectionStart;
  743. const end = this.selectionEnd;
  744. $(this).val(newValue);
  745. this.setSelectionRange(start, end);
  746. }
  747. });
  748. updateCounterUI();
  749. $(document).on('click', '.account_prefix', function () {
  750. AjaxSend('/registration/account/prefix', 'POST', {}, true).then(function (prefix) {
  751. if (prefix.type === "notice") {
  752. responseAnalysis(prefix);
  753. return;
  754. }
  755. $('.account_prefix').text(prefix);
  756. updateCounterUI();
  757. });
  758. });
  759. $(document).on('click', '#togglePassword', function () {
  760. const passwordField = $('#passwordRegistration');
  761. const passwordFieldType = passwordField.attr('type');
  762. const toggleIcon = $(this).find('i');
  763. if (passwordFieldType === 'password') {
  764. passwordField.attr('type', 'text');
  765. toggleIcon.removeClass('bi-eye-fill').addClass('bi-eye-slash-fill');
  766. } else {
  767. passwordField.attr('type', 'password');
  768. toggleIcon.removeClass('bi-eye-slash-fill').addClass('bi-eye-fill');
  769. }
  770. });
  771. $(document).on('change', '#hidePasswordRegistration', function () {
  772. const passwordField = $('#passwordRegistration');
  773. const toggleIcon = $('#togglePassword').find('i');
  774. if ($(this).is(':checked')) {
  775. passwordField.attr('type', 'password');
  776. toggleIcon.removeClass('bi-eye-slash-fill').addClass('bi-eye-fill');
  777. } else {
  778. passwordField.attr('type', 'text');
  779. toggleIcon.removeClass('bi-eye-fill').addClass('bi-eye-slash-fill');
  780. }
  781. });
  782. </script>
  783. <script>
  784. function messageRegistrationAccount(response) {
  785. if (response.ok) {
  786. $("#registrationDataMessage").removeClass("d-none");
  787. $("#registrationMessage").removeClass("bg-success-transparent");
  788. $("#registrationMessage").removeClass("bg-danger-transparent");
  789. $("#registrationMessage").addClass("bg-success-transparent");
  790. $("#registrationMessage").text(response.message);
  791. } else {
  792. $("#registrationDataMessage").removeClass("d-none");
  793. $("#registrationMessage").removeClass("bg-danger-transparent");
  794. $("#registrationMessage").removeClass("bg-success-transparent");
  795. $("#registrationMessage").addClass("bg-danger-transparent");
  796. $("#registrationMessage").text(response.message);
  797. }
  798. }
  799. $(document).ready(function () {
  800. var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
  801. var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
  802. return new bootstrap.Tooltip(tooltipTriggerEl);
  803. });
  804. $(document).on('click', '.toggle-characters', function () {
  805. var accountName = $(this).data('account');
  806. var characterRow = $('.character-row-' + CSS.escape(accountName));
  807. $('.character-container').not(characterRow).hide();
  808. characterRow.toggle();
  809. });
  810. });
  811. </script>
  812. {%endblock%}
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Environment.php(392) : eval()'d code (строка 50)
Twig\Template->yield(Array(18))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Template.php (строка 360)
__TwigTemplate_313ff35f9e89a79cdc34f4c7d7c6ba71->doDisplay(Array(18), Array(0))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Environment.php(392) : eval()'d code (строка 1066)
Twig\Template->yield(Array(17))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Template.php (строка 430)
__TwigTemplate_b3d3adc28658407de0038475a51107e3->block_content(Array(17), Array(5))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Environment.php(392) : eval()'d code (строка 269)
Twig\Template->yieldBlock('content', Array(12), Array(5))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Template.php (строка 360)
__TwigTemplate_64a03cda582864f9912d97731d1f6eb7->doDisplay(Array(12), Array(5))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Environment.php(392) : eval()'d code (строка 45)
Twig\Template->yield(Array(11), Array(5))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Template.php (строка 360)
__TwigTemplate_b3d3adc28658407de0038475a51107e3->doDisplay(Array(11), Array(3))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/Template.php (строка 327)
Twig\Template->yield(Array(11), Array(3))
/home/emerland/web/emerland.su/public_html/vendor/twig/twig/src/TemplateWrapper.php (строка 45)
Twig\Template->display(Array(11), Array(0))
/home/emerland/web/emerland.su/public_html/src/template/tpl.php (строка 2795)
Twig\TemplateWrapper->display(Array(11))
/home/emerland/web/emerland.su/public_html/src/controller/main/main.php (строка 18)
Ofey\Logan22\template\tpl::display('index.html')
[Внутренняя функция]
Ofey\Logan22\controller\main\main::index()
/home/emerland/web/emerland.su/public_html/vendor/bramus/router/src/Bramus/Router/Router.php (строка 430)
call_user_func_array('Ofey\Logan22\controller\main\m...', Array(0))
/home/emerland/web/emerland.su/public_html/vendor/bramus/router/src/Bramus/Router/Router.php (строка 416)
Bramus\Router\Router->invoke('Ofey\Logan22\controller\main\m...', Array(0))
/home/emerland/web/emerland.su/public_html/vendor/bramus/router/src/Bramus/Router/Router.php (строка 280)
Bramus\Router\Router->handle(Array(174), true)
/home/emerland/web/emerland.su/public_html/src/route/route_registry.php (строка 90)
Bramus\Router\Router->run()
/home/emerland/web/emerland.su/public_html/index.php (строка 11)
require('/home/emerland/web/emerland.su...')

Переменные доступные в шаблоне:

__route__ (string)
"/main"
dir (string)
""
protocol (string)
"https"
path (string)
""
template (string)
"/src/template/sphere/"
pointTime (string)
"0.10"
page_external_css (array)
[]
page_external_js (array)
[]
page_inline_css (string)
""
page_inline_js (string)
"$(document).on('click', '.removeHWID', function () { var obj = $(this).data('obj'); var acco..."
page_title (string)
"Личный кабинет"

Возможные решения

Проверьте синтаксис и логику шаблона.
Убедитесь, что все переменные и функции определены и доступны.
Проверьте, не используются ли устаревшие методы или функции.