diff --git a/admin/api/save-chapter.php b/admin/api/save-chapter.php index dd05f0e..293b585 100644 --- a/admin/api/save-chapter.php +++ b/admin/api/save-chapter.php @@ -12,7 +12,7 @@ $input = json_decode(file_get_contents('php://input'), true); $storyId = $input['storyId'] ?? null; $chapterId = $input['chapterId'] ?? null; $title = $input['title'] ?? ''; -$content = $input['content'] ?? ''; +$content = $input['content']; try { $story = Stories::get($storyId); diff --git a/assets/js/story-edit.js b/assets/js/story-edit.js index fc4e61f..77a8aa4 100644 --- a/assets/js/story-edit.js +++ b/assets/js/story-edit.js @@ -308,7 +308,7 @@ document.addEventListener('DOMContentLoaded', function() { storyId: storyId, chapterId: currentChapterId, title: title, - content: JSON.stringify(quill.getContents()) + content: quill.root.innerHTML }) }); diff --git a/chapitre.php b/chapitre.php index da63e19..388edcd 100644 --- a/chapitre.php +++ b/chapitre.php @@ -1,7 +1,6 @@ 0 ? $story['chapters'][$currentIndex - 1] : null; $nextChapter = $currentIndex < count($story['chapters']) - 1 ? $story['chapters'][$currentIndex + 1] : null; @@ -76,7 +65,7 @@ $config = Config::load();
- +
@@ -112,7 +101,8 @@ $config = Config::load();
@@ -121,7 +111,7 @@ $config = Config::load(); document.addEventListener('DOMContentLoaded', function() { const scrollTopBtn = document.querySelector('.scroll-top'); - // Afficher/masquer le bouton + // Afficher/masquer le bouton de retour en haut window.addEventListener('scroll', function() { if (window.pageYOffset > 300) { scrollTopBtn.classList.add('visible'); diff --git a/includes/DeltaConverter.php b/includes/DeltaConverter.php deleted file mode 100644 index 296023a..0000000 --- a/includes/DeltaConverter.php +++ /dev/null @@ -1,268 +0,0 @@ - '', - 'attrs' => [], - 'inlineAttrs' => [] - ]; - - foreach ($content['ops'] as $op) { - $text = ''; - $attrs = isset($op['attributes']) ? $op['attributes'] : []; - - // Gérer l'insertion de texte - if (is_string($op['insert'])) { - $text = $op['insert']; - - // Si c'est un saut de ligne, on finalise le bloc - if ($text === "\n") { - // Vérifier les attributs de bloc pour ce saut de ligne - if (!empty($attrs['align'])) { - $currentBlock['attrs']['text-align'] = $attrs['align']; - } - if (!empty($attrs['header'])) { - $currentBlock['attrs']['header'] = $attrs['header']; - } - if (!empty($attrs['blockquote'])) { - $currentBlock['attrs']['blockquote'] = true; - } - if (!empty($attrs['code-block'])) { - $currentBlock['attrs']['code-block'] = true; - } - - // Finaliser le bloc courant - if (!empty($currentBlock['content']) || !empty($currentBlock['attrs'])) { - $html .= self::renderBlock($currentBlock); - } - - // Réinitialiser pour le prochain bloc - $currentBlock = [ - 'content' => '', - 'attrs' => [], - 'inlineAttrs' => [] - ]; - } else { - // Ajouter le texte avec ses attributs inline - $currentBlock['content'] .= $text; - if (!empty($attrs)) { - $currentBlock['inlineAttrs'][] = [ - 'start' => mb_strlen($currentBlock['content']) - mb_strlen($text), - 'length' => mb_strlen($text), - 'attrs' => $attrs - ]; - } - } - } - // Gérer les images - elseif (is_array($op['insert']) && isset($op['insert']['image'])) { - if (!empty($currentBlock['content'])) { - $html .= self::renderBlock($currentBlock); - $currentBlock = [ - 'content' => '', - 'attrs' => [], - 'inlineAttrs' => [] - ]; - } - - $imageUrl = self::cleanImageUrl($op['insert']['image']); - $imgAttributes = ['class' => 'chapter-image']; - if (isset($attrs['alt'])) { - $imgAttributes['alt'] = $attrs['alt']; - } else { - $imgAttributes['alt'] = "Image"; - } - - $html .= self::createImageTag($imageUrl, $imgAttributes); - } - } - - // Finaliser le dernier bloc si nécessaire - if (!empty($currentBlock['content'])) { - $html .= self::renderBlock($currentBlock); - } - - return $html; - } - - private static function renderBlock($block) { - if (empty($block['content'])) return ''; - - $tag = 'p'; - $styles = []; - $classes = []; - - // Déterminer le tag et attributs de base - if (!empty($block['attrs']['header'])) { - $tag = 'h' . $block['attrs']['header']; - } elseif (!empty($block['attrs']['blockquote'])) { - $tag = 'blockquote'; - } elseif (!empty($block['attrs']['code-block'])) { - $tag = 'pre'; - $classes[] = 'code-block'; - } - - // Appliquer l'alignement au niveau du bloc - if (!empty($block['attrs']['text-align'])) { - $styles[] = "text-align: " . $block['attrs']['text-align'] . " !important"; - } - - // Construire le contenu avec les attributs inline - $content = $block['content']; - if (!empty($block['inlineAttrs'])) { - // Trier les attributs par position de fin pour les appliquer de la fin vers le début - usort($block['inlineAttrs'], function($a, $b) { - return ($a['start'] + $a['length']) - ($b['start'] + $b['length']); - }); - - // Appliquer les attributs inline - foreach (array_reverse($block['inlineAttrs']) as $attr) { - $start = $attr['start']; - $length = $attr['length']; - $segment = mb_substr($content, $start, $length); - - if (!empty($attr['attrs'])) { - $segment = self::applyInlineAttributes($segment, $attr['attrs']); - } - - $content = mb_substr($content, 0, $start) . $segment . mb_substr($content, $start + $length); - } - } - - // Si c'est un bloc de code, wrapper dans code - if ($tag === 'pre') { - $content = "$content"; - } - - // Construire les attributs HTML finaux - $attributes = ''; - if (!empty($styles)) { - $attributes .= ' style="' . implode('; ', array_unique($styles)) . '"'; - } - if (!empty($classes)) { - $attributes .= ' class="' . implode(' ', array_unique($classes)) . '"'; - } - - return "<$tag$attributes>$content"; - } - - private static function applyInlineAttributes($text, $attrs) { - $text = htmlspecialchars($text); - - if (!empty($attrs['bold'])) { - $text = "$text"; - } - if (!empty($attrs['italic'])) { - $text = "$text"; - } - if (!empty($attrs['underline'])) { - $text = "$text"; - } - if (!empty($attrs['strike'])) { - $text = "$text"; - } - if (!empty($attrs['color'])) { - $text = "$text"; - } - if (!empty($attrs['background'])) { - $text = "$text"; - } - if (!empty($attrs['link'])) { - $text = "$text"; - } - if (!empty($attrs['font'])) { - switch($attrs['font']) { - case 'serif': - $text = "$text"; - break; - case 'monospace': - $text = "$text"; - break; - case 'sans-serif': - $text = "$text"; - break; - } - } - if (!empty($attrs['script'])) { - if ($attrs['script'] === 'super') $text = "$text"; - if ($attrs['script'] === 'sub') $text = "$text"; - } - - return $text; - } - - private static function isJson($string) { - json_decode($string); - return json_last_error() === JSON_ERROR_NONE; - } - - private static function cleanImageUrl($url) { - return preg_replace('/^(?:\.\.\/)+/', '', $url); - } - - private static function cleanImageUrls($html) { - return preg_replace_callback( - '/]+src=([\'"])((?:\.\.\/)*(?:assets\/[^"\']+))\1[^>]*>/', - function($matches) { - $cleanUrl = self::cleanImageUrl($matches[2]); - return str_replace($matches[2], $cleanUrl, $matches[0]); - }, - $html - ); - } - - private static function createImageTag($src, $attributes) { - $html = ' $value) { - $html .= ' ' . $key . '="' . htmlspecialchars($value) . '"'; - } - $html .= '>'; - return $html; - } -} \ No newline at end of file diff --git a/version.txt b/version.txt index 8428158..9c1218c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.1.2 \ No newline at end of file +1.1.3 \ No newline at end of file