لقد أنشأت bookmarklet لإنشاء جدول المحتويات لمنشورات المنتدى

جدول المحتويات:

لقد أنشأت أداة إشارات مرجعية لإنشاء جدول محتويات قابل للطي (ToC) مثل الذي يظهر أعلاه.
آمل أن يساعد أعضاء المجتمع المتحمسين الذين يكتبون نصوصًا طويلة!

ملخص

أحيانًا أكتب مواضيع/منشورات طويلة وأحتاج إلى جدول محتويات لتسهيل القراءة.
لقد وجدت بعض الأعمال الموجودة، مثل https://meta.discourse.org/t/discotoc-automatic-table-of-contents/111143، لكنني كنت بحاجة إلى أداة لي وحدي، لا تتطلب تثبيت شيء عبر المجتمع.

بعد نشر منشور منظم، انقر على الأداة المرجعية، وسيتم نسخ جدول المحتويات إلى الحافظة الخاصة بك. قم بتحرير المنشور والصق جدول المحتويات في الأعلى!

كيفية الاستخدام

التثبيت

  1. احفظ صفحة كإشارة مرجعية.
  2. قم بتحرير الاسم، مثل “:clipboard: نسخ جدول محتويات المنتدى إلى الحافظة.”
  3. قم بتحرير عنوان URL والصق الكود التالي. قم بتخصيص الكود إذا لزم الأمر - انظر بندين “اختياري” أدناه.
javascript:(function() {
	const copyForumTocToClipboard = function() {
		const urlMatch = window.location.href.match(/\/t\/[^\/]*\/\d+\/?(\d*)/);
		if (!urlMatch) return;

		const postIndex = urlMatch ? urlMatch[1] : 1;
		const anchors = document.querySelectorAll('#post_' + postIndex + ' div.cooked h6 a.anchor,h5 a.anchor,h4 a.anchor,h3 a.anchor,h2 a.anchor,h1 a.anchor');
		if (!anchors) return;

		let toc = '';
		anchors.forEach(anchor => {
			toc +=
				' '.repeat((anchor.parentNode.nodeName[1] - 1) * 4) +
				`<a href="${anchor.href}">${anchor.parentNode.textContent}</a><br>\n`;
		});
		if (!toc) return;

		navigator.clipboard.writeText('<details open><summary>Table of contents: </summary><ul>\n' + toc + '</ul></details>');
	};

	copyForumTocToClipboard();
})();

