أضف زر "تعاون" في المساهمات لتعديل الموضوع بشكل جماعي

كود جيفري

عضو جديد
عضو انكور
في بعض المواضيع المهمة كالأدلة والشروحات الطويلة والمشاريع المشتركة، يحتاج أكثر من عضو إلى المساهمة في تطوير المحتوى نفسه، لكن تتبع من أضاف ماذا يصبح صعبًا مع مرور الوقت. هذا الكود يضيف زرًا جديدًا باسم "تعاون" بجانب أزرار التحكم التقليدية مثل التعديل والحذف، ويظهر فقط للأعضاء الذين يملكون صلاحية تعديل الموضوع. ويتيح الزر لأكثر من عضو المشاركة في تعديل الموضوع أو المساهمة وتطويرها، مع توثيق أسماء وصور جميع المشاركين تلقائيًا أسفل المساهمة، حفاظًا على حقوق كل من ساهم في العمل. والكود مخصص لنسخ phpBB3 وModernBB وAwesomeBB.

مثال على الكود​

زر تعاون بجانب أزرار التعديل في المساهمة مع توثيق أسماء وصور الأعضاء المشاركين


شرح تركيب الكود​

كود CSS
CSS:
.btn-collab {
    float: left;
    border-radius: 3px;
    cursor: pointer;
    margin-right: 11px;
}
img.collab-avatar-img {
    margin-top: 6px;
    object-fit: cover;
    box-shadow: 0 1px 3px rgb(0 0 0 / .11),0 0 1px rgb(0 0 0 / .22);
    width: 90px;
    height: 90px;
    border-radius: 50%;
    padding: 2px;
    background: #b1b1b1;
    align-items: center;
    transition: transform 0.2s ease, background 0.3s ease;
    box-sizing: border-box;
}

img.collab-extra-avatar {
    width: 30px !important;
    height: 30px !important;
    margin: 0 6px 0 0 !important;
    padding: 2px !important;
    border-radius: 50%;
    object-fit: cover;
    vertical-align: middle;
    box-sizing: border-box;
    box-shadow: 0 1px 3px rgb(0 0 0 / .11),0 0 1px rgb(0 0 0 / .22);
    background: #b1b1b1;
}
a.collab-member-link {
    top: -3px;
    text-decoration: none;
    position: relative;
}

يمكنك تغيير التصميم كما تشاء ليناسب منتداك.

كود JavaScript
العنوان: كما تريد
الصلاحيات: اختر الكل، المدير - المشرفون - الأعضاء - الزوار
المكان: جميع الصفحات

