Ahmed Bouchefra Profile Header
A.B

;Ahmed Bouchefra

1.2k منشورات
100k قارئ
9 كاتب

أنا أحمد بوشفرة، مبرمج ومؤلف تقني (Tech Author) متخصص في تبسيط مفاهيم البرمجة وتطوير الويب. منذ عام 2017، أقدّم محتوى موجّهًا للمبرمجين عبر موقع 10xdev blog، بالإضافة إلى منصّات مثل SitePoint وSmashing Magazine. أسلوبي عملي ويساعد المبرمجين على فهم التقنيات بسرعة وبناء مهارات قوية بثقة. كما تعاونت مع دار النشر Packt في إصدار كتاب Full Stack Development with Angular and GraphQL، مما يعكس جودة المحتوى الذي أقدمه للمبرمجين. يحتوي هذا الموقع على مقالات كتبتها للجمهور العربي، بالإضافة إلى مقالاتي المترجمة من موقع 10xdev blog ومقالات أخرى ساهم بها مبرمجون من مختلف الأنحاء.

لماذا يجب أن تغير طريقة كتابة الكود في 2025 (مع كورس بايثون مجاني)

لماذا يجب أن تغير طريقة كتابة الكود في 2025 (مع كورس بايثون مجاني)

Farid Rajab • December 08, 2025

البرمجة

الذكاء الاصطناعي

تكنولوجيا

تطوير الويب

الأمن السيبراني

بايثون

تطوير وظيفي

