- إصدار الزين فورو
- XenForo 2.x
مرحبا اصدقائي، اعضاء وزوار منتديات شباب الرافدين.
فكرة الدرس العملي اليوم: إضافة زر “إزالة الروابط من النص” داخل محرر XenForo 2.3.7
(لماذا نحتاج هذه الإضافة؟)
كثير من المستخدمين عند كتابة موضوع في المنتدى يقومون بلصق محتوى من مواقع أو مقالات، فيتم لصق النص مع روابط مدمجة تلقائيًا داخل الكلمات (Anchored Links)، وهذا يسبب مشاكل مثل:
1) المتطلبات الأساسية
قبل البدء تأكد أنك تعمل على:
سنقوم بعمل 3 أشياء:
(1) إنشاء ملف JavaScript مخصص يقوم بـ:
تسجيل أمر جديد داخل Froala باسم: axUnlinkAll
إضافة زر داخل Toolbar تلقائيًا بجانب زر unlink
(2) حقن تحميل الملف داخل قالب المحرر editor عبر Template Modification
(3) (اختياري) تصغير حجم أيقونة الزر عبر extra.less
3) إنشاء ملف JavaScript للزر
3.1 أنشئ ملف جديد داخل مجلد js
على السيرفر ضع الملف هنا:
3.2 الصق هذا الكود داخل الملف (كما هو)
هذا الكود لا يعتمد على jQuery نهائيًا، ويعمل حتى لو ترتيب التحميل تغيّر.
شرح سريع لما يفعل الكود:
هنا كثير يتعثرون:
وجود الملف وحده لا يكفي… لازم XenForo “يحمّله” داخل قالب المحرر.
4.1 أنشئ Template Modification
تفعيل إعدادات وضع التطوير للمبرمجين - Development Enabled
بعدها اذهب إلى:
ACP → Appearance → Template modifications → Add template modification
ضع التالي:
Template modification type: Public
Template: editor
Modification key:
axvoid_unlinkall_button
Search type: Simple replacement
Find
انسخ هذا كما هو:
Replace
ضع هذا:
ثم اضغط Test ثم Save.
5) تصغير حجم الأيقونة (اختياري لكنه جميل)
إذا كانت الأيقونة أكبر من بقية الأزرار، نضبطها عبر CSS.
اذهب إلى:
ACP → Appearance → Templates → extra.less
وأضف:
لو تريد أصغر:
6) اختبار تشغيل الزر (مهم جدًا)
بعد تنفيذ كل شيء:
افتح “موضوع جديد”
الصق نص فيه روابط
لاحظ ظهور زر جديد بجانب unlink
جرّب حالتين:
حالة 1: تحديد كلمة داخل رابط
اضغط الزر → ينفك الرابط فقط عن هذا الجزء
حالة 2: بدون تحديد شيء
اضغط الزر → يظهر تأكيد
ثم يحذف كل الروابط من النص
7) حل المشاكل الشائعة (Troubleshooting)
المشكلة A: الزر لا يظهر نهائيًا
الحل:
افتح صفحة كتابة موضوع
View Page Source
ابحث عن:
unlink_all_v3.js
إن لم يكن موجودًا → Template Modification لم يُطبق.
المشكلة B: ظهور خطأ “jQuery is not defined”
السبب:
بعض الأكواد القديمة تكون مكتوبة بصيغة:
وهذا يسبب انهيار الملف إن لم تكن jQuery محمّلة وقت التنفيذ.
الحل النهائي:
استخدم ملفنا الحالي لأنه لا يعتمد على jQuery نهائيًا.
المشكلة C: تغييرات لا تظهر بسبب الكاش
الحل:
Hard Refresh:
Mac: Cmd + Shift + R
Windows: Ctrl + Shift + R
وإذا تستخدم Cloudflare:
Purge Cache
خاتمة الدرس
بهذا أنت أضفت ميزة احترافية داخل محرر XenForo 2.3.7:
✅ زر “إزالة الروابط” يعمل بسرعة
✅ بدون التأثير على النص
✅ وبدون اعتماد على إضافات خارجية أو BB Code hacks
والأجمل أنه “حل نظيف” لأننا أضفناه كأمر محرر (Editor Command) مع زر داخل شريط الأدوات.
جربوها وستنجح معكم بكل تاكيد ان شاء الله.
تحيتي
فكرة الدرس العملي اليوم: إضافة زر “إزالة الروابط من النص” داخل محرر XenForo 2.3.7
(لماذا نحتاج هذه الإضافة؟)
كثير من المستخدمين عند كتابة موضوع في المنتدى يقومون بلصق محتوى من مواقع أو مقالات، فيتم لصق النص مع روابط مدمجة تلقائيًا داخل الكلمات (Anchored Links)، وهذا يسبب مشاكل مثل:
- تشويه تنسيق الموضوع
- نشر روابط غير مرغوبة أو دعائية
- ضعف جودة المحتوى من منظور التحرير والسيو
- روابط تتبع Tracking مزعجة (utm / fbclid ..)
✅ الحل: زر داخل المحرر يقوم بضغطة واحدة بـ: فك الرابط عن الكلمة/الجملة المحددة أو إزالة كل الروابط من الموضوع بالكامل مع الحفاظ على النص.
1) المتطلبات الأساسية
قبل البدء تأكد أنك تعمل على:
- XenForo 2.3.7
- المحرر الافتراضي (Froala Editor) مفعّل
- لديك صلاحية رفع ملفات إلى السيرفر (FTP أو File Manager)
سنقوم بعمل 3 أشياء:
(1) إنشاء ملف JavaScript مخصص يقوم بـ:
تسجيل أمر جديد داخل Froala باسم: axUnlinkAll
إضافة زر داخل Toolbar تلقائيًا بجانب زر unlink
(2) حقن تحميل الملف داخل قالب المحرر editor عبر Template Modification
(3) (اختياري) تصغير حجم أيقونة الزر عبر extra.less
3) إنشاء ملف JavaScript للزر
3.1 أنشئ ملف جديد داخل مجلد js
على السيرفر ضع الملف هنا:
CSS:
/js/axvoid/unlink_all_v3.js
إذا مجلد axvoid غير موجود… أنشئه داخل مجلد js
3.2 الصق هذا الكود داخل الملف (كما هو)
هذا الكود لا يعتمد على jQuery نهائيًا، ويعمل حتى لو ترتيب التحميل تغيّر.
JavaScript:
(function (window, document) {
"use strict";
var CMD = "axUnlinkAll";
var REGISTERED = false;
// 1) سجل الأمر عند توفر Froala
function registerCommand() {
if (REGISTERED) return;
if (!window.FroalaEditor) {
return setTimeout(registerCommand, 50);
}
var FE = window.FroalaEditor;
try {
FE.DefineIcon(CMD, { NAME: "unlink", SVG_KEY: "unlink" });
} catch (e) {}
FE.RegisterCommand(CMD, {
title: "إزالة الروابط من النص",
focus: true,
undo: true,
showOnMobile: true,
refreshAfterCallback: true,
callback: function () {
var editor = this;
editor.undo.saveStep();
// إذا المؤشر داخل رابط: فك الرابط فقط
var el = editor.selection.element();
var insideLink = el ? el.closest("a[href]") : null;
if (insideLink) {
editor.commands.exec("unlink");
editor.undo.saveStep();
editor.events.focus();
return;
}
// إذا بدون تحديد: إزالة كل الروابط
var root = editor.el;
var links = root.querySelectorAll("a[href]");
if (!links.length) {
alert("لا توجد روابط لإزالتها داخل النص.");
return;
}
if (!window.confirm("سيتم إزالة جميع الروابط من النص (ستبقى الكلمات كما هي). هل تريد المتابعة؟")) {
return;
}
links.forEach(function (a) {
// تجنب روابط الصور/الملفات
if (a.querySelector("img") || a.closest(".fr-file")) return;
var parent = a.parentNode;
while (a.firstChild) {
parent.insertBefore(a.firstChild, a);
}
parent.removeChild(a);
});
editor.events.trigger("contentChanged");
editor.undo.saveStep();
editor.events.focus();
}
});
REGISTERED = true;
console.log("[Axvoid] Command registered ✅");
}
// 2) حقن زر داخل أي Toolbar يظهر
function injectButton(toolbar) {
if (!toolbar || toolbar.querySelector('button[data-cmd="' + CMD + '"]')) return;
var unlinkBtn = toolbar.querySelector('button[data-cmd="unlink"]');
var targetGroup = unlinkBtn ? unlinkBtn.closest(".fr-btn-grp") : toolbar.querySelector(".fr-btn-grp");
if (!targetGroup) return;
var btn = document.createElement("button");
btn.type = "button";
btn.className = "fr-command fr-btn";
btn.setAttribute("data-cmd", CMD);
btn.setAttribute("title", "إزالة الروابط من النص");
btn.setAttribute("aria-label", "إزالة الروابط من النص");
// ✅ أيقونة صحيحة 100%: انسخ SVG الحقيقي من زر unlink
var svg = unlinkBtn ? unlinkBtn.querySelector("svg") : null;
if (svg) {
var svgClone = svg.cloneNode(true);
svgClone.style.width = "16px";
svgClone.style.height = "16px";
// تأكيد وجود الكلاس الذي يستخدمه Froala لتنسيق الأيقونات
if (!svgClone.classList.contains("fr-svg")) {
svgClone.classList.add("fr-svg");
}
btn.textContent = ""; // مهم: نمسح أي نص داخل الزر
btn.appendChild(svgClone); // نضيف الـ SVG النظيف فقط
} else {
// fallback لو زر unlink غير موجود لأي سبب
btn.innerHTML =
'<svg class="fr-svg" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">' +
'<path d="M10.59 13.41a1.996 1.996 0 0 1 0-2.82l2.12-2.12a2 2 0 1 1 2.83 2.83l-.88.88" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>' +
'<path d="M13.41 10.59a1.996 1.996 0 0 1 0 2.82l-2.12 2.12a2 2 0 1 1-2.83-2.83l.88-.88" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>' +
'<path d="M3 3l18 18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>' +
"</svg>";
}
// ضع الزر بعد unlink
if (unlinkBtn && unlinkBtn.parentNode === targetGroup) {
unlinkBtn.insertAdjacentElement("afterend", btn);
} else {
targetGroup.appendChild(btn);
}
console.log("[Axvoid] Button injected ✅");
}
// 3) راقب الصفحة: كلما ظهر Toolbar جديد احقنه
function watchToolbars() {
// حقن سريع لأول مرة
document.querySelectorAll(".fr-toolbar").forEach(injectButton);
var obs = new MutationObserver(function (mutations) {
mutations.forEach(function (m) {
m.addedNodes.forEach(function (node) {
if (!(node instanceof HTMLElement)) return;
// إذا العقدة نفسها Toolbar
if (node.matches && node.matches(".fr-toolbar")) {
injectButton(node);
}
// أو بداخلها Toolbar
var toolbars = node.querySelectorAll ? node.querySelectorAll(".fr-toolbar") : [];
toolbars.forEach(injectButton);
});
});
});
obs.observe(document.documentElement, { childList: true, subtree: true });
}
// تشغيل
registerCommand();
watchToolbars();
})(window, document);
شرح سريع لما يفعل الكود:
- يسجل أمر Froala جديد اسمه axUnlinkAll
- إذا كان المؤشر داخل رابط → يعمل Unlink للكلمة/الجزء فقط
- إذا لم يكن هناك تحديد → يحذف كل <a href> ويترك النص
- يراقب الصفحة ويضيف الزر تلقائيًا عند ظهور شريط الأدوات
هنا كثير يتعثرون:
وجود الملف وحده لا يكفي… لازم XenForo “يحمّله” داخل قالب المحرر.
4.1 أنشئ Template Modification
لاظهار زر اضافة تامبلت جديد، يجب اضافة الكود التالي داخل ملف config
تفعيل إعدادات وضع التطوير للمبرمجين - Development Enabled
PHP:
$config['development']['enabled'] = true;
بعدها اذهب إلى:
ACP → Appearance → Template modifications → Add template modification
ضع التالي:
Template modification type: Public
Template: editor
Modification key:
axvoid_unlinkall_button
Search type: Simple replacement
Find
انسخ هذا كما هو:
كود:
<!--[XF:include_js]-->
Replace
ضع هذا:
كود:
<!--[XF:include_js]-->
<xf:js src="axvoid/unlink_all_v3.js" />
ثم اضغط Test ثم Save.
احذف الكود الذي اضفناه في ملف config بعد الانتهاء من اضافة التامبلت.
5) تصغير حجم الأيقونة (اختياري لكنه جميل)
إذا كانت الأيقونة أكبر من بقية الأزرار، نضبطها عبر CSS.
اذهب إلى:
ACP → Appearance → Templates → extra.less
وأضف:
CSS:
/* تصغير أيقونة زر إزالة الروابط */
.fr-box .fr-toolbar .fr-command[data-cmd="axUnlinkAll"] svg.fr-svg
{
width: 16px !important;
height: 16px !important;
}
لو تريد أصغر:
CSS:
width: 14px !important;
height: 14px !important;
6) اختبار تشغيل الزر (مهم جدًا)
بعد تنفيذ كل شيء:
افتح “موضوع جديد”
الصق نص فيه روابط
لاحظ ظهور زر جديد بجانب unlink
جرّب حالتين:
حالة 1: تحديد كلمة داخل رابط
اضغط الزر → ينفك الرابط فقط عن هذا الجزء
حالة 2: بدون تحديد شيء
اضغط الزر → يظهر تأكيد
ثم يحذف كل الروابط من النص
7) حل المشاكل الشائعة (Troubleshooting)
المشكلة A: الزر لا يظهر نهائيًا
الحل:
افتح صفحة كتابة موضوع
View Page Source
ابحث عن:
unlink_all_v3.js
إن لم يكن موجودًا → Template Modification لم يُطبق.
المشكلة B: ظهور خطأ “jQuery is not defined”
السبب:
بعض الأكواد القديمة تكون مكتوبة بصيغة:
JavaScript:
})(jQuery, window, document);
الحل النهائي:
استخدم ملفنا الحالي لأنه لا يعتمد على jQuery نهائيًا.
المشكلة C: تغييرات لا تظهر بسبب الكاش
الحل:
Hard Refresh:
Mac: Cmd + Shift + R
Windows: Ctrl + Shift + R
وإذا تستخدم Cloudflare:
Purge Cache
خاتمة الدرس
بهذا أنت أضفت ميزة احترافية داخل محرر XenForo 2.3.7:
✅ زر “إزالة الروابط” يعمل بسرعة
✅ بدون التأثير على النص
✅ وبدون اعتماد على إضافات خارجية أو BB Code hacks
والأجمل أنه “حل نظيف” لأننا أضفناه كأمر محرر (Editor Command) مع زر داخل شريط الأدوات.
جربوها وستنجح معكم بكل تاكيد ان شاء الله.
تحيتي




