diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php
index 48babdb..6e1e603 100644
--- a/app/Helpers/Helper.php
+++ b/app/Helpers/Helper.php
@@ -1271,3 +1271,98 @@ function sendingSMS($text, $number, $args)
return true;
}
+
+/**
+ * table of content generator
+ * @param $html
+ * @return array
+ */
+function generateTOC($html) {
+ // Load HTML into a DOMDocument for parsing
+ $doc = new DOMDocument();
+ @$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
+
+ $toc = '';
+ $tocItems = [];
+ $lastH2 = '';
+ $lastH3 = '';
+ $idCounter = 0;
+
+ // Fetch all headings in the document
+ $headings = $doc->getElementsByTagName('*');
+
+ foreach ($headings as $heading) {
+ if (in_array($heading->nodeName, ['h2', 'h3'])) {
+ // Generate a unique ID for each heading
+ $id = generateHeadingID($heading->nodeValue, $idCounter);
+ $idCounter++;
+ $heading->setAttribute('id', $id);
+
+ if ($heading->nodeName === 'h2') {
+ $tocItems[] = [
+ 'title' => $heading->nodeValue,
+ 'id' => $id,
+ 'children' => []
+ ];
+ $lastH2 = $heading->nodeValue; // Update last H2 title
+ $lastH3 = ''; // Reset last H3
+ } elseif ($heading->nodeName === 'h3') {
+ if ($lastH2) {
+ // Create a new child entry for the last H2
+ $tocItems[count($tocItems) - 1]['children'][] = [
+ 'title' => $heading->nodeValue,
+ 'id' => $id,
+ ];
+ $lastH3 = $heading->nodeValue; // Update last H3 title
+ }
+ }
+ }
+ }
+
+ // Create the TOC HTML
+ $toc .= buildTOC($tocItems);
+
+ // Return the modified HTML and the TOC
+ return [$toc, $doc->saveHTML()];
+}
+
+/**
+ * generate heading ID for table of content
+ * @param $text
+ * @param $counter
+ * @return string
+ */
+function generateHeadingID($text, $counter) {
+ // Convert to lowercase and replace non-alphanumeric characters with dashes
+ $id = strtolower(preg_replace('/[^a-zA-Z0-9]+/', '-', $text));
+
+ // Remove leading and trailing dashes
+ $id = trim($id, '-');
+
+ // Ensure the ID is not empty
+ if (empty($id)) {
+ $id = 'heading';
+ }
+
+ // Add the counter to ensure uniqueness
+ $id .= '-' . $counter;
+
+ return $id;
+}
+
+// The buildTOC function remains unchanged
+function buildTOC($items) {
+ $html = '
';
+ foreach ($items as $item) {
+ $html .= '- ';
+ $html .= '' . $item['title'] . '';
+
+ if (!empty($item['children'])) {
+ $html .= buildTOC($item['children']);
+ }
+
+ $html .= '
';
+ }
+ $html .= '
';
+ return $html;
+}
diff --git a/app/Http/Controllers/Admin/PostController.php b/app/Http/Controllers/Admin/PostController.php
index 735f459..8de63b4 100644
--- a/app/Http/Controllers/Admin/PostController.php
+++ b/app/Http/Controllers/Admin/PostController.php
@@ -58,6 +58,7 @@ class PostController extends XController
$post->group_id = $request->input('group_id');
$post->user_id = auth()->id();
$post->is_pinned = $request->has('is_pin');
+ $post->table_of_contents = $request->has('table_of_contents');
$post->icon = $request->input('icon');
if ($post->hash == null) {
diff --git a/app/Models/Post.php b/app/Models/Post.php
index ff7713e..d646db6 100644
--- a/app/Models/Post.php
+++ b/app/Models/Post.php
@@ -196,4 +196,14 @@ RESULT;
return implode(',', $this->tags()->pluck('name')->toArray());
}
}
+
+ public function tableOfContents(){
+ list($toc, $modifiedHtml) = generateTOC($this->body);
+ return $toc;
+ }
+
+ public function bodyContent(){
+ list($toc, $modifiedHtml) = generateTOC($this->body);
+ return $modifiedHtml;
+ }
}
diff --git a/composer.json b/composer.json
index 486ef42..97158d9 100644
--- a/composer.json
+++ b/composer.json
@@ -6,6 +6,7 @@
"license": "GPL-3.0-or-later",
"require": {
"php": "^8.2",
+ "ext-dom": "*",
"carlos-meneses/laravel-mpdf": "^2.1",
"chillerlan/php-qrcode": "^5.0",
"dpsoft/mellat": "^1.1",
diff --git a/database/migrations/2024_05_07_123414_create_posts_table.php b/database/migrations/2024_05_07_123414_create_posts_table.php
index 48dd4f7..1a0a69b 100644
--- a/database/migrations/2024_05_07_123414_create_posts_table.php
+++ b/database/migrations/2024_05_07_123414_create_posts_table.php
@@ -26,6 +26,7 @@ return new class extends Migration
$table->unsignedInteger('like')->default(0);
$table->unsignedInteger('dislike')->default(0);
$table->string('icon', 128)->nullable();
+ $table->boolean('table_of_contents')->default(0);
$table->softDeletes();
$table->timestamps();
diff --git a/resources/lang/fa.json b/resources/lang/fa.json
index 6b6aa0f..4d22cd7 100644
--- a/resources/lang/fa.json
+++ b/resources/lang/fa.json
@@ -418,6 +418,7 @@
"Successfully Invoices": "",
"Summary": "خلاصه",
"System notification": "پیام سیستم",
+ "Table of contents": "فهرست عناوین",
"Tag": "برچسب",
"Tags": "برچسبها",
"Tags list": "فهرست برچسبها",
diff --git a/resources/views/admin/posts/post-form.blade.php b/resources/views/admin/posts/post-form.blade.php
index 224cf9d..7f5b0c3 100644
--- a/resources/views/admin/posts/post-form.blade.php
+++ b/resources/views/admin/posts/post-form.blade.php
@@ -103,13 +103,23 @@
placeholder="{{__('Title')}}" value="{{old('title',$item->title??null)}}"/>
-
+
+
- {!! $post->body !!}
+ @if($post->table_of_contents)
+ {!! $post->tableOfContents() !!}
+ {!! $post->bodyContent() !!}
+ @else
+
+ {!! $post->body !!}
+ @endif
+
diff --git a/resources/views/segments/post/SimplePost/SimplePost.blade.php b/resources/views/segments/post/SimplePost/SimplePost.blade.php
index 126e32e..da459c5 100644
--- a/resources/views/segments/post/SimplePost/SimplePost.blade.php
+++ b/resources/views/segments/post/SimplePost/SimplePost.blade.php
@@ -37,7 +37,13 @@
@endif
- {!! $post->body !!}
+ @if($post->table_of_contents)
+ {!! $post->tableOfContents() !!}
+ {!! $post->bodyContent() !!}
+ @else
+
+ {!! $post->body !!}
+ @endif