to your page. * 2. Mark content:
...
* 3. Mark links: ... * * Flow: * - If not subscribed -> Shows Bottom Bar. * - Clicking Bar/Link -> Redirects to /subscribe?next={currentUrl} */ const ContentLocker = { config: { appId: "c1f1ef60-6daa-4617-a6c6-4a8d0df082d7", subscribeUrl: "/subscribe", // The page where you handle the actual subscription text: { barMessage: "🔒 هذا المحتوى حصري للمشتركين.", barBtn: "اشترك مجاناً للوصول", lockedContentOverlay: "🔒 اشترك للمتابعة" } }, init: function(options = {}) { const globalConfig = window.ContentLockerConfig || {}; this.config = { ...this.config, ...globalConfig, ...options }; this.injectSDK(); this.injectStyles(); this.setupOneSignal(); }, injectSDK: function() { if (!document.querySelector('script[src*="OneSignalSDK.page.js"]')) { const script = document.createElement('script'); script.src = "https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js"; script.defer = true; document.head.appendChild(script); } }, injectStyles: function() { const css = ` /* Bottom Bar */ #os-simple-bar { position: fixed; bottom: 0; left: 0; width: 100%; background: white; box-shadow: 0 -4px 20px rgba(0,0,0,0.1); padding: 15px 20px; display: none; /* Hidden by default */ flex-direction: row; justify-content: space-between; align-items: center; z-index: 99999; font-family: 'IBM Plex Sans Arabic', sans-serif; border-top: 1px solid #eee; } #os-simple-bar span { font-weight: bold; color: #333; font-size: 14px; } #os-simple-bar button { background: #2563eb; color: white; border: none; padding: 10px 20px; border-radius: 6px; font-weight: bold; cursor: pointer; font-family: inherit; font-size: 14px; white-space: nowrap; } #os-simple-bar button:hover { background: #1d4ed8; } /* Mobile Stack */ @media (max-width: 600px) { #os-simple-bar { flex-direction: column; gap: 10px; text-align: center; } #os-simple-bar button { width: 100%; } } /* Content Blur */ .os-locked-blur { filter: blur(5px); user-select: none; pointer-events: none; } .os-locked-wrapper { position: relative; overflow: hidden; } /* Overlay on blurred content */ .os-locked-overlay-msg { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 10; background: rgba(255,255,255,0.9); padding: 10px 20px; border-radius: 30px; font-weight: bold; color: #333; box-shadow: 0 4px 10px rgba(0,0,0,0.1); pointer-events: auto; /* Allow clicking if we add a button here later */ white-space: nowrap; cursor: pointer; } `; const style = document.createElement('style'); style.textContent = css; document.head.appendChild(style); }, createBottomBar: function() { if (document.getElementById('os-simple-bar')) return; const div = document.createElement('div'); div.id = 'os-simple-bar'; div.dir = "rtl"; div.innerHTML = ` ${this.config.text.barMessage} `; document.body.appendChild(div); // Bind redirect logic document.getElementById('os-bar-btn').onclick = () => this.redirectToSubscribe(); }, redirectToSubscribe: function(targetUrl) { // If a specific target (like a file download) was passed, use that as the "next" url // Otherwise use the current page const returnUrl = targetUrl || window.location.href; // Redirect to subscribe page with ?next= parameter window.location.href = `${this.config.subscribeUrl}?next=${encodeURIComponent(returnUrl)}`; }, lockContent: function() { // 1. Show Bar this.createBottomBar(); document.getElementById('os-simple-bar').style.display = 'flex'; // 2. Lock Content Blocks const contentBlocks = document.querySelectorAll('[data-locked="content"]'); contentBlocks.forEach(block => { if (!block.classList.contains('os-locked-wrapper')) { block.classList.add('os-locked-wrapper'); // Wrap inner content to blur it const inner = document.createElement('div'); inner.className = 'os-locked-blur'; inner.innerHTML = block.innerHTML; block.innerHTML = ''; block.appendChild(inner); // Add simple center message const msg = document.createElement('div'); msg.className = 'os-locked-overlay-msg'; msg.innerHTML = this.config.text.lockedContentOverlay; msg.onclick = () => this.redirectToSubscribe(); block.appendChild(msg); } }); // 3. Lock Links const links = document.querySelectorAll('a[data-locked="link"]'); links.forEach(link => { // Clone to remove old event listeners const newLink = link.cloneNode(true); link.parentNode.replaceChild(newLink, link); newLink.addEventListener('click', (e) => { e.preventDefault(); // Pass the link href so they get sent there after subscribing this.redirectToSubscribe(newLink.href); }); }); }, unlockContent: function() { // 1. Hide Bar const bar = document.getElementById('os-simple-bar'); if (bar) bar.style.display = 'none'; // 2. Unblur Content const contentBlocks = document.querySelectorAll('[data-locked="content"]'); contentBlocks.forEach(block => { if (block.classList.contains('os-locked-wrapper')) { // Remove overlay message const msg = block.querySelector('.os-locked-overlay-msg'); if (msg) msg.remove(); // Unwrap content (remove blur div) const blurDiv = block.querySelector('.os-locked-blur'); if (blurDiv) { block.innerHTML = blurDiv.innerHTML; } block.classList.remove('os-locked-wrapper'); } }); // 3. Restore Links (Simple reload or just let them work if clicked now) // Since we replaced nodes in lockContent, we simply won't preventDefault anymore. // However, we need to remove the listeners we added in lockContent. // The easiest way for this lightweight script is just to reload page // OR simply realize that if we are here, OneSignal logic runs first on load. }, setupOneSignal: function() { window.OneSignalDeferred = window.OneSignalDeferred || []; OneSignalDeferred.push(async (OneSignal) => { await OneSignal.init({ appId: this.config.appId, // We don't need service worker path here strictly if we are just checking status, // but good practice to keep it if initialized elsewhere. // serviceWorker: { path: "OneSignalSDK.sw.js" } }); if (OneSignal.User.PushSubscription.optedIn) { this.unlockContent(); } else { this.lockContent(); } // Real-time listener (in case they subscribe on this page somehow) OneSignal.User.PushSubscription.addEventListener("change", (event) => { if (event.current.optedIn) { this.unlockContent(); } else { this.lockContent(); } }); }); } }; // Auto-init document.addEventListener('DOMContentLoaded', () => { ContentLocker.init(); });