أنا أحاول حاليًا إضافة مقطع فيديو إلى صفحات ملفات تعريف مستخدمين معينة، بحيث يكون لدى جميع رعاتنا مقطع فيديو خلفي معين على ملفاتهم الشخصية. (قبل أن تنزعجوا، سيكون مجرد رسوم متحركة متكررة، وليس فيديو كامل - يجب أن يبدو لطيفًا جدًا، على غرار خلفيات ملفات تعريف Steam.)
رمز HTML و CSS التالي يعمل لجميع المستخدمين - ولكن من الواضح أن هذا ليس ما نسعى إليه حقًا:
// هذا يذهب في علامة التبويب "Header"
<video playsinline autoplay muted loop id="myVideo" poster="[INSERT LINK]">
<source src="[INSERT LINK]" type="video/webm">
<source src="[INSERT LINK]" type="video/mp4">
</video>
على عكس استخدام body.category-general لإضافة صورة إلى الصفحات الموجودة في فئة “general” فقط، لا يبدو أن هناك علامات محددة مخصصة لصفحات الملفات الشخصية للمستخدمين في مجموعة معينة أو باسم مستخدم معين. نحن جدد جدًا في هذا الأمر ولدينا خبرة في CSS بشكل أساسي بدلاً من العمل المباشر مع HTML، ولذلك لسنا متأكدين مما إذا كانت هناك طريقة سهلة ومريحة لجعل هذا يعمل كما نرغب.
نتخيل أن النهج الأفضل سيكون إضافة علامة مشابهة لملفات تعريف المستخدمين بناءً على مجموعتهم، لكننا لسنا متأكدين من كيفية تحقيق ذلك وكيفية جعل الفيديو يظهر فقط في الصفحات ذات المحتوى الصحيح، كما أننا لسنا ملتزمين باستخدام هذا النهج تحديدًا إذا كانت هناك طريقة أخرى أسهل.
على سبيل المثال، سنكون منفتحين أيضًا على فكرة القيام بذلك على أساس كل مستخدم على حدة بدلاً من أساس كل مجموعة، إذا كان ذلك أسهل بطريقة ما.
نفضل فقط عدم الاضطرار إلى ترميز الفيديو بشكل ثابت على كل صفحة، بحيث يتم تحميله فقط عند زيارة المستخدم (المستخدمين) المعنيين.
تعديل: ربما يجب أن أشير إلى أننا نستخدم الفرع المستقر، في حال كان ذلك يغير شيئًا.
نهجنا الحالي هو معرفة ما إذا كان بإمكاننا ببساطة اكتشاف أننا على صفحة مستخدم معين عبر الرابط الأساسي، وإذا كنا كذلك، فسنقوم بتطبيق الفيديو. على هذا النحو، لدينا ما يلي:
<script type="text/discourse-plugin" version="0.8">
api.onPageChange(() => {
determineUser();
});
function determineUser() {
var pageURL = document.querySelector("link[rel='canonical']").getAttribute("href");
var isUserPage = pageURL.includes("https://www.fortressoflies.com/u/");
document.documentElement.style.setProperty('--currUsername', pageURL);
if(isUserPage)
{
document.documentElement.style.setProperty('--lastUsername', pageURL);
$('body').css('background-color', '#'+(Math.random()*0xFFFFFF<<0).toString(16));
}
}
</script>
ومع ذلك، يبدو أن هذا يعمل فقط عند التحديث الكامل - لأي سبب كان، فإن التنقل بين الصفحات لا يؤدي إلى تحديث خاصية --currUsername، وبدلاً من تطبيق خلفية ملونة عشوائية لصفحات المستخدم، فإنه يطبق خلفية ملونة عشوائية لجميع الصفحات إذا تم الضغط على F5 مؤخرًا على صفحة مستخدم، بينما لا يطبق شيئًا على أي صفحة إذا تم الضغط على F5 مؤخرًا على صفحة غير مستخدم.
بصراحة، لست خبيرًا بما يكفي في JavaScript لمعرفة سبب ذلك - يبدو لي أنه عند تغيير الصفحة، يجب تشغيل الدالة (وهو ما يحدث)، مما يؤدي إلى تحديث متغير pageURL، وهذا يجب أن يؤدي إلى تحديث خاصية --currUsername عند تحميل صفحة. ومع ذلك، يحدث هذا فقط عند التحديث الكامل، وإلا فإن المتغيرات لا تتغير على ما يبدو.
يبدو أن هذا يرجع إلى أن عنوان URL الأساسي لا يتم تحديثه، بينما يتم تحديث خاصية “og:url”.
المشكلة الوحيدة هي أن استخدام var pageURL = document.querySelector("meta[property='og:url']").getAttribute("content"); يتم تحديثه قبل تحديث العلامة الوصفية نفسها - أي أن هذا الرمز يعطيني عنوان URL للصفحة السابقة، وليس الحالي.
If you want to add content to a specific page, your best option is a plugin-outlet. In a nutshell, plugin-outlets are spaces reserved in Discourse templates that you can use to add new content.
The first thing you’ll need to find out is if a plugin-outlet exists on the page you want to target. There’s a theme component that you can install that helps you with that.
Once you install that component, toggle it, head over to the page you want to target and check what you have to work with. In your case, such a plugin-outlet exists (highlighted in green)
Suppose that it didn’t exist… what then? The best option, in that case, is to ask for it to be added or send a PR to add it to core. It will get accepted most of the time if your use-case makes sense.
Anyway, as I said, it already exists in this case. So, let’s see how you can add markup to it. You won’t need the component above for the rest of this, so you can disable it now since you already have the name of the plugin outlet.
All you need to do is add something like this in the header tab of your theme.
<script type="text/x-handlebars" data-template-name="/connectors/OUTLET_NAME/SOME_NAME">
Your markup goes here...
</script>
You need to change OUTLET_NAME to the name of the outlet you want to target. Then change SOME_NAME to the name you want to give this customization. The name can be anything, but try to be descriptive if you can. It’s a good practice. So, we end up with this.
<script type="text/x-handlebars" data-template-name="/connectors/above-user-profile/add-profile-videos">
Your markup goes here...like
<h1>Hello World!!</h1>
</script>
Let’s try that and see what happens… remember, the snippet above goes in your theme’s common > header tab.
You don’t want your videos to show on every profile, and you want them to only show based on some condition. So, how do you do that? Well, you’ll need two things, some data to consume and a bit of Javascript.
Let’s find the data. Remember when I said plugin-outlets are reserved spaces? Well, what’s the point of having them without context? That’s why Discourse passes the relevant bits of context to each plugin outlet… but first, let’s take a step back. When you add this
and check the browser console. You’ll see this whenever the outlet is rendered; IE, you’re on a user page.
Now, is any of this stuff helpful? Yes… but not at the moment. We’ll come back to this. Let’s take another step back and see how Discourse passes the context to the outlet. If you search for the outlet name on Github - or locally - you’ll get this.
You can browse through that data and see if it has what you need. It should since it contains all the data about the user used in other elements on that page. It’s the “model” for the user page for that particular user.
One of the properties available there is… drumroll … the groups the user belongs to.
So, if you do
{{log args.model.groups}}
you’ll get all the groups the user belongs to in the console.
Alright, now we have the data we need, so the only thing left is to add some condition(s) based on that.
You might be tempted to think that we can do that in the same snippet, but, unfortunately, we can’t. Handlebars is a templating language. It has very, very basic support for logic - nothing beyond simple true/false conditions and loops. You can’t do comparisons and other stuff like that.
So where exactly can you do that? In a connector class, sounds fancy… I know.
In a nutshell, a connector class is essentially a bit of Javascript attached to the outlet. It’s a lot more nuanced than that, but that’s all you really need to know for now.
Inside our connector class, we can do some work… but… we need to be mindful that it’s not just like any javaScript file. For lack of a better description… think of it as an Ember component on a diet. Expanding on this is a bit outside the scope here, so let’s move on.
You can then call that action from within the outlet, like when a button is pressed. We won’t be needing this one here, so let’s move on.
api.registerConnectorClass("above-user-profile", "add-profile-videos", {
shouldRender(args, component) {
// return true or false here
}
});
We also won’t be using this one since the outlet only renders on profile pages, and we don’t have any other requirements for now. However, you can use this to add any conditions you want to test before the outlet is rendered. For example, the trust-level of the current user or stuff like that. Moving on…
This is the one we want to focus on. Whatever javaScript conditions or variables you want to set go here. Before we dig deeper into that one, let’s cover the last method first for completeness’ sake
you’ll see the same information in the browser console that we saw before. The groups that the profile owner belongs to. This is where the fun begins, you now have the data, and you have the correct hook. So you can do whatever you want here. So, if I want the video to only show on the profiles of members that belong to a certain group, I can do this
If you try this on a profile page that belongs to a user in the staff group, it will print true in the console. So, now the only thing we have left to do is to pass that to the outlet template. Here’s how you can do that.
component passed to setupComponent here is shared between the connector and the outlet. You can pass things to the outlet by setting them as properties on the component like so
then check a profile page for a staff user. You’ll see that it loads the video.
Once you navigate away from the staff member’s profile, the video will go away. The video won’t show on profiles for users who are not in the staff group.
So, let’s put all of this together. This is the same stuff from above.
Here’s the CSS I used. common > css tab
#myVideo {
position: fixed;
top: var(--header-offset);
min-height: 100vh;
left: 0;
z-index: -1;
}
.user-content {
background: none;
}
.user-main {
padding: 0.5em;
background: rgba(var(--secondary-rgb), 0.8);
}
// if you want it on mobile too
.mobile-view {
body[class*="user-"] {
background: none;
.user-main,
.user-content {
padding: 0.5em;
background: rgba(var(--secondary-rgb), 0.8);
}
}
}
HTML / javaScript / Handlebars. This goes in the common > header tab of your theme
Change TARGET_GROUP to the name of the group you want to target and add the src attributes for your videos.
This post was on the longer side… don’t be deterred by that. Once you grasp the concept, everything we did above can be done in less than 3-5 minutes.
The nice thing here is that all the stuff we talked about is pretty much the same for any plugin outlet. The only thing that changes is the name. So, this applies to any plugin-outlet modifications you want to do in the future.
هذا مفصل بشكل لا يصدق وسأتأكد من مراجعته عندما يكون لدي بعض الوقت الأسبوع المقبل، ولكن يكفي القول من خلال التصفح السريع يبدو أفضل بكثير من تطبيقي الحالي (تضمين الفيديو في كل صفحة على حدة وإظهاره فقط في ملف تعريف المستخدم، والذي أنجزته باستخدام برنامج نصي يضيف علامة إلى جسم صفحة المستخدم إذا كان اسم حسابه شيئًا معينًا). شكرًا على الشرح المفصل، لا أطيق الانتظار للبدء فيه!
ومع ذلك، نواجه مشكلة في CSS الخاص بنا - نرغب في إجراء بعض التغييرات على كيفية ظهور صفحة المستخدم لهؤلاء المستخدمين فقط.
في الوقت الحالي، نحقق ذلك عبر نفس الكود السابق:
<script type="text/discourse-plugin" version="0.8">
api.onPageChange(() =>{
window.onload = determineUser();
});
async function determineUser() {
await sleep(50);
var pageURL = document.querySelector("meta[property='og:url']").getAttribute("content");
var isUserPage = pageURL.includes("https://www.siteurl.com/u/");
var isUser1 = pageURL.includes("u/User1/");
document.body.className = document.body.className.replace(" user-page-animated","");
if(isUserPage)
{
if(isUser1)
{
document.body.className += ' user-page-animated';
}
}
}
function sleep(ms)
{
return new Promise(resolve => setTimeout(resolve, ms));
}
</script>
يتيح لنا هذا ببساطة نسخ ولصق كود “User1” لكل مستخدم جديد، ولكنه يعتمد على تأخير 50 مللي ثانية بعد كل تحميل للصفحة قبل التشغيل، وهو ما يكون مرئيًا للمستخدم النهائي (وإذا تمت إزالته، فإنه لا يعمل لأي سبب).
هل هناك أي طريقة لربط إضافة الفئة هذه إلى الجسم بالكود الذي قدمته، حتى نتمكن من استخدامه لتنسيق الصفحات التي تحتوي على مقاطع فيديو بشكل مختلف عن تلك التي لا تحتوي عليها؟