1. الصق المقتطف
ضع الكود المُولَّد قبل وسم إغلاق body مباشرة في كل صفحة. لا اعتماديات له ولا يضيف أي طلبات شبكة.
أداة مجانية
اختر فئات ملفات تعريف الارتباط، واكتب النص، واختر الشكل — ثم انسخ لافتة موافقة بلا أي اعتماديات يمكن لصقها في أي موقع. تحفظ اختيار الزائر، وتُبقي النصوص البرمجية الموسومة محجوبة حتى تُمنح فئتها، ويمكن إعادة فتحها من رابط في التذييل.
لافتة الموافقة الخاصة بك
الصق هذا قبل وسم إغلاق body مباشرة، في كل صفحة.
<!-- Cookie consent banner - paste this just before </body> -->
<script>
(function () {
var CFG = {
"storageKey": "cookie_consent",
"position": "bar",
"theme": "light",
"accent": "#a6144d",
"title": "نستخدم ملفات تعريف الارتباط",
"message": "نستخدم ملفات تعريف الارتباط لتشغيل هذا الموقع وفهم كيفية استخدامه وتحسينه. يمكنك قبول كل شيء، أو رفض الاختياري، أو الاختيار حسب الفئة.",
"policyUrl": "https://example.com/privacy",
"policyLabel": "اقرأ سياسة الخصوصية",
"accept": "قبول الكل",
"reject": "رفض الاختياري",
"prefs": "التفضيلات",
"save": "حفظ الاختيارات",
"categories": [
{
"id": "necessary",
"label": "ضرورية تماماً",
"desc": "لازمة لعمل الموقع. مفعّلة دائماً ولا تطلب موافقة.",
"required": true
},
{
"id": "analytics",
"label": "التحليلات",
"desc": "تقيس كيفية استخدام الموقع بهدف تحسينه.",
"required": false
},
{
"id": "marketing",
"label": "التسويق",
"desc": "تُستخدم لتخصيص الإعلانات وقياس الحملات.",
"required": false
}
]
};
var KEY = CFG.storageKey;
var doc = document;
var box = null;
function read() {
try { return JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (e) { return null; }
}
function save(consent) {
consent.necessary = true;
consent.date = new Date().toISOString();
try { localStorage.setItem(KEY, JSON.stringify(consent)); } catch (e) {}
unblock(consent);
window.dispatchEvent(new CustomEvent('consentchange', { detail: consent }));
if (typeof window.onConsentChange === 'function') window.onConsentChange(consent);
}
// Scripts the site parked behind a category run only once it is granted. Park
// one by giving its tag type="text/plain" and data-consent="analytics".
// (Deliberately described, not shown: a literal script tag written out here
// would close this one early and truncate everything below it.)
function unblock(consent) {
var parked = doc.querySelectorAll('script[type="text/plain"][data-consent]');
for (var i = 0; i < parked.length; i++) {
var old = parked[i];
if (!consent[old.getAttribute('data-consent')]) continue;
var next = doc.createElement('script');
for (var a = 0; a < old.attributes.length; a++) {
var at = old.attributes[a];
if (at.name !== 'type' && at.name !== 'data-consent') next.setAttribute(at.name, at.value);
}
next.text = old.text;
old.parentNode.replaceChild(next, old);
}
}
function styles() {
var dark = CFG.theme === 'dark';
var bg = dark ? '#161622' : '#ffffff';
var fg = dark ? '#f4f4f8' : '#141a47';
var muted = dark ? 'rgba(244,244,248,.72)' : 'rgba(20,26,71,.7)';
var line = dark ? 'rgba(255,255,255,.14)' : 'rgba(20,26,71,.12)';
var el = doc.createElement('style');
el.textContent = [
'.cc-root{position:fixed;z-index:2147483000;font:400 14px/1.55 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;color:' + fg + ';box-sizing:border-box}',
'.cc-root *,.cc-root *::before,.cc-root *::after{box-sizing:inherit}',
'.cc-card{background:' + bg + ';border:1px solid ' + line + ';box-shadow:0 18px 48px rgba(0,0,0,.18);border-radius:14px;padding:20px}',
'.cc-bar{left:0;right:0;bottom:0;padding:16px}',
'.cc-bar .cc-card{display:flex;flex-wrap:wrap;gap:16px;align-items:center;justify-content:space-between;max-width:1120px;margin:0 auto}',
'.cc-box{left:16px;bottom:16px;max-width:400px}',
'.cc-modal{inset:0;display:flex;align-items:center;justify-content:center;padding:16px;background:rgba(10,10,20,.5)}',
'.cc-modal .cc-card{max-width:520px;width:100%}',
'.cc-title{margin:0 0 6px;font-size:16px;font-weight:700}',
'.cc-text{margin:0;color:' + muted + '}',
'.cc-text a{color:' + CFG.accent + ';font-weight:600}',
'.cc-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}',
'.cc-bar .cc-actions{margin-top:0}',
'.cc-btn{appearance:none;cursor:pointer;border:1px solid ' + line + ';border-radius:999px;padding:9px 18px;font:600 14px inherit;background:transparent;color:' + fg + '}',
'.cc-btn-main{background:' + CFG.accent + ';border-color:' + CFG.accent + ';color:#fff}',
'.cc-btn:focus-visible{outline:2px solid ' + CFG.accent + ';outline-offset:2px}',
'.cc-cats{display:none;margin:14px 0 0;padding:14px 0 0;border-top:1px solid ' + line + '}',
'.cc-cats.cc-open{display:block}',
'.cc-cat{display:flex;gap:10px;align-items:flex-start;margin-bottom:12px}',
'.cc-cat input{margin:3px 0 0;accent-color:' + CFG.accent + '}',
'.cc-cat strong{display:block;font-size:14px}',
'.cc-cat span{display:block;color:' + muted + ';font-size:13px}',
'@media(max-width:640px){.cc-bar .cc-card{display:block}.cc-bar .cc-actions{margin-top:14px}.cc-btn{flex:1 1 auto}}'
].join('');
doc.head.appendChild(el);
}
function build() {
var stored = read() || {};
var root = doc.createElement('div');
root.className = 'cc-root cc-' + CFG.position;
root.setAttribute('role', CFG.position === 'modal' ? 'dialog' : 'region');
root.setAttribute('aria-label', CFG.title);
if (CFG.position === 'modal') root.setAttribute('aria-modal', 'true');
var card = doc.createElement('div');
card.className = 'cc-card';
var copy = doc.createElement('div');
var h = doc.createElement('p');
h.className = 'cc-title';
h.textContent = CFG.title;
var p = doc.createElement('p');
p.className = 'cc-text';
p.textContent = CFG.message + ' ';
if (CFG.policyUrl) {
var link = doc.createElement('a');
link.href = CFG.policyUrl;
link.textContent = CFG.policyLabel;
p.appendChild(link);
}
copy.appendChild(h);
copy.appendChild(p);
var cats = doc.createElement('div');
cats.className = 'cc-cats';
var inputs = {};
for (var i = 0; i < CFG.categories.length; i++) {
var c = CFG.categories[i];
var row = doc.createElement('label');
row.className = 'cc-cat';
var cb = doc.createElement('input');
cb.type = 'checkbox';
cb.checked = c.required || stored[c.id] === true;
cb.disabled = !!c.required;
var txt = doc.createElement('div');
var name = doc.createElement('strong');
name.textContent = c.label;
var desc = doc.createElement('span');
desc.textContent = c.desc;
txt.appendChild(name);
txt.appendChild(desc);
row.appendChild(cb);
row.appendChild(txt);
cats.appendChild(row);
inputs[c.id] = cb;
}
copy.appendChild(cats);
var actions = doc.createElement('div');
actions.className = 'cc-actions';
function button(label, main, onClick) {
var b = doc.createElement('button');
b.type = 'button';
b.className = 'cc-btn' + (main ? ' cc-btn-main' : '');
b.textContent = label;
b.addEventListener('click', onClick);
actions.appendChild(b);
return b;
}
function decide(granted) {
var consent = {};
for (var i = 0; i < CFG.categories.length; i++) {
var c = CFG.categories[i];
consent[c.id] = c.required ? true : granted === null ? !!inputs[c.id].checked : granted;
}
save(consent);
close();
}
var prefsBtn = button(CFG.prefs, false, function () {
var open = cats.classList.toggle('cc-open');
prefsBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
saveBtn.style.display = open ? '' : 'none';
});
prefsBtn.setAttribute('aria-expanded', 'false');
button(CFG.reject, false, function () { decide(false); });
button(CFG.accept, true, function () { decide(true); });
var saveBtn = button(CFG.save, false, function () { decide(null); });
saveBtn.style.display = 'none';
card.appendChild(copy);
card.appendChild(actions);
root.appendChild(card);
doc.body.appendChild(root);
box = root;
}
function close() {
if (box && box.parentNode) box.parentNode.removeChild(box);
box = null;
}
function open() {
if (!box) build();
}
function start() {
styles();
var stored = read();
if (stored) unblock(stored);
else build();
window.showConsentPreferences = open;
}
if (doc.readyState === 'loading') doc.addEventListener('DOMContentLoaded', start);
else start();
})();
</script> طريقة الاستخدام
ضع الكود المُولَّد قبل وسم إغلاق body مباشرة في كل صفحة. لا اعتماديات له ولا يضيف أي طلبات شبكة.
غيّر نوع وسم التتبّع إلى text/plain وأضف data-consent="analytics". تشغّله اللافتة لحظة منح تلك الفئة — ولا تشغّله قبل ذلك أبداً.
أضف رابطاً في التذييل يستدعي window.showConsentPreferences() ليتمكن الزوار من إعادة فتح اللوحة. كل قرار يُطلق أيضاً حدث consentchange يمكنك الاستماع إليه.
الأسئلة الشائعة
توفّر لك الآليات التي تتوقعها الجهات التنظيمية: لا ملفات تعريف ارتباط اختيارية قبل الموافقة، ورفض بسهولة القبول نفسها، واختيار حسب الفئة، وإمكانية تغيير الرأي لاحقاً. لكن الامتثال يعتمد أيضاً على ما تشغّله فعلاً، وما تقوله سياستك، وأين يوجد زوارك، فتعامل مع الكود المُولَّد كنقطة انطلاق متينة لا كاستشارة قانونية.
أعطِ وسم النص البرمجي type="text/plain" وسمة data-consent تحمل اسم فئته. لن ينفّذه المتصفح، وتعيد اللافتة كتابته كوسم نص برمجي حقيقي فور منح تلك الفئة — في هذه الزيارة أو في التالية، اعتماداً على القرار المحفوظ.
في localStorage، تحت المفتاح الذي تختاره، ككائن JSON صغير يحمل علامة لكل فئة إضافة إلى التاريخ. لا تضع اللافتة نفسها أي ملف تعريف ارتباط ولا تُرسل شيئاً إلى خادم، لذا تعمل على موقع ثابت بالكامل.
نعم. الموضع والمظهر ولون التمييز خيارات هنا، وكل عنصر في CSS المُولَّد يبدأ بالبادئة cc-، فيمكنك تجاوز القواعد من ورقة أنماطك دون المساس بالمقتطف.
لموقع واحد بفئات قليلة، يكفي هذا المقتطف عادةً. وحين تحتاج إلى سجلات موافقة أو عدة نطاقات أو تحليلات تحترم الاختيار تلقائياً، يتولى مدير الموافقة المدمج في PulsePanda المهمة كاملة.
ذات صلة
يأتي PulsePanda بمدير موافقة مدمج — بلا ملفات تعريف ارتباط افتراضياً، ويتوقف عن الجمع لحظة انسحاب أي شخص. لا مزوّد ثانٍ ولا كود ربط.
ابدأ مجانًا