• منتديات شباب الرافدين .. تجمع عراقي يقدم محتوى مميز لجميع طلبة وشباب العراق .. لذا ندعوكم للانضمام الى اسرتنا والمشاركة والدعم وتبادل الافكار والرؤى والمعلومات. فأهلاَ وسهلاَ بكم.
إضافة زر “إزالة الروابط من النص” داخل محرر XenForo 2.3.7

درس XF-2.x إضافة زر “إزالة الروابط من النص” داخل محرر XenForo 2.3.7

Ibn AliraQ

ヅ واحد من الناس ヅ
السمعة: 100%
النقاط 297
الحلول 0
إنضم
2018-08-28
المشاركات
17,579
مستوى التفاعل
6,943
النقاط
297
الإقامة
العراق
Ibn AliraQ
إصدار الزين فورو
XenForo 2.x
مرحبا اصدقائي، اعضاء وزوار منتديات شباب الرافدين.
فكرة الدرس العملي اليوم: إضافة زر “إزالة الروابط من النص” داخل محرر XenForo 2.3.7

(لماذا نحتاج هذه الإضافة؟)
كثير من المستخدمين عند كتابة موضوع في المنتدى يقومون بلصق محتوى من مواقع أو مقالات، فيتم لصق النص مع روابط مدمجة تلقائيًا داخل الكلمات (Anchored Links)، وهذا يسبب مشاكل مثل:
  • تشويه تنسيق الموضوع
  • نشر روابط غير مرغوبة أو دعائية
  • ضعف جودة المحتوى من منظور التحرير والسيو
  • روابط تتبع Tracking مزعجة (utm / fbclid ..)
✅ الحل: زر داخل المحرر يقوم بضغطة واحدة بـ: فك الرابط عن الكلمة/الجملة المحددة أو إزالة كل الروابط من الموضوع بالكامل مع الحفاظ على النص.


إضافة زر “إزالة الروابط من النص” داخل محرر XenForo 2.3.7.png

1) المتطلبات الأساسية
قبل البدء تأكد أنك تعمل على:
  • XenForo 2.3.7
  • المحرر الافتراضي (Froala Editor) مفعّل
  • لديك صلاحية رفع ملفات إلى السيرفر (FTP أو File Manager)
2) ماذا سنبني بالضبط؟
سنقوم بعمل 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 نهائيًا، ويعمل حتى لو ترتيب التحميل تغيّر.

unlink_all_v3.js.png

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);

شرح سريع لما يفعل الكود:
  1. يسجل أمر Froala جديد اسمه axUnlinkAll
  2. إذا كان المؤشر داخل رابط → يعمل Unlink للكلمة/الجزء فقط
  3. إذا لم يكن هناك تحديد → يحذف كل <a href> ويترك النص
  4. يراقب الصفحة ويضيف الزر تلقائيًا عند ظهور شريط الأدوات
4) تفعيل تحميل الملف داخل محرر XenForo (الخطوة الأهم)
هنا كثير يتعثرون:
وجود الملف وحده لا يكفي… لازم XenForo “يحمّله” داخل قالب المحرر.

4.1 أنشئ Template Modification
لاظهار زر اضافة تامبلت جديد، يجب اضافة الكود التالي داخل ملف config

تفعيل إعدادات وضع التطوير للمبرمجين - Development Enabled
PHP:
$config['development']['enabled'] = true;

بعدها اذهب إلى:
ACP → Appearance → Template modifications → Add template modification

Add template modification.jpg

ضع التالي:
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.

Test.png

احذف الكود الذي اضفناه في ملف config بعد الانتهاء من اضافة التامبلت.


5) تصغير حجم الأيقونة (اختياري لكنه جميل)

extra.less.png

إذا كانت الأيقونة أكبر من بقية الأزرار، نضبطها عبر 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 محمّلة وقت التنفيذ.
الحل النهائي:
استخدم ملفنا الحالي لأنه لا يعتمد على jQuery نهائيًا.

المشكلة C: تغييرات لا تظهر بسبب الكاش
الحل:

Hard Refresh:
Mac: Cmd + Shift + R
Windows: Ctrl + Shift + R
وإذا تستخدم Cloudflare:
Purge Cache

خاتمة الدرس
بهذا أنت أضفت ميزة احترافية داخل محرر XenForo 2.3.7:
✅ زر “إزالة الروابط” يعمل بسرعة
✅ بدون التأثير على النص
✅ وبدون اعتماد على إضافات خارجية أو BB Code hacks
والأجمل أنه “حل نظيف” لأننا أضفناه كأمر محرر (Editor Command) مع زر داخل شريط الأدوات.

جربوها وستنجح معكم بكل تاكيد ان شاء الله.
تحيتي
 
شرح ممتاز
سلمت يمناك مديرنا🌹🌹🌹
 
شكرا جزيلا لمرورج العطر كرميلا
تحيتي
 
Similar content الاكثر مشاهدة عرض المزيد
عودة
أعلى أسفل