Clavier arabe

Arabic keyboard with transliteration.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

Advertisement:

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

Advertisement:

// ==UserScript==
// @name         Clavier arabe
// @namespace    http://tampermonkey.net/
// @version      8.0
// @description  Arabic keyboard with transliteration.
// @author       A9ARTAS
// @match        *://*/*
// @match        *://newtab/*
// @match        about:newtab
// @match        chrome://newtab/*
// @match        edge://newtab/*
// @grant        GM_registerMenuCommand
// @run-at       document-end
// @license      MIT
// ==/UserScript==
(function() {
    'use strict';
    const SK = 'aekb7';
    function injectCSS() {
        if (document.getElementById('akcss')) return;
        const s = document.createElement('style');
        s.id = 'akcss';
        s.textContent = `
#aekb {
    position: fixed !important;
    z-index: 2147483647 !important;
    width: 92% !important; max-width: 420px !important;
    display: none; flex-direction: column !important;
    background: #1c1c1e !important;
    border-radius: 14px !important;
    box-shadow: 0 12px 48px rgba(0,0,0,.5), 0 0 0 0.5px rgba(255,255,255,.05) !important;
    font: 14px/1.5 -apple-system, BlinkMacSystemFont, sans-serif !important;
    color: #fff !important;
    user-select: none !important;
    overflow: hidden !important;
    font-family: -apple-system, BlinkMacSystemFont, sans-serif !important;
}
#aekb * { box-sizing: border-box !important; margin: 0 !important; padding: 0 !important; font-family: inherit !important; }
#aekb-bar {
    display: flex !important; align-items: center !important; justify-content: flex-end !important;
    height: 32px !important; padding: 0 8px !important;
    cursor: grab !important;
    background: #1c1c1e !important;
}
#aekb-bar:active { cursor: grabbing !important; }
#aekb-x {
    width: 26px !important; height: 26px !important; border-radius: 50% !important;
    background: #3a3a3c !important; border: none !important; color: #8e8e93 !important;
    font: 600 14px/1 -apple-system, sans-serif !important;
    display: flex !important; align-items: center !important; justify-content: center !important;
    cursor: pointer !important;
    transition: background .12s, color .12s !important;
}
#aekb-x:hover { background: #48484a !important; color: #fff !important; }
#aekb-x:active { background: #5a5a5e !important; }
#aekb-inp {
    width: 100% !important; padding: 12px 16px !important;
    background: #2c2c2e !important; color: #fff !important;
    border: none !important; outline: none !important;
    font: 16px/1.4 -apple-system, sans-serif !important;
    direction: rtl !important; resize: none !important; height: 50px !important;
}
#aekb-inp::placeholder { color: #8e8e93 !important; }
#aekb-cb {
    display: none !important;
}
#aekb-copy {
    background: #3a3a3c !important; border: none !important; border-radius: 6px !important;
    color: #fff !important; font: 500 12px/1 -apple-system, sans-serif !important;
    padding: 5px 16px !important; cursor: pointer !important;
    transition: background .12s !important;
}
#aekb-copy:hover { background: #48484a !important; }
#aekb-g {
    display: grid !important; grid-template-columns: repeat(10, 1fr) !important;
    gap: 6px !important; padding: 6px 5px 4px !important;
    background: #1c1c1e !important;
}
.aekb-k {
    background: #3a3a3c !important; border: none !important; border-radius: 5px !important;
    color: #fff !important; font: 400 18px/1 -apple-system, sans-serif !important;
    display: flex !important; align-items: center !important; justify-content: center !important;
    height: 42px !important; cursor: pointer !important;
    transition: background .06s, transform .06s !important;
    -webkit-tap-highlight-color: transparent !important;
    padding: 0 !important;
    box-shadow: 0 1px 0 rgba(0,0,0,.3) !important;
}
.aekb-k:hover { background: #48484a !important; }
.aekb-k:active { background: #545458 !important; transform: scale(.95) !important; }
.aekb-k.sp {
    grid-column: span 4 !important; font-size: 13px !important; font-weight: 500 !important;
    background: #636366 !important;
}
.aekb-k.sp:hover { background: #6e6e73 !important; }
.aekb-k.sp:active { background: #76767a !important; }
.aekb-k.cp {
    grid-column: span 2 !important; font-size: 12px !important; font-weight: 500 !important;
    background: #3a3a3c !important;
}
.aekb-k.cp:hover { background: #48484a !important; }
.aekb-k.cp:active { background: #545458 !important; }
#aekb-bot {
    display: flex !important; justify-content: center !important; padding: 6px 0 8px !important;
    background: #1c1c1e !important;
}
#aekb-bot div {
    width: 36px !important; height: 4px !important; border-radius: 2px !important;
    background: #48484a !important;
}
#akn {
    position: fixed !important; bottom: 80px !important; left: 50% !important;
    transform: translateX(-50%) !important;
    background: rgba(30,30,30,.92) !important; color: #fff !important;
    padding: 8px 20px !important; border-radius: 20px !important;
    z-index: 2147483647 !important;
    font: 500 13px/1.4 -apple-system, sans-serif !important;
    pointer-events: none !important; white-space: nowrap !important;
    animation: akf 1s ease forwards !important;
}
@keyframes akf {
    0% { opacity: 1; transform: translateX(-50%) translateY(0) }
    100% { opacity: 0; transform: translateX(-50%) translateY(-6px) }
}
`;
        document.head.appendChild(s);
    }
    // ─── Transliteration ─────────────────────────────────────────────────
    const R = [
        [/==a/g,'\u064B'],[/==i/g,'\u064D'],[/==u/g,'\u064C'],
        [/=a/g,'\u064E'],[/=i/g,'\u0650'],[/=u/g,'\u064F'],
        [/=w/g,'\u0651'],[/=o/g,'\u0652'],
        [/aa/g,'\u0622'],
        [/[a\u00E2\u00E0\u0101]/g,'\u0627'],
        [/b/g,'\u0628'],[/p/g,'\u067E'],[/t/g,'\u062A'],
        [/\u1E6F/g,'\u062B'],[/[j\u01E7]/g,'\u062C'],[/c/g,'\u0686'],
        [/[H\u1E25\u1E24]/g,'\u062D'],[/[x\u1E96K]/g,'\u062E'],
        [/d/g,'\u062F'],[/\u1E0F/g,'\u0630'],[/r/g,'\u0631'],[/z/g,'\u0632'],
        [/s/g,'\u0633'],[/\u0161/g,'\u0634'],[/[S\u1E63]/g,'\u0635'],
        [/[D\u1E0D]/g,'\u0636'],[/[T\u1E6B]/g,'\u0637'],[/[Z\u1E93]/g,'\u0638'],
        [/[g\u02BF]/g,'\u0639'],[/\u0121/g,'\u063A'],[/f/g,'\u0641'],[/v/g,'\u06A4'],
        [/q/g,'\u0642'],[/k/g,'\u0643'],[/l/g,'\u0644'],[/m/g,'\u0645'],
        [/n/g,'\u0646'],[/h/g,'\u0647'],
        [/[wou\u00F4\u00FB\u014D\u016B]/g,'\u0648'],
        [/[yie\u00EE\u012B]/g,'\u064A'],[/[YIE]/g,'\u0649'],[/\u1E97/g,'\u0629'],
        [/[\-]/g,'\u0621'],[/\u02BE/g,'\u0621'],[/_/g,'\u0640'],
        [/[?]/g,'\u061F'],[/[;]/g,'\u061B'],[/[,]/g,'\u060C'],
        [/0/g,'\u0660'],[/1/g,'\u0661'],[/2/g,'\u0662'],[/3/g,'\u0663'],
        [/4/g,'\u0664'],[/5/g,'\u0665'],[/6/g,'\u0666'],[/7/g,'\u0667'],
        [/8/g,'\u0668'],[/9/g,'\u0669'],[/%/g,'\u066A'],
    ];
    const POST = [
        [/'\u0628/g,'\u067E'],[/\u0628'/g,'\u067E'],
        [/'\u062A/g,'\u062B'],[/\u062A'/g,'\u062B'],
        [/'\u062C/g,'\u0686'],[/\u062C'/g,'\u0686'],
        [/'\u062D/g,'\u062E'],[/\u062D'/g,'\u062E'],
        [/'\u062F/g,'\u0630'],[/\u062F'/g,'\u0630'],
        [/'\u0631/g,'\u0632'],[/\u0631'/g,'\u0632'],
        [/'\u0633/g,'\u0634'],[/\u0633'/g,'\u0634'],
        [/'\u0635/g,'\u0636'],[/\u0635'/g,'\u0636'],
        [/'\u0637/g,'\u0638'],[/\u0637'/g,'\u0638'],
        [/'\u0639/g,'\u063A'],[/\u0639'/g,'\u063A'],
        [/'\u0641/g,'\u06A4'],[/\u0641'/g,'\u06A4'],
        [/'\u0642/g,'\u06A8'],[/\u0642'/g,'\u06A8'],
        [/'\u0643/g,'\u06AD'],[/\u0643'/g,'\u06AD'],
        [/'\u0647/g,'\u0629'],[/\u0647'/g,'\u0629'],
        [/'\u0648/g,'\u0624'],[/\u0648'/g,'\u0624'],
        [/'\u064A/g,'\u0649'],[/\u064A'/g,'\u0649'],
        [/'\u0649/g,'\u0626'],[/\u0649'/g,'\u0626'],
        [/'\u0627/g,'\u0623'],
        [/\u0627\u0627/g,'\u0622'],
        [/\u0648\u0621/g,'\u0624'],[/\u064A\u0621/g,'\u0626'],
        [/\u0627\u0621/g,'\u0625'],[/\u0647\u0621/g,'\u0629'],
        [/\u0621\u0627/g,'\u0623'],
    ];
    function tfm(t) {
        let r = t;
        for (const [re, s] of R) r = r.replace(re, s);
        for (const [re, s] of POST) r = r.replace(re, s);
        return r;
    }
    // ─── State ───────────────────────────────────────────────────────────
    let isOn = localStorage.getItem(SK) === 'true';
    let dragging = false, ox = 0, oy = 0;
    // ─── Input ───────────────────────────────────────────────────────────
    function onInput(e) {
        if (e.target.id !== 'aekb-inp') return;
        const el = e.target;
        const s = el.selectionStart, end = el.selectionEnd, st = el.scrollTop, o = el.value;
        if (s === 0 && end === o.length) {
            el.value = tfm(o);
            el.selectionStart = 0; el.selectionEnd = el.value.length;
        } else {
            el.value = tfm(o);
            el.selectionStart = el.selectionEnd = tfm(o.slice(0, s)).length;
        }
        el.scrollTop = st;
    }
    function ins(c) {
        const e = document.getElementById('aekb-inp'); if (!e) return;
        e.focus();
        const s = e.selectionStart;
        e.value = e.value.slice(0, s) + c + e.value.slice(e.selectionEnd);
        e.selectionStart = e.selectionEnd = s + c.length;
        e.dispatchEvent(new Event('input', { bubbles: true }));
    }
    function onKey(k) {
        if (k === 'Space') return ins(' ');
        ins(k);
    }
    // ─── Copy ────────────────────────────────────────────────────────────
    async function doCopy() {
        const e = document.getElementById('aekb-inp'); if (!e || !e.value) return;
        try { await navigator.clipboard.writeText(e.value); }
        catch { e.select(); document.execCommand('copy'); }
        notify('Copied!');
    }
    // ─── Notify ──────────────────────────────────────────────────────────
    function notify(msg) {
        let n = document.getElementById('akn');
        if (!n) { n = document.createElement('div'); n.id = 'akn'; document.body.appendChild(n); }
        n.textContent = msg;
        n.style.animation = 'none'; void n.offsetWidth;
        n.style.animation = 'akf 1s ease forwards';
    }
    // ─── Layout (no del button) ──────────────────────────────────────────
    const rows = [
        ['\u0636','\u0635','\u062B','\u0642','\u0641','\u063A','\u0639','\u0647','\u062E','\u062D'],
        ['\u0634','\u0633','\u064A','\u0628','\u0644','\u0627','\u062A','\u0646','\u0645','\u0643'],
        ['\u0626','\u0621','\u0624','\u0631','\u0644\u0627','\u0649','\u0629','\u0648','\u0632','\u0638'],
        ['\u0630','\u062F','\u062C','Space','\u0637','copy'],
    ];
    // ─── Build ───────────────────────────────────────────────────────────
    function build() {
        injectCSS();
        const p = document.createElement('div');
        p.id = 'aekb';
        // Title bar (drag handle)
        const bar = document.createElement('div');
        bar.id = 'aekb-bar';
        const xb = document.createElement('button');
        xb.id = 'aekb-x';
        xb.innerHTML = '×';
        xb.addEventListener('click', function() {
            p.style.display = 'none';
            isOn = false;
            localStorage.setItem(SK, 'false');
        });
        bar.appendChild(xb);
        p.appendChild(bar);
        // Textarea
        const ta = document.createElement('textarea');
        ta.id = 'aekb-inp';
        ta.placeholder = 'Type... \u0627\u0643\u062A\u0628...';
        ta.addEventListener('input', onInput);
        p.appendChild(ta);
        // Copy bar
        const cb = document.createElement('div');
        cb.id = 'aekb-cb';
        const cpb = document.createElement('button');
        cpb.id = 'aekb-copy';
        cpb.textContent = '\uD83D\uDCCB Copy';
        cpb.addEventListener('click', doCopy);
        cb.appendChild(cpb);
        p.appendChild(cb);
        // Keys
        const g = document.createElement('div');
        g.id = 'aekb-g';
        for (const row of rows) {
            for (const k of row) {
                const b = document.createElement('button');
                b.className = 'aekb-k';
                if (k === 'Space') b.classList.add('sp');
                if (k === 'copy') { b.classList.add('cp'); b.textContent = '\uD83D\uDCCB Copy'; b.addEventListener('click', doCopy); }
                else { b.textContent = k; b.addEventListener('click', (function(key) { return function() { onKey(key); }; })(k)); }
                g.appendChild(b);
            }
        }
        p.appendChild(g);
        // Bottom indicator
        const bot = document.createElement('div');
        bot.id = 'aekb-bot';
        bot.appendChild(document.createElement('div'));
        p.appendChild(bot);
        document.body.appendChild(p);
        // Drag
        bar.addEventListener('mousedown', function(e) {
            dragging = true;
            const r = p.getBoundingClientRect();
            ox = e.clientX - r.left;
            oy = e.clientY - r.top;
            p.style.transition = 'none';
            e.preventDefault();
        });
    }
    // ─── Global drag ─────────────────────────────────────────────────────
    document.addEventListener('mousemove', function(e) {
        if (!dragging) return;
        const p = document.getElementById('aekb'); if (!p) return;
        let x = e.clientX - ox, y = e.clientY - oy;
        const w = window.innerWidth, h = window.innerHeight;
        x = Math.max(0, Math.min(x, w - p.offsetWidth));
        y = Math.max(0, Math.min(y, h - p.offsetHeight));
        p.style.left = x + 'px';
        p.style.top = y + 'px';
    });
    document.addEventListener('mouseup', function() { dragging = false; });
    // ─── Toggle ──────────────────────────────────────────────────────────
    function toggle() {
        let p = document.getElementById('aekb');
        if (!p) { build(); p = document.getElementById('aekb'); }
        if (p.style.display === 'flex') {
            p.style.display = 'none';
            isOn = false;
        } else {
            p.style.left = Math.max(0, (window.innerWidth - p.offsetWidth) / 2) + 'px';
            p.style.top = Math.max(0, (window.innerHeight - p.offsetHeight) / 2) + 'px';
            p.style.display = 'flex';
            isOn = true;
            const t = document.getElementById('aekb-inp');
            if (t) setTimeout(function() { t.focus(); }, 80);
        }
        localStorage.setItem(SK, isOn ? 'true' : 'false');
    }
    // ─── Init ────────────────────────────────────────────────────────────
    function init() {
        injectCSS();
        try { GM_registerMenuCommand('Arabic keyboard', toggle); } catch (_) {}
        if (isOn) toggle();
    }
    if (document.readyState === 'loading')
        document.addEventListener('DOMContentLoaded', init);
    else
        init();
})();