var/cache/dev/twig/ab/abdc6bea67325ad6b3755d2fd0648e4f.php line 55

Open in your IDE?
  1. <?php
  2. use Twig\Environment;
  3. use Twig\Error\LoaderError;
  4. use Twig\Error\RuntimeError;
  5. use Twig\Extension\CoreExtension;
  6. use Twig\Extension\SandboxExtension;
  7. use Twig\Markup;
  8. use Twig\Sandbox\SecurityError;
  9. use Twig\Sandbox\SecurityNotAllowedTagError;
  10. use Twig\Sandbox\SecurityNotAllowedFilterError;
  11. use Twig\Sandbox\SecurityNotAllowedFunctionError;
  12. use Twig\Source;
  13. use Twig\Template;
  14. use Twig\TemplateWrapper;
  15. /* pages/listelivre.html.twig */
  16. class __TwigTemplate_2a8fb7fa7eca9999182491f324d06712 extends Template
  17. {
  18. private Source $source;
  19. /**
  20. * @var array<string, Template>
  21. */
  22. private array $macros = [];
  23. public function __construct(Environment $env)
  24. {
  25. parent::__construct($env);
  26. $this->source = $this->getSourceContext();
  27. $this->blocks = [
  28. 'body' => [$this, 'block_body'],
  29. 'stylesheets' => [$this, 'block_stylesheets'],
  30. 'javascripts' => [$this, 'block_javascripts'],
  31. ];
  32. }
  33. protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
  34. {
  35. // line 1
  36. return "base.html.twig";
  37. }
  38. protected function doDisplay(array $context, array $blocks = []): iterable
  39. {
  40. $macros = $this->macros;
  41. $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  42. $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "pages/listelivre.html.twig"));
  43. $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  44. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "pages/listelivre.html.twig"));
  45. $this->parent = $this->loadTemplate("base.html.twig", "pages/listelivre.html.twig", 1);
  46. yield from $this->parent->unwrap()->yield($context, array_merge($this->blocks, $blocks));
  47. $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  48. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  49. }
  50. // line 3
  51. /**
  52. * @return iterable<null|scalar|\Stringable>
  53. */
  54. public function block_body(array $context, array $blocks = []): iterable
  55. {
  56. $macros = $this->macros;
  57. $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  58. $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body"));
  59. $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  60. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body"));
  61. // line 4
  62. yield "<div id=\"titleListe\">
  63. ";
  64. // line 5
  65. if ((array_key_exists("isSearchResult", $context) && (isset($context["isSearchResult"]) || array_key_exists("isSearchResult", $context) ? $context["isSearchResult"] : (function () { throw new RuntimeError('Variable "isSearchResult" does not exist.', 5, $this->source); })()))) {
  66. // line 6
  67. yield " <!-- Résultats de recherche avec formulaire de modification -->
  68. <div class=\"card mb-4\">
  69. <div class=\"card-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
  70. <div class=\"d-flex justify-content-between align-items-center\">
  71. <h5 class=\"mb-0 text-white\">
  72. <i class=\"fas fa-search\"></i> Résultats de recherche
  73. </h5>
  74. ";
  75. // line 13
  76. if (((isset($context["totalResults"]) || array_key_exists("totalResults", $context) ? $context["totalResults"] : (function () { throw new RuntimeError('Variable "totalResults" does not exist.', 13, $this->source); })()) > 0)) {
  77. // line 14
  78. yield " <span class=\"badge badge-light px-3 py-2\">";
  79. yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["totalResults"]) || array_key_exists("totalResults", $context) ? $context["totalResults"] : (function () { throw new RuntimeError('Variable "totalResults" does not exist.', 14, $this->source); })()), "html", null, true);
  80. yield " livre(s)</span>
  81. ";
  82. }
  83. // line 16
  84. yield " </div>
  85. </div>
  86. <div class=\"card-body\">
  87. <!-- Formulaire de recherche intégré -->
  88. <form action=\"";
  89. // line 20
  90. yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("searchBook");
  91. yield "\" method=\"get\" class=\"mb-3\" id=\"searchForm\">
  92. <div class=\"row\">
  93. <div class=\"col-md-5 mb-2\">
  94. <div class=\"input-group\">
  95. <div class=\"input-group-prepend\">
  96. <span class=\"input-group-text bg-white border-right-0\"><i class=\"fas fa-book text-primary\"></i></span>
  97. </div>
  98. <input type=\"text\" name=\"value\" class=\"form-control border-left-0\" id=\"search\"
  99. value=\"";
  100. // line 28
  101. yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["searchQuery"]) || array_key_exists("searchQuery", $context) ? $context["searchQuery"] : (function () { throw new RuntimeError('Variable "searchQuery" does not exist.', 28, $this->source); })()), "html", null, true);
  102. yield "\"
  103. placeholder=\"Titre, auteur ou ISBN...\">
  104. <div class=\"input-group-append d-md-none\">
  105. <button type=\"button\" class=\"btn bg-white border-left-0\" id=\"scanBarcodeBtn\" title=\"Scanner un code-barres\" style=\"border-color: #ced4da; color: #6c757d;\">
  106. <i class=\"fas fa-barcode\"></i>
  107. </button>
  108. </div>
  109. </div>
  110. </div>
  111. <div class=\"col-md-4 mb-2\">
  112. <select name=\"user\" class=\"form-control\">
  113. <option value=\"0\">Toutes les bibliothèques</option>
  114. ";
  115. // line 40
  116. if (array_key_exists("users", $context)) {
  117. // line 41
  118. yield " ";
  119. $context['_parent'] = $context;
  120. $context['_seq'] = CoreExtension::ensureTraversable((isset($context["users"]) || array_key_exists("users", $context) ? $context["users"] : (function () { throw new RuntimeError('Variable "users" does not exist.', 41, $this->source); })()));
  121. foreach ($context['_seq'] as $context["_key"] => $context["user"]) {
  122. // line 42
  123. yield " <option value=\"";
  124. yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["user"], "id", [], "any", false, false, false, 42), "html", null, true);
  125. yield "\" ";
  126. if ((array_key_exists("searchUserId", $context) && ((isset($context["searchUserId"]) || array_key_exists("searchUserId", $context) ? $context["searchUserId"] : (function () { throw new RuntimeError('Variable "searchUserId" does not exist.', 42, $this->source); })()) == CoreExtension::getAttribute($this->env, $this->source, $context["user"], "id", [], "any", false, false, false, 42)))) {
  127. yield "selected";
  128. }
  129. yield ">
  130. ";
  131. // line 43
  132. yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["user"], "name", [], "any", false, false, false, 43), "html", null, true);
  133. yield " ";
  134. yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["user"], "lastName", [], "any", false, false, false, 43), "html", null, true);
  135. yield "
  136. </option>
  137. ";
  138. }
  139. $_parent = $context['_parent'];
  140. unset($context['_seq'], $context['_key'], $context['user'], $context['_parent']);
  141. $context = array_intersect_key($context, $_parent) + $_parent;
  142. // line 46
  143. yield " ";
  144. }
  145. // line 47
  146. yield " </select>
  147. </div>
  148. <div class=\"col-md-3 mb-2\">
  149. <button type=\"submit\" class=\"btn btn-primary btn-block\">
  150. <i class=\"fas fa-search\"></i> Rechercher
  151. </button>
  152. </div>
  153. </div>
  154. </form>
  155. <!-- Zone de scan de code-barres -->
  156. <div id=\"barcodeScannerContainer\" class=\"mb-3\" style=\"display: none;\">
  157. <div class=\"card border-primary\">
  158. <div class=\"card-header bg-primary text-white d-flex justify-content-between align-items-center py-2\">
  159. <span><i class=\"fas fa-camera\"></i> Scanner un code-barres ISBN</span>
  160. <button type=\"button\" class=\"btn btn-sm btn-light\" id=\"closeScannerBtn\">
  161. <i class=\"fas fa-times\"></i>
  162. </button>
  163. </div>
  164. <div class=\"card-body p-0\">
  165. <div id=\"barcodeReader\" style=\"width: 100%;\"></div>
  166. <div class=\"p-2\">
  167. <p class=\"text-muted small mb-0\">
  168. <i class=\"fas fa-info-circle\"></i> Positionnez le code-barres ISBN devant la caméra.
  169. </p>
  170. </div>
  171. </div>
  172. </div>
  173. </div>
  174. <div class=\"d-flex flex-wrap align-items-center mb-3\">
  175. <span class=\"mr-2 text-muted\">Recherche actuelle :</span>
  176. <span class=\"badge badge-primary mr-2 px-3 py-2\" style=\"font-size: 0.95rem;\">";
  177. // line 79
  178. yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["searchQuery"]) || array_key_exists("searchQuery", $context) ? $context["searchQuery"] : (function () { throw new RuntimeError('Variable "searchQuery" does not exist.', 79, $this->source); })()), "html", null, true);
  179. yield "</span>
  180. ";
  181. // line 80
  182. if ((isset($context["searchUser"]) || array_key_exists("searchUser", $context) ? $context["searchUser"] : (function () { throw new RuntimeError('Variable "searchUser" does not exist.', 80, $this->source); })())) {
  183. // line 81
  184. yield " <span class=\"badge badge-success px-3 py-2\" style=\"font-size: 0.95rem;\">
  185. <i class=\"fas fa-user\"></i> ";
  186. // line 82
  187. yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["searchUser"]) || array_key_exists("searchUser", $context) ? $context["searchUser"] : (function () { throw new RuntimeError('Variable "searchUser" does not exist.', 82, $this->source); })()), "html", null, true);
  188. yield "
  189. </span>
  190. ";
  191. }
  192. // line 85
  193. yield " </div>
  194. ";
  195. // line 87
  196. if (((isset($context["totalResults"]) || array_key_exists("totalResults", $context) ? $context["totalResults"] : (function () { throw new RuntimeError('Variable "totalResults" does not exist.', 87, $this->source); })()) == 0)) {
  197. // line 88
  198. yield " <div class=\"alert alert-warning border-0\" style=\"background-color: #fff3cd;\">
  199. <h5 class=\"alert-heading\"><i class=\"fas fa-exclamation-triangle\"></i> Aucun résultat</h5>
  200. <p class=\"mb-2\">Aucun livre ne correspond à \"<strong>";
  201. // line 90
  202. yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["searchQuery"]) || array_key_exists("searchQuery", $context) ? $context["searchQuery"] : (function () { throw new RuntimeError('Variable "searchQuery" does not exist.', 90, $this->source); })()), "html", null, true);
  203. yield "</strong>\"</p>
  204. <hr>
  205. <p class=\"mb-0 small\">
  206. <strong>Suggestions :</strong> Vérifiez l'orthographe, essayez des termes plus généraux, ou vérifiez le code ISBN.
  207. </p>
  208. </div>
  209. ";
  210. }
  211. // line 97
  212. yield "
  213. <div class=\"d-flex flex-wrap\">
  214. <a href=\"";
  215. // line 99
  216. yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("listesLivres");
  217. yield "\" class=\"btn btn-outline-secondary mb-2\">
  218. <i class=\"fas fa-list\"></i> Tout le catalogue
  219. </a>
  220. </div>
  221. </div>
  222. </div>
  223. ";
  224. } else {
  225. // line 106
  226. yield " <!-- Liste complète des livres -->
  227. <div class=\"card mb-4\">
  228. <div class=\"card-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
  229. <div class=\"d-flex justify-content-between align-items-center\">
  230. <h5 class=\"mb-0 text-white\">
  231. <i class=\"fas fa-book\"></i> Catalogue complet
  232. </h5>
  233. <a href=\"";
  234. // line 113
  235. yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("index");
  236. yield "\" class=\"btn btn-light btn-sm\">
  237. <i class=\"fas fa-search\"></i> Rechercher
  238. </a>
  239. </div>
  240. </div>
  241. <div class=\"card-body py-2\">
  242. <small class=\"text-muted\">
  243. <i class=\"fas fa-info-circle\"></i>
  244. Cliquez sur une couverture pour l'agrandir, ou sur un titre pour voir les détails.
  245. </small>
  246. </div>
  247. </div>
  248. ";
  249. }
  250. // line 126
  251. yield "</div>
  252. ";
  253. // line 128
  254. if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["Listelivres"]) || array_key_exists("Listelivres", $context) ? $context["Listelivres"] : (function () { throw new RuntimeError('Variable "Listelivres" does not exist.', 128, $this->source); })())) > 0)) {
  255. // line 129
  256. yield " ";
  257. yield from $this->loadTemplate("includes/tableauLivres.html.twig", "pages/listelivre.html.twig", 129)->unwrap()->yield(CoreExtension::merge($context, ["pagination" => (isset($context["pagination"]) || array_key_exists("pagination", $context) ? $context["pagination"] : (function () { throw new RuntimeError('Variable "pagination" does not exist.', 129, $this->source); })()), "images" => (isset($context["images"]) || array_key_exists("images", $context) ? $context["images"] : (function () { throw new RuntimeError('Variable "images" does not exist.', 129, $this->source); })()), "Listelivres" => (isset($context["Listelivres"]) || array_key_exists("Listelivres", $context) ? $context["Listelivres"] : (function () { throw new RuntimeError('Variable "Listelivres" does not exist.', 129, $this->source); })())]));
  258. }
  259. // line 131
  260. yield "
  261. ";
  262. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  263. $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  264. yield from [];
  265. }
  266. // line 135
  267. /**
  268. * @return iterable<null|scalar|\Stringable>
  269. */
  270. public function block_stylesheets(array $context, array $blocks = []): iterable
  271. {
  272. $macros = $this->macros;
  273. $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  274. $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "stylesheets"));
  275. $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  276. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "stylesheets"));
  277. // line 136
  278. yield " ";
  279. yield from $this->yieldParentBlock("stylesheets", $context, $blocks);
  280. yield "
  281. <style>
  282. /* Arrondir le bord droit de l'input sur desktop (quand le bouton scan est caché) */
  283. @media (min-width: 768px) {
  284. #search {
  285. border-top-right-radius: 0.25rem !important;
  286. border-bottom-right-radius: 0.25rem !important;
  287. }
  288. }
  289. </style>
  290. ";
  291. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  292. $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  293. yield from [];
  294. }
  295. // line 148
  296. /**
  297. * @return iterable<null|scalar|\Stringable>
  298. */
  299. public function block_javascripts(array $context, array $blocks = []): iterable
  300. {
  301. $macros = $this->macros;
  302. $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  303. $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascripts"));
  304. $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  305. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascripts"));
  306. // line 149
  307. yield " ";
  308. yield from $this->yieldParentBlock("javascripts", $context, $blocks);
  309. yield "
  310. <!-- Bibliothèque html5-qrcode pour le scan de code-barres -->
  311. <script src=\"https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js\"></script>
  312. <script>
  313. \$(document).ready(function () {
  314. var modal = document.getElementById(\"myModal\");
  315. var modalImg = document.getElementById(\"img01\");
  316. var captionText = document.getElementById(\"caption\");
  317. // Fermer la modale en cliquant sur le X
  318. \$('.image-modal-close').click(function() {
  319. modal.style.display = \"none\";
  320. });
  321. // Fermer la modale en cliquant sur le fond
  322. \$('#myModal').click(function (event) {
  323. if (event.target === modal) {
  324. modal.style.display = \"none\";
  325. }
  326. });
  327. // Ouvrir la modale en cliquant sur une image
  328. \$('.img-cover').click(function (event) {
  329. var image = document.getElementById(event.target.id);
  330. modal.style.display = \"block\";
  331. modalImg.src = image.src;
  332. captionText.innerHTML = image.alt;
  333. });
  334. // Fermer avec Echap
  335. \$(document).keydown(function(e) {
  336. if (e.keyCode === 27) {
  337. modal.style.display = \"none\";
  338. }
  339. });
  340. // Scanner de code-barres
  341. let html5QrCode = null;
  342. let isScanning = false;
  343. \$('#scanBarcodeBtn').click(function() {
  344. \$('#barcodeScannerContainer').slideDown();
  345. startScanner();
  346. });
  347. \$('#closeScannerBtn').click(function() {
  348. stopScanner();
  349. \$('#barcodeScannerContainer').slideUp();
  350. });
  351. function startScanner() {
  352. if (isScanning) return;
  353. html5QrCode = new Html5Qrcode(\"barcodeReader\");
  354. const config = {
  355. fps: 10,
  356. qrbox: { width: 250, height: 100 },
  357. formatsToSupport: [
  358. Html5QrcodeSupportedFormats.EAN_13,
  359. Html5QrcodeSupportedFormats.EAN_8,
  360. Html5QrcodeSupportedFormats.UPC_A,
  361. Html5QrcodeSupportedFormats.UPC_E,
  362. Html5QrcodeSupportedFormats.CODE_128,
  363. Html5QrcodeSupportedFormats.CODE_39
  364. ]
  365. };
  366. html5QrCode.start(
  367. { facingMode: \"environment\" },
  368. config,
  369. onScanSuccess,
  370. onScanError
  371. ).then(() => {
  372. isScanning = true;
  373. }).catch((err) => {
  374. console.error(\"Erreur démarrage scanner:\", err);
  375. showScannerError(\"Impossible d'accéder à la caméra. Vérifiez les permissions.\");
  376. });
  377. }
  378. function stopScanner() {
  379. if (html5QrCode && isScanning) {
  380. html5QrCode.stop().then(() => {
  381. isScanning = false;
  382. html5QrCode.clear();
  383. }).catch((err) => {
  384. console.error(\"Erreur arrêt scanner:\", err);
  385. });
  386. }
  387. }
  388. function onScanSuccess(decodedText, decodedResult) {
  389. try {
  390. const audioContext = new (window.AudioContext || window.webkitAudioContext)();
  391. const oscillator = audioContext.createOscillator();
  392. oscillator.type = 'sine';
  393. oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
  394. oscillator.connect(audioContext.destination);
  395. oscillator.start();
  396. oscillator.stop(audioContext.currentTime + 0.1);
  397. } catch(e) {}
  398. \$('#search').val(decodedText);
  399. showScannerSuccess(\"Code-barres détecté : \" + decodedText);
  400. stopScanner();
  401. setTimeout(function() {
  402. \$('#barcodeScannerContainer').slideUp();
  403. }, 1000);
  404. }
  405. function onScanError(errorMessage) {}
  406. function showScannerSuccess(message) {
  407. const alertHtml = '<div class=\"alert alert-success alert-dismissible fade show m-3\" role=\"alert\">' +
  408. '<i class=\"fas fa-check-circle\"></i> ' + message +
  409. '<button type=\"button\" class=\"close\" data-dismiss=\"alert\"><span>&times;</span></button>' +
  410. '</div>';
  411. \$('#barcodeReader').after(alertHtml);
  412. }
  413. function showScannerError(message) {
  414. const alertHtml = '<div class=\"alert alert-danger m-3\" role=\"alert\">' +
  415. '<i class=\"fas fa-exclamation-triangle\"></i> ' + message +
  416. '</div>';
  417. \$('#barcodeReader').html(alertHtml);
  418. }
  419. });
  420. </script>
  421. ";
  422. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  423. $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  424. yield from [];
  425. }
  426. /**
  427. * @codeCoverageIgnore
  428. */
  429. public function getTemplateName(): string
  430. {
  431. return "pages/listelivre.html.twig";
  432. }
  433. /**
  434. * @codeCoverageIgnore
  435. */
  436. public function isTraitable(): bool
  437. {
  438. return false;
  439. }
  440. /**
  441. * @codeCoverageIgnore
  442. */
  443. public function getDebugInfo(): array
  444. {
  445. return array ( 341 => 149, 328 => 148, 305 => 136, 292 => 135, 280 => 131, 276 => 129, 274 => 128, 270 => 126, 254 => 113, 245 => 106, 235 => 99, 231 => 97, 221 => 90, 217 => 88, 215 => 87, 211 => 85, 205 => 82, 202 => 81, 200 => 80, 196 => 79, 162 => 47, 159 => 46, 148 => 43, 139 => 42, 134 => 41, 132 => 40, 117 => 28, 106 => 20, 100 => 16, 94 => 14, 92 => 13, 83 => 6, 81 => 5, 78 => 4, 65 => 3, 42 => 1,);
  446. }
  447. public function getSourceContext(): Source
  448. {
  449. return new Source("{% extends 'base.html.twig' %}
  450. {% block body %}
  451. <div id=\"titleListe\">
  452. {% if isSearchResult is defined and isSearchResult %}
  453. <!-- Résultats de recherche avec formulaire de modification -->
  454. <div class=\"card mb-4\">
  455. <div class=\"card-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
  456. <div class=\"d-flex justify-content-between align-items-center\">
  457. <h5 class=\"mb-0 text-white\">
  458. <i class=\"fas fa-search\"></i> Résultats de recherche
  459. </h5>
  460. {% if totalResults > 0 %}
  461. <span class=\"badge badge-light px-3 py-2\">{{ totalResults }} livre(s)</span>
  462. {% endif %}
  463. </div>
  464. </div>
  465. <div class=\"card-body\">
  466. <!-- Formulaire de recherche intégré -->
  467. <form action=\"{{ path('searchBook') }}\" method=\"get\" class=\"mb-3\" id=\"searchForm\">
  468. <div class=\"row\">
  469. <div class=\"col-md-5 mb-2\">
  470. <div class=\"input-group\">
  471. <div class=\"input-group-prepend\">
  472. <span class=\"input-group-text bg-white border-right-0\"><i class=\"fas fa-book text-primary\"></i></span>
  473. </div>
  474. <input type=\"text\" name=\"value\" class=\"form-control border-left-0\" id=\"search\"
  475. value=\"{{ searchQuery }}\"
  476. placeholder=\"Titre, auteur ou ISBN...\">
  477. <div class=\"input-group-append d-md-none\">
  478. <button type=\"button\" class=\"btn bg-white border-left-0\" id=\"scanBarcodeBtn\" title=\"Scanner un code-barres\" style=\"border-color: #ced4da; color: #6c757d;\">
  479. <i class=\"fas fa-barcode\"></i>
  480. </button>
  481. </div>
  482. </div>
  483. </div>
  484. <div class=\"col-md-4 mb-2\">
  485. <select name=\"user\" class=\"form-control\">
  486. <option value=\"0\">Toutes les bibliothèques</option>
  487. {% if users is defined %}
  488. {% for user in users %}
  489. <option value=\"{{ user.id }}\" {% if searchUserId is defined and searchUserId == user.id %}selected{% endif %}>
  490. {{ user.name }} {{ user.lastName }}
  491. </option>
  492. {% endfor %}
  493. {% endif %}
  494. </select>
  495. </div>
  496. <div class=\"col-md-3 mb-2\">
  497. <button type=\"submit\" class=\"btn btn-primary btn-block\">
  498. <i class=\"fas fa-search\"></i> Rechercher
  499. </button>
  500. </div>
  501. </div>
  502. </form>
  503. <!-- Zone de scan de code-barres -->
  504. <div id=\"barcodeScannerContainer\" class=\"mb-3\" style=\"display: none;\">
  505. <div class=\"card border-primary\">
  506. <div class=\"card-header bg-primary text-white d-flex justify-content-between align-items-center py-2\">
  507. <span><i class=\"fas fa-camera\"></i> Scanner un code-barres ISBN</span>
  508. <button type=\"button\" class=\"btn btn-sm btn-light\" id=\"closeScannerBtn\">
  509. <i class=\"fas fa-times\"></i>
  510. </button>
  511. </div>
  512. <div class=\"card-body p-0\">
  513. <div id=\"barcodeReader\" style=\"width: 100%;\"></div>
  514. <div class=\"p-2\">
  515. <p class=\"text-muted small mb-0\">
  516. <i class=\"fas fa-info-circle\"></i> Positionnez le code-barres ISBN devant la caméra.
  517. </p>
  518. </div>
  519. </div>
  520. </div>
  521. </div>
  522. <div class=\"d-flex flex-wrap align-items-center mb-3\">
  523. <span class=\"mr-2 text-muted\">Recherche actuelle :</span>
  524. <span class=\"badge badge-primary mr-2 px-3 py-2\" style=\"font-size: 0.95rem;\">{{ searchQuery }}</span>
  525. {% if searchUser %}
  526. <span class=\"badge badge-success px-3 py-2\" style=\"font-size: 0.95rem;\">
  527. <i class=\"fas fa-user\"></i> {{ searchUser }}
  528. </span>
  529. {% endif %}
  530. </div>
  531. {% if totalResults == 0 %}
  532. <div class=\"alert alert-warning border-0\" style=\"background-color: #fff3cd;\">
  533. <h5 class=\"alert-heading\"><i class=\"fas fa-exclamation-triangle\"></i> Aucun résultat</h5>
  534. <p class=\"mb-2\">Aucun livre ne correspond à \"<strong>{{ searchQuery }}</strong>\"</p>
  535. <hr>
  536. <p class=\"mb-0 small\">
  537. <strong>Suggestions :</strong> Vérifiez l'orthographe, essayez des termes plus généraux, ou vérifiez le code ISBN.
  538. </p>
  539. </div>
  540. {% endif %}
  541. <div class=\"d-flex flex-wrap\">
  542. <a href=\"{{ path('listesLivres') }}\" class=\"btn btn-outline-secondary mb-2\">
  543. <i class=\"fas fa-list\"></i> Tout le catalogue
  544. </a>
  545. </div>
  546. </div>
  547. </div>
  548. {% else %}
  549. <!-- Liste complète des livres -->
  550. <div class=\"card mb-4\">
  551. <div class=\"card-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
  552. <div class=\"d-flex justify-content-between align-items-center\">
  553. <h5 class=\"mb-0 text-white\">
  554. <i class=\"fas fa-book\"></i> Catalogue complet
  555. </h5>
  556. <a href=\"{{ path('index') }}\" class=\"btn btn-light btn-sm\">
  557. <i class=\"fas fa-search\"></i> Rechercher
  558. </a>
  559. </div>
  560. </div>
  561. <div class=\"card-body py-2\">
  562. <small class=\"text-muted\">
  563. <i class=\"fas fa-info-circle\"></i>
  564. Cliquez sur une couverture pour l'agrandir, ou sur un titre pour voir les détails.
  565. </small>
  566. </div>
  567. </div>
  568. {% endif %}
  569. </div>
  570. {% if Listelivres|length > 0 %}
  571. {% include 'includes/tableauLivres.html.twig' with {'pagination' : pagination, 'images' : images, 'Listelivres' : Listelivres}%}
  572. {% endif %}
  573. {% endblock %}
  574. {% block stylesheets %}
  575. {{ parent() }}
  576. <style>
  577. /* Arrondir le bord droit de l'input sur desktop (quand le bouton scan est caché) */
  578. @media (min-width: 768px) {
  579. #search {
  580. border-top-right-radius: 0.25rem !important;
  581. border-bottom-right-radius: 0.25rem !important;
  582. }
  583. }
  584. </style>
  585. {% endblock %}
  586. {% block javascripts %}
  587. {{parent()}}
  588. <!-- Bibliothèque html5-qrcode pour le scan de code-barres -->
  589. <script src=\"https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js\"></script>
  590. <script>
  591. \$(document).ready(function () {
  592. var modal = document.getElementById(\"myModal\");
  593. var modalImg = document.getElementById(\"img01\");
  594. var captionText = document.getElementById(\"caption\");
  595. // Fermer la modale en cliquant sur le X
  596. \$('.image-modal-close').click(function() {
  597. modal.style.display = \"none\";
  598. });
  599. // Fermer la modale en cliquant sur le fond
  600. \$('#myModal').click(function (event) {
  601. if (event.target === modal) {
  602. modal.style.display = \"none\";
  603. }
  604. });
  605. // Ouvrir la modale en cliquant sur une image
  606. \$('.img-cover').click(function (event) {
  607. var image = document.getElementById(event.target.id);
  608. modal.style.display = \"block\";
  609. modalImg.src = image.src;
  610. captionText.innerHTML = image.alt;
  611. });
  612. // Fermer avec Echap
  613. \$(document).keydown(function(e) {
  614. if (e.keyCode === 27) {
  615. modal.style.display = \"none\";
  616. }
  617. });
  618. // Scanner de code-barres
  619. let html5QrCode = null;
  620. let isScanning = false;
  621. \$('#scanBarcodeBtn').click(function() {
  622. \$('#barcodeScannerContainer').slideDown();
  623. startScanner();
  624. });
  625. \$('#closeScannerBtn').click(function() {
  626. stopScanner();
  627. \$('#barcodeScannerContainer').slideUp();
  628. });
  629. function startScanner() {
  630. if (isScanning) return;
  631. html5QrCode = new Html5Qrcode(\"barcodeReader\");
  632. const config = {
  633. fps: 10,
  634. qrbox: { width: 250, height: 100 },
  635. formatsToSupport: [
  636. Html5QrcodeSupportedFormats.EAN_13,
  637. Html5QrcodeSupportedFormats.EAN_8,
  638. Html5QrcodeSupportedFormats.UPC_A,
  639. Html5QrcodeSupportedFormats.UPC_E,
  640. Html5QrcodeSupportedFormats.CODE_128,
  641. Html5QrcodeSupportedFormats.CODE_39
  642. ]
  643. };
  644. html5QrCode.start(
  645. { facingMode: \"environment\" },
  646. config,
  647. onScanSuccess,
  648. onScanError
  649. ).then(() => {
  650. isScanning = true;
  651. }).catch((err) => {
  652. console.error(\"Erreur démarrage scanner:\", err);
  653. showScannerError(\"Impossible d'accéder à la caméra. Vérifiez les permissions.\");
  654. });
  655. }
  656. function stopScanner() {
  657. if (html5QrCode && isScanning) {
  658. html5QrCode.stop().then(() => {
  659. isScanning = false;
  660. html5QrCode.clear();
  661. }).catch((err) => {
  662. console.error(\"Erreur arrêt scanner:\", err);
  663. });
  664. }
  665. }
  666. function onScanSuccess(decodedText, decodedResult) {
  667. try {
  668. const audioContext = new (window.AudioContext || window.webkitAudioContext)();
  669. const oscillator = audioContext.createOscillator();
  670. oscillator.type = 'sine';
  671. oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
  672. oscillator.connect(audioContext.destination);
  673. oscillator.start();
  674. oscillator.stop(audioContext.currentTime + 0.1);
  675. } catch(e) {}
  676. \$('#search').val(decodedText);
  677. showScannerSuccess(\"Code-barres détecté : \" + decodedText);
  678. stopScanner();
  679. setTimeout(function() {
  680. \$('#barcodeScannerContainer').slideUp();
  681. }, 1000);
  682. }
  683. function onScanError(errorMessage) {}
  684. function showScannerSuccess(message) {
  685. const alertHtml = '<div class=\"alert alert-success alert-dismissible fade show m-3\" role=\"alert\">' +
  686. '<i class=\"fas fa-check-circle\"></i> ' + message +
  687. '<button type=\"button\" class=\"close\" data-dismiss=\"alert\"><span>&times;</span></button>' +
  688. '</div>';
  689. \$('#barcodeReader').after(alertHtml);
  690. }
  691. function showScannerError(message) {
  692. const alertHtml = '<div class=\"alert alert-danger m-3\" role=\"alert\">' +
  693. '<i class=\"fas fa-exclamation-triangle\"></i> ' + message +
  694. '</div>';
  695. \$('#barcodeReader').html(alertHtml);
  696. }
  697. });
  698. </script>
  699. {% endblock %}", "pages/listelivre.html.twig", "/home/jla23/project/DEV/Bdd-Books-DEV/templates/pages/listelivre.html.twig");
  700. }
  701. }