ماذا يفعل الكود

  1. تحقق مما إذا كان عنوان URL يبدو كمنشور مجتمعي: https://{domain}/t/{title}/{topicID}(/{postIndex}).
  2. تحقق مما إذا كانت الروابط الثابتة (العناوين مثل <h1> و # ) مضمنة في المنشور.
  3. إنشاء كود HTML لجدول المحتويات.
  4. نسخ الكود إلى الحافظة.

إنشاء جدول المحتويات

  1. انشر منشورًا به هيكل (HTML <h1>، <h2>، … و Markdown # ، ## ، …). سيقوم Discourse بتعيين روابط ثابتة لكل عنوان.
  2. تأكد من تحديد المنشور الخاص بك من خلال النظر إلى شريط التقدم (على سبيل المثال، 1/22) أو عنوان URL (على سبيل المثال، /1).
  3. انقر على الأداة المرجعية في شريط الإشارات المرجعية.
  4. يتم نسخ جدول المحتويات إلى الحافظة الخاصة بك.

استخدام جدول المحتويات

  1. انقر على أيقونة القلم لتعديل المنشور.
  2. الصق الكود في الأعلى.
  3. تحقق مما إذا كانت عناصر جدول المحتويات معروضة بشكل صحيح (مشكلة معروفة: الأداة المرجعية تفوت بعض الرموز التعبيرية).
  4. (اختياري) قم بتغيير/ترجمة “جدول المحتويات”.
  5. (اختياري) احذف open إذا كنت تريد طي جدول المحتويات افتراضيًا.
  6. انقر على “حفظ التعديل”. إذا قمت بذلك في غضون دقائق قليلة بعد نشر المنشور، فلن تتم إضافة أيقونة القلم “تم التعديل” إلى منشورك.

ملاحظات فنية للمهتمين

  • يمكنك أيضًا نسخ ولصق كود JavaScript في وحدة تحكم المطور.
    • لقد قمت بتغليف الكود في دالة لأن return; لا يعمل عند استخدامه خارج الدوال.
  • يبدو نهج '\u0026nbsp;'.repeat() فوضويًا عند معاينة الموضوع، ولكنه يبدو الأفضل في المنشور الفعلي (مقارنة باستخدام <li></li>) في رأيي.
  • عندما اختبرت querySelectorAll، بطريقة ما لم يتم العثور على العنصر الأول في h6 a.anchor,h5 a.anchor, .... وضعت h6 في البداية لأنها ربما تستخدم بأقل تكرار.
  • قد تتوقف الأداة المرجعية عن العمل إذا قام Discourse بتغيير واجهته/نموذج كائن المستند الخاص به. يرجى الرد علي إذا وجدت أخطاء.

لقطات شاشة

كمستخدم جديد في meta.discourse.org، لا يمكنني إضافة صور متعددة، لذلك أقوم بتجميع جميع لقطات الشاشة في صورة واحدة:

18 إعجابًا

رائع - هل يمكن توسيع ذلك لإنشاء جدول محتويات للمنشور بأكمله مع جميع الردود؟

3 إعجابات

يتم تحميل المشاركات بشكل عام حوالي 20 في كل مرة، وأعتقد أنه سيكون من الصعب إنشاء جدول محتويات لجميع المشاركات دفعة واحدة

4 إعجابات

رائع جداً! شكراً على المشاركة @ShunS!

أحببت الطريقة التي عرضت بها المشكلة التي تحلها بهذه الأداة، وكيف تم تصميمها لتلبية احتياجات المستخدمين المهمين في المواقع الذين قد لا يمتلكون صلاحيات لتغيير الأشياء في الموقع نفسه كما هي اليوم.

10 إعجابات

شكراً على الردود :slight_smile:

كما يقول @Lhc_fl، فإن نهج DOM (HTML/JavaScript) محدود في عدد العناصر التي يمكننا إدارتها. قد تساعد واجهة برمجة تطبيقات Discourse في مثل هذه الإجراءات.
مشكلة أخرى في إنشاء جدول المحتويات للردود هي أنه ليس من السهل تحديد عنوان العنوان لكل رد. يمكننا استخدام معلومات مثل المؤلف والتاريخ، لكنني لست متأكدًا من مدى فائدتها مقارنة بشريط تقدم التمرير الحالي.

شكراً @mcwumbly!

6 إعجابات

@ShunS هذا رائع جداً، شكراً لك على المشاركة. أهلاً بك في ميتا أيضاً :wave: :slight_smile:

5 إعجابات

هذا رائع وهو بالضبط ما كنت أبحث عنه. يبدو أنه يحل هذه المشكلة

لماذا لا تقدم هذا إلى Discourse لتضمينه كمكون إضافي رسمي أو ميزة؟ يمكن تضمينه في شريط أدوات المنشئ/المحرر لإدراج جدول محتويات تلقائيًا في المنشور.

6 إعجابات

لدي اقتراح واحد، هل من الممكن إضافة نقطة في بداية سطر جدول المحتويات؟ في حالتي، كل عنوان هو سطر طويل، لذا تساعد النقطة في التمييز بين إدخال وآخر.

إعجاب واحد (1)

مرحباً @RBoy، شكراً على الملاحظات والاقتراح!

ستكون إضافة لمحرر رائعة، ولكن سيتطلب الأمر الكثير من الجهد لقراءة الكود المصدري لـ discourse لفهم منطق التعامل مع الرموز التعبيرية وتحديد نص العنوان/المرساة وإنشاء مستودع للإضافة.

إضافة (تبدو) بسيطة مثل Spoiler Alert هي مستودع كبير وليس لدي وقت كافٍ للالتزام الكامل بالتطوير. لذا، آمل أن يعطي Discourse الأولوية لطلبات الميزات مثل Automatic Table of Contents generation ويطور ميزة أصلية في هذه الأثناء :folded_hands:


أدناه الإصدار مع النقاط. المسافات بين <ul> و </ul> كبيرة جدًا، لذا فضلت الإصدار الأصلي غير المنقط.

لقطة شاشة:

الكود:

javascript:(function() {
	const copyForumTocToClipboard = function() {
		const urlMatch = window.location.href.match(/\/t\/[^\\/]*\/\d+\/?(\d*)/);
		if (!urlMatch) return;

		const postIndex = 1;
		const anchors = document.querySelectorAll('#post_' + postIndex + ' div.cooked h6 a.anchor,h5 a.anchor,h4 a.anchor,h3 a.anchor,h2 a.anchor,h1 a.anchor');

		let toc = '';
		let currentLevel = 1;
		anchors.forEach(anchor => {
			newLevel = anchor.parentNode.nodeName[1];
			levelChange = newLevel - currentLevel;
			toc +=
				((levelChange >= 0) ? '<ul>'.repeat(levelChange) : '</ul>'.repeat(levelChange * -1)) +
				`<li><a href="${anchor.href}">${anchor.parentNode.textContent}</a></li>`;
			currentLevel = newLevel;
		});
		if (newLevel > 1) toc += '</ul>'.repeat(newLevel - 1);
		toc = '<details open><summary>Table of contents: </summary><ul>\n' + toc + '</ul></details>';

		navigator.clipboard.writeText(toc);
	};

	copyForumTocToClipboard();
})();
5 إعجابات

لدينا بالفعل ملحق ToC ولا يحتاج إلى صيانة ToC في جسم المنشور.

أوصي بالتأكيد بهذا الملحق إذا تم تثبيته لأنه لا يمكن أن يخرج عن التزامن.

تبدو هذه الأداة رائعة عندما لا يكون DiscoToC متاحًا. عمل جيد! :+1:

4 إعجابات

يمكن القيام بذلك باستخدام مكون سمة. يمكنك إلقاء نظرة على طريقة decorateCookedElement الخاصة بـ api، يجب أن تكون مفيدة.

4 إعجابات

مرحباً @supermathie، شكراً على الرد.

عندما لا يكون DiscoToC متاحاً
نعم، هذا هو التمييز. لقد أنشأت الـ bookmarklet لأنني لست في وضع يسمح لي بتحديد “مكون السمة” الذي يجب تثبيته في المنتدى الذي أتواجد فيه عادةً، وقليلون فقط هم من يكتبون نصوصاً طويلة تحتاج إلى جدول محتويات.


شكراً @Lhc_fl، هذا مفيد جداً!

لقد بحثت في مستودع GitHub ووجدت هذه الطريقة. سأفكر في تطويرها (فقط) عندما يكون لدي وقت فراغ كافٍ وأرى طلباً كبيراً على الميزة.

ومع ذلك، إذا كان يمكن إضافة مكون سمة إلى المجتمع، فهناك بالفعل DiscoTOC كما قال @supermathie :slight_smile:

4 إعجابات

للأسف، هذا المكون الإضافي غير قابل للاستخدام تمامًا عندما يكون العنوان أطول من بضع كلمات، لأنه يحدث فوضى كاملة في الأمور. إذا كانت العناوين عبارة عن سطر أو سطرين (على سبيل المثال، صفحة الأسئلة الشائعة)، فإن المكون الإضافي Disco TOC يُحدث فوضى كاملة في الصفحة، وهذا هو سبب طرحي لهذا الطلب لجدول محتويات مضمن (والذي يوفره هذا) وهو مثالي لمثل هذه الصفحات

مع كمية العبقرية/الموهبة بين الفرق التي تبني Discourse، لا ينبغي أن يكون من الصعب جدًا تضمين هذه الميزة المذهلة كبديل لـ DiscoTOC لمنحها نطاقًا أوسع بكثير من الاستخدام.