JavaScript:
$(document).ready(function () {
    function cleanAvatarUrl(avatarData) {
        if (!avatarData) return 'https://2img.net/i/fa/empty.gif';
        var srcMatch = avatarData.match(/src=["']([^"']+)["']/i);
        if (srcMatch && srcMatch[1]) {
            return srcMatch[1];
        }
        if (avatarData.indexOf('http') === 0 || avatarData.indexOf('/') === 0) {
            return avatarData;
        }
        return 'https://2img.net/i/fa/empty.gif';
    }

    function getCleanTopicTitle() {
        var rawTitle = $('.topic-title, .page-title').first().text().trim();
        if (!rawTitle) {
            rawTitle = document.title.split('-')[0].split('|')[0].trim();
        }
        return rawTitle
            .replace(/^موضوع:\s*/i, '')
            .replace(/[\r\n\t]/g, '')
            .trim() || 'الموضوع';
    }

    function applyClassesToEditorTable($container) {
        $container.find('table').each(function () {
            var $table = $(this);
            $table.find('tr').each(function (rowIndex) {
                var $row = $(this);
                var $cells = $row.children('td');
                if ($cells.length === 0) return;
                if (rowIndex === 1) {
                    $cells.each(function (cellIndex) {
                        var $cell = $(this);
                        if (cellIndex < 4) {
                            $cell.find('img')
                                .addClass('collab-avatar-img')
                                .removeClass('collab-extra-avatar');
                        } else if (cellIndex === 4) {
                            $cell.find('img')
                                .removeClass('collab-avatar-img')
                                .addClass('collab-extra-avatar');
                        }
                    });
                }
            });

            $table.find('a').each(function () {
                var $a = $(this);
                if (
                    !$a.hasClass('collab-more-btn') &&
                    !$a.closest('.collab-more-list').length
                ) {
                    $a.addClass('collab-member-link');
                }
            });
        });
    }

    $('.postbody, .post-content').each(function () {
        var $body = $(this);
        if ($body.find('table[style*="border-collapse"]').length > 0) {
            $body
                .closest('.post, .post-wrap, div[id^="p"]')
                .addClass('has-collab-table');
            applyClassesToEditorTable($body);
        }
    });

    $('.post-wrap, .post, div[id^="p"]').each(function () {
        var $post = $(this);
        var $editBtn = $post.find('.btn-edit a, a[href*="mode=editpost"]');
        var editLink = $editBtn.attr('href');
        if (editLink && $post.find('.btn-collab').length === 0) {
            var $authorLink = $post.find(
                '.post-author-name a, ' +
                '.postprofile-name a, ' +
                '.postprofile dt a, ' +
                'p.author a'
            ).first();
            var originalAuthorName = $authorLink.text().trim() || 'كاتب المساهمة';
            var originalAuthorProfile = $authorLink.attr('href') || '#';
            var $avatarImg = $post.find(
                '.post-author-avatar img, ' +
                '.postprofile-avatar img, ' +
                '.postprofile dt img'
            ).first();
            var originalAuthorAvatar = cleanAvatarUrl($avatarImg.attr('src'));
            var topicTitle = getCleanTopicTitle();
            if (originalAuthorProfile.indexOf('http') === -1) {
                originalAuthorProfile = window.location.origin + originalAuthorProfile;
            }
            var collabEditUrl =
                editLink +
                '&collab=1' +
                '&author=' + encodeURIComponent(originalAuthorName) +
                '&author_prof=' + encodeURIComponent(originalAuthorProfile) +
                '&author_avatar=' + encodeURIComponent(originalAuthorAvatar) +
                '&title=' + encodeURIComponent(topicTitle);

            var $buttonTarget = $post.find('.profile-icons, .post-buttons ul, .dropdown-box');

            if ($buttonTarget.length) {
                $buttonTarget.append(
                    '<div class="btn-collab">' +
                    '<a href="' + collabEditUrl + '" title=" تعديل بالتعاون "> تعاون </a>' +
                    '</div>'
                );
            }
        }
    });
    if (window.location.search.indexOf('collab=1') !== -1) {
        var urlParams = new URLSearchParams(window.location.search);
        var authorName = urlParams.get('author') || 'كاتب المساهمة';
        var authorProf = urlParams.get('author_prof') || '#';
        var authorAvatar = urlParams.get('author_avatar') || 'https://2img.net/i/fa/empty.gif';
        var topicTitle = urlParams.get('title') || 'الموضوع';
        var currentUserName = (
            typeof _userdata !== 'undefined' && _userdata.username
        ) ? _userdata.username : 'عضو متعاون';
        var currentUserProf = window.location.origin + '/u' + (
            typeof _userdata !== 'undefined' ? _userdata.user_id : '1'
        );
        var currentUserAvatar = cleanAvatarUrl((
            typeof _userdata !== 'undefined' && _userdata.avatar
        ) ? _userdata.avatar : '');
        if (currentUserAvatar.indexOf('empty.gif') !== -1) {
            var pageAvatar = $(
                '.header-avatar img, ' +
                '#fa_welcome img, ' +
                '.avatar img'
            ).first().attr('src');

            if (pageAvatar) {
                currentUserAvatar = cleanAvatarUrl(pageAvatar);
            }
        }
        var checkEditor = setInterval(function () {
            var $textarea = $('textarea[name="message"]');
            var editorInstance = $textarea.data('sceditor');
            if (editorInstance || $textarea.length) {
                clearInterval(checkEditor);
                var currentContent = editorInstance ? editorInstance.val() : $textarea.val();
                var membersList = [];
                function addMember(name, prof, avatar) {
                    if (!name || name.trim() === '') return;
                    var cleanName = name
                        .replace(/[????????⯆▼]/g, '')
                        .replace(/account_circle/g, '')
                        .trim();

                    var cleanProf = prof || '#';
                    var exists = membersList.some(function (m) {
                        return (
                            m.name.toLowerCase() === cleanName.toLowerCase()
                        ) || (
                            m.prof !== '#' && m.prof === cleanProf
                        );
                    });

                    if (!exists) {
                        membersList.push({
                            name: cleanName,
                            prof: cleanProf,
                            avatar: avatar || 'https://2img.net/i/fa/empty.gif'
                        });
                    }
                }

                var tableRegex = /\[table[\s\S]*?\[\/table\]/i;
                if (tableRegex.test(currentContent)) {
                    var tableCode = currentContent.match(tableRegex)[0];
                    var tdMatches = tableCode.match(/\[td[\s\S]*?\[\/td\]/gi) || [];

                    for (var i = 0; i < tdMatches.length; i++) {
                        var td = tdMatches[i];
                        if (td.indexOf('colspan=') !== -1) continue;
                        var memberRegex = /\[url=([^\]]+)\]([\s\S]*?)\[b\]([^\[]+)\[\/b\][\s\S]*?\[\/url\]/gi;
                        var match;
                        var foundInTd = false;
                        while ((match = memberRegex.exec(td)) !== null) {
                            foundInTd = true;
                            var profUrl = match[1];
                            var innerContent = match[2];
                            var memberName = match[3];
                            var imgInUrl = innerContent.match(/\[img(?:\([^\)]+\))?\]([^\[]+)\[\/img\]/i);
                            var avatarUrl = 'https://2img.net/i/fa/empty.gif';
                            if (imgInUrl && imgInUrl[1]) {
                                avatarUrl = imgInUrl[1];
                            } else {
                                var imgInTd = td.match(/\[img(?:\([^\)]+\))?\]([^\[]+)\[\/img\]/i);
                                if (imgInTd && imgInTd[1]) {
                                    avatarUrl = imgInTd[1];
                                }
                            }

                            addMember(memberName, profUrl, avatarUrl);
                        }

                        if (!foundInTd) {
                            var fallbackRegex = /\[url=([^\]]+)\][\s\S]*?\[b\]([^\[]+)\[\/b\]/i;
                            var fallbackMatch = td.match(fallbackRegex);
                            var imgMatch = td.match(/\[img(?:\([^\)]+\))?\]([^\[]+)\[\/img\]/i);

                            if (fallbackMatch && fallbackMatch[2]) {
                                addMember(
                                    fallbackMatch[2],
                                    fallbackMatch[1],
                                    imgMatch ? imgMatch[1] : 'https://2img.net/i/fa/empty.gif'
                                );
                            }
                        }
                    }

                    var dropdownHtmlMatch = tableCode.match(/<div class="collab-more-list">([\s\S]*?)<\/div>/i);
                    if (dropdownHtmlMatch && dropdownHtmlMatch[1]) {
                        var linkRegex = /<a href="([^"]+)">([^<]+)<\/a>/gi;
                        var linkMatch;
                        while ((linkMatch = linkRegex.exec(dropdownHtmlMatch[1])) !== null) {
                            addMember(
                                linkMatch[2],
                                linkMatch[1],
                                'https://2img.net/i/fa/empty.gif'
                            );
                        }
                    }

                    addMember(currentUserName, currentUserProf, currentUserAvatar);
                } else {
                    addMember(authorName, authorProf, authorAvatar);
                    addMember(currentUserName, currentUserProf, currentUserAvatar);
                }
                var mainMembers = membersList.slice(0, 4);
                var hasExtraMembers = membersList.length > 4;
                var totalCols = mainMembers.length + (hasExtraMembers ? 1 : 0);
                var colWidth = Math.floor(100 / totalCols) + '%';
                var tdsCode = [];

                for (var j = 0; j < mainMembers.length; j++) {
                    var m = mainMembers[j];
                    tdsCode.push(
                        '[td style="width: ' + colWidth + '; padding: 0; text-align: center; border-right: 1px solid #f1f5f9; vertical-align: top;"]' +
                        ' \n' +
                        '[url=' + m.prof + ']' + m.name + '[/url]' +
                        '[/td]'
                    );
                }

                if (hasExtraMembers) {
                    var extraMembersCode = '';
                    for (var k = 4; k < membersList.length; k++) {
                        var ex = membersList[k];
                        extraMembersCode +=
                            '[url=' + ex.prof + ']' +
                            ' ' +
                            '' + ex.name + '' +
                            '[/url]' +
                            '';
                    }
                    var extraTd =
                        '[td style="width: ' +
                        colWidth +
                        '; padding: 8px 12px; text-align: right; vertical-align: middle;"]' +
                        extraMembersCode +
                        '[/td]';

                    tdsCode.push(extraTd);
                }

                var newTableBBCode =
                    '\n' +                    'المتعاونون في (' + topicTitle + ')\n' +                    '\n' +                    '\n' +                    tdsCode.join('\n') +                    '\n\n' +                    '\n\n';

                if (tableRegex.test(currentContent)) {
                    var updatedContent = currentContent.replace(tableRegex, newTableBBCode.trim());
                    if (editorInstance) {
                        editorInstance.val(updatedContent);
                        editorInstance.updateOriginal();
                    } else {
                        $textarea.val(updatedContent);
                    }
                } else {
                    if (editorInstance) {
                        editorInstance.val(newTableBBCode + currentContent);
                        editorInstance.updateOriginal();
                    } else {
                        $textarea.val(newTableBBCode + currentContent);
                    }
                }
                if (editorInstance && editorInstance.$area) {
                    setTimeout(function () {
                        applyClassesToEditorTable(editorInstance.$area.parent());
                    }, 500);
                }
            }
        }, 300);
    }
});

ثم اضغط على زر قدم.

فكرة رائعة تشجع روح العمل الجماعي في المنتدى وتحفظ لكل مشارك جهده بشكل واضح وموثق. شكر خاص لصاحب الكود على هذه الإضافة المبتكرة التي طوّرها بالاستعانة بالذكاء الاصطناعي.

صاحب الكود: كونان2000
 

رأيك جزء من المعرفة.

أضف تجربتك أو سؤالك، فالنقاش يكمل الفكرة.

في هذا الموضوع

صاحب النقاش

كود جيفري
كود جيفريعضو جديد

معرفة تكبر بالنقاش

وجدت معلومة مفيدة؟ أضف تجربتك أو سؤالك ليساعد النقاش أعضاء آخرين.

أكمل رحلتك

كود يخفي أي جزء من المساهمة عن الزواركود الروابط أو الزيارات الأخيرة في المنتدىتمييز المساهمات حسب الجهاز (الهواتف والكمبيوترات)
عودة
أعلى