mirror of
https://github.com/elder-plinius/P4RS3LT0NGV3.git
synced 2026-02-12 16:52:46 +00:00
Transforms: add QWERTY Left Shift, Base32 Crockford, Hex Compact Uppercase, Bitflip+Base64; register categories
This commit is contained in:
@@ -229,10 +229,6 @@ h1, h2, h3, h4, h5 {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
/* Safety: hide all tab-content until Vue mounts and activates one */
|
||||
/* Remove aggressive v-cloak hiding to avoid blank app if Vue fails */
|
||||
/* [v-cloak] .tab-content { display: none; } */
|
||||
|
||||
/* Input and output sections */
|
||||
.input-section,
|
||||
.output-section,
|
||||
|
||||
19
js/app.js
19
js/app.js
@@ -14,15 +14,15 @@ window.app = new Vue({
|
||||
activeTransform: null,
|
||||
// Transform categories for styling
|
||||
transformCategories: {
|
||||
encoding: ['Base64', 'Base64 URL', 'Base32', 'Base45', 'Base58', 'Base62', 'Base85 (Z85)', 'Base91', 'Binary', 'Hexadecimal', 'ASCII85', 'URL Encode', 'HTML Entities', 'Quoted-Printable'],
|
||||
encoding: ['Base64', 'Base64 URL', 'Base32', 'Base32 Crockford', 'Base45', 'Base58', 'Base62', 'Base85 (Z85)', 'Base91', 'Binary', 'Hexadecimal', 'Hex (Compact Uppercase)', 'ASCII85', 'URL Encode', 'HTML Entities', 'Quoted-Printable', 'Bitflip (NOT)+Base64'],
|
||||
cipher: ['Caesar Cipher', 'ROT13', 'ROT47', 'Morse Code', 'Atbash Cipher', 'ROT5', 'Vigenère Cipher', 'Rail Fence (3 Rails)', 'Rail Fence (5 Rails)', 'XOR Cipher (KEY)'],
|
||||
visual: ['Rainbow Text', 'Strikethrough', 'Underline', 'Reverse Text', 'Alternating Case', 'Reverse Words', 'Random Case', 'Swap Case', 'Title Case', 'Sentence Case', 'Emoji Speak'],
|
||||
format: ['Pig Latin', 'Leetspeak', 'Ubbi Dubbi', 'Rövarspråket', 'NATO Phonetic', 'camelCase', 'snake_case', 'kebab-case', 'Squash Whitespace'],
|
||||
format: ['Pig Latin', 'Ubbi Dubbi', 'Rövarspråket', 'NATO Phonetic', 'camelCase', 'snake_case', 'kebab-case', 'Squash Whitespace'],
|
||||
unicode: ['Invisible Text', 'Upside Down', 'Full Width', 'Small Caps', 'Bubble', 'Braille', 'Greek Letters', 'Wingdings', 'Superscript', 'Subscript', 'Regional Indicator Letters', 'Fraktur', 'Cyrillic Stylized', 'Katakana', 'Hiragana', 'Roman Numerals'],
|
||||
special: ['Medieval', 'Cursive', 'Monospace', 'Double-Struck', 'Elder Futhark', 'Mirror Text', 'Zalgo', 'Unicode Normalize (NFC)', 'Unicode Normalize (NFD)', 'Strip Diacritics', 'Unicode Escape (\\u)'],
|
||||
special: ['Medieval', 'Cursive', 'Monospace', 'Double-Struck', 'Elder Futhark', 'Mirror Text', 'Zalgo', 'Unicode Normalize (NFC)', 'Unicode Normalize (NFD)', 'Strip Diacritics', 'Unicode Escape (\u)'],
|
||||
fantasy: ['Quenya (Tolkien Elvish)', 'Tengwar Script', 'Klingon', 'Aurebesh (Star Wars)', 'Dovahzul (Dragon)'],
|
||||
ancient: ['Hieroglyphics', 'Ogham (Celtic)', 'Semaphore Flags'],
|
||||
technical: ['Brainfuck', 'Mathematical Notation', 'Chemical Symbols'],
|
||||
technical: ['Brainfuck', 'Mathematical Notation', 'Chemical Symbols', 'QWERTY Right Shift', 'QWERTY Left Shift', 'QWERTY ↔ Dvorak'],
|
||||
randomizer: ['Random Mix']
|
||||
},
|
||||
transforms: Object.entries(window.transforms).map(([key, transform]) => ({
|
||||
@@ -145,9 +145,8 @@ window.app = new Vue({
|
||||
const emojiGridContainer = document.getElementById('emoji-grid-container');
|
||||
if (emojiGridContainer) {
|
||||
console.log('Found emoji grid container after tab switch');
|
||||
// Only set local sizing, do not force global display states
|
||||
emojiGridContainer.style.minHeight = '300px';
|
||||
emojiGridContainer.style.padding = '10px';
|
||||
// Make sure the container is visible
|
||||
emojiGridContainer.setAttribute('style', 'display: block !important; visibility: visible !important; min-height: 300px; padding: 10px;');
|
||||
// Render the emoji grid
|
||||
this.renderEmojiGrid();
|
||||
} else {
|
||||
@@ -1634,13 +1633,13 @@ window.app = new Vue({
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure container sizing only; do not force global display state
|
||||
container.style.minHeight = '300px';
|
||||
// Force container to be completely visible
|
||||
container.style.cssText = 'display: block !important; visibility: visible !important; min-height: 300px;';
|
||||
|
||||
// Make sure parent containers are visible too
|
||||
const emojiLibrary = document.querySelector('.emoji-library');
|
||||
if (emojiLibrary) {
|
||||
// No-op: keep default visibility controlled by Vue
|
||||
emojiLibrary.style.cssText = 'display: block !important; visibility: visible !important;';
|
||||
}
|
||||
|
||||
// Clear any existing content to avoid duplication
|
||||
|
||||
130
js/transforms.js
130
js/transforms.js
@@ -15,17 +15,18 @@ const transforms = {
|
||||
},
|
||||
reverse: function(text) {
|
||||
if (!text) return '';
|
||||
const matches = [...text.matchAll(/[\uE0000-\uE007F]/g)];
|
||||
if (!matches.length) return '';
|
||||
const bytes = new Uint8Array(matches.length);
|
||||
for (let i=0;i<matches.length;i++) {
|
||||
bytes[i] = matches[i][0].codePointAt(0) - 0xE0000;
|
||||
const bytesArr = [];
|
||||
for (const ch of Array.from(text)) {
|
||||
const cp = ch.codePointAt(0);
|
||||
if (cp >= 0xE0000 && cp <= 0xE007F) bytesArr.push(cp - 0xE0000);
|
||||
}
|
||||
if (!bytesArr.length) return '';
|
||||
const bytes = new Uint8Array(bytesArr);
|
||||
try {
|
||||
return new TextDecoder().decode(bytes);
|
||||
} catch (_) {
|
||||
// Fallback: direct char mapping
|
||||
return Array.from(bytes).map(b => String.fromCharCode(b)).join('');
|
||||
return Array.from(bytesArr).map(b => String.fromCharCode(b)).join('');
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -309,6 +310,23 @@ const transforms = {
|
||||
return result;
|
||||
}
|
||||
},
|
||||
// Hex (compact uppercase)
|
||||
hex_compact: {
|
||||
name: 'Hex (Compact Uppercase)',
|
||||
func: function(text) {
|
||||
const bytes = new TextEncoder().encode(text || '');
|
||||
return Array.from(bytes).map(b => b.toString(16).toUpperCase().padStart(2,'0')).join('');
|
||||
},
|
||||
preview: function(text) { return this.func(text || 'Hi'); },
|
||||
reverse: function(text) {
|
||||
const s = (text || '').replace(/\s+/g,'');
|
||||
const out = [];
|
||||
for (let i=0;i<s.length;i+=2) {
|
||||
const byte = s.substr(i,2); if (byte.length===2) out.push(parseInt(byte,16));
|
||||
}
|
||||
return new TextDecoder().decode(Uint8Array.from(out));
|
||||
}
|
||||
},
|
||||
|
||||
caesar: {
|
||||
name: 'Caesar Cipher',
|
||||
@@ -452,10 +470,7 @@ const transforms = {
|
||||
name: 'Strikethrough',
|
||||
func: function(text) {
|
||||
// Use proper Unicode combining characters for strikethrough
|
||||
const splitter = (typeof window !== 'undefined' && window.emojiLibrary && window.emojiLibrary.splitEmojis)
|
||||
? window.emojiLibrary.splitEmojis
|
||||
: (t) => Array.from(t);
|
||||
const segments = splitter(text);
|
||||
const segments = window.emojiLibrary.splitEmojis(text);
|
||||
return segments.map(c => c + '\u0336').join('');
|
||||
},
|
||||
preview: function(text) {
|
||||
@@ -472,10 +487,7 @@ const transforms = {
|
||||
name: 'Underline',
|
||||
func: function(text) {
|
||||
// Use proper Unicode combining characters for underline
|
||||
const splitter = (typeof window !== 'undefined' && window.emojiLibrary && window.emojiLibrary.splitEmojis)
|
||||
? window.emojiLibrary.splitEmojis
|
||||
: (t) => Array.from(t);
|
||||
const segments = splitter(text);
|
||||
const segments = window.emojiLibrary.splitEmojis(text);
|
||||
return segments.map(c => c + '\u0332').join('');
|
||||
},
|
||||
preview: function(text) {
|
||||
@@ -824,7 +836,7 @@ const transforms = {
|
||||
value = (value << 8) | bytes[i];
|
||||
bits += 8;
|
||||
|
||||
while (bits >= 5) {
|
||||
while (bits >= 5) {
|
||||
bits -= 5;
|
||||
result += this.alphabet[(value >> bits) & 0x1F];
|
||||
}
|
||||
@@ -882,6 +894,39 @@ const transforms = {
|
||||
}
|
||||
},
|
||||
|
||||
// Base32 Crockford (no padding, normalized decode)
|
||||
base32_crockford: {
|
||||
name: 'Base32 Crockford',
|
||||
alphabet: '0123456789ABCDEFGHJKMNPQRSTVWXYZ',
|
||||
func: function(text) {
|
||||
if (!text) return '';
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
let result = '';
|
||||
let bits = 0, value = 0;
|
||||
for (let i=0;i<bytes.length;i++) {
|
||||
value = (value << 8) | bytes[i]; bits += 8;
|
||||
while (bits >= 5) { bits -= 5; result += this.alphabet[(value >> bits) & 0x1F]; }
|
||||
}
|
||||
if (bits > 0) result += this.alphabet[(value << (5 - bits)) & 0x1F];
|
||||
return result;
|
||||
},
|
||||
preview: function(text) { return this.func(text || 'hi'); },
|
||||
reverse: function(text) {
|
||||
if (!text) return '';
|
||||
const norm = String(text).toUpperCase().replace(/[IL]/g,'1').replace(/[O]/g,'0').replace(/[-_\s]/g,'');
|
||||
const map = {};
|
||||
for (let i=0;i<this.alphabet.length;i++) map[this.alphabet[i]] = i;
|
||||
let result = '';
|
||||
let bits = 0, value = 0;
|
||||
for (let i=0;i<norm.length;i++) {
|
||||
const v = map[norm[i]]; if (v === undefined) continue;
|
||||
value = (value << 5) | v; bits += 5;
|
||||
while (bits >= 8) { bits -= 8; result += String.fromCharCode((value >> bits) & 0xFF); }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
greek: {
|
||||
name: 'Greek Letters',
|
||||
map: {
|
||||
@@ -1314,6 +1359,27 @@ const transforms = {
|
||||
}
|
||||
},
|
||||
|
||||
// Bitflip (NOT) + Base64
|
||||
bitflip_b64: {
|
||||
name: 'Bitflip (NOT)+Base64',
|
||||
func: function(text) {
|
||||
if (!text) return '';
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
const flipped = new Uint8Array(bytes.length);
|
||||
for (let i=0;i<bytes.length;i++) flipped[i] = bytes[i] ^ 0xFF;
|
||||
let bin = ''; for (let i=0;i<flipped.length;i++) bin += String.fromCharCode(flipped[i]);
|
||||
return btoa(bin);
|
||||
},
|
||||
preview: function(text) { return this.func(text || 'flip'); },
|
||||
reverse: function(text) {
|
||||
try {
|
||||
const bin = atob(text || '');
|
||||
const bytes = new Uint8Array(bin.length);
|
||||
for (let i=0;i<bin.length;i++) bytes[i] = bin.charCodeAt(i) ^ 0xFF;
|
||||
return new TextDecoder().decode(bytes);
|
||||
} catch (e) { return text; }
|
||||
}
|
||||
},
|
||||
// Base85 (Z85 variant)
|
||||
base85_z85: {
|
||||
name: 'Base85 (Z85)',
|
||||
@@ -1807,6 +1873,40 @@ const transforms = {
|
||||
return [...text].map(c => inv[c] || c).join('');
|
||||
}
|
||||
},
|
||||
// QWERTY Left-Shift (maps to previous key on same row)
|
||||
qwerty_left_shift: {
|
||||
name: 'QWERTY Left Shift',
|
||||
rows: [
|
||||
'qwertyuiop',
|
||||
'asdfghjkl',
|
||||
'zxcvbnm'
|
||||
],
|
||||
buildMap: function() {
|
||||
if (this._map) return this._map;
|
||||
const map = {};
|
||||
for (const row of this.rows) {
|
||||
for (let i=0;i<row.length;i++) {
|
||||
const from = row[i], to = row[(i-1+row.length)%row.length];
|
||||
map[from] = to;
|
||||
map[from.toUpperCase()] = to.toUpperCase();
|
||||
}
|
||||
}
|
||||
this._map = map; return map;
|
||||
},
|
||||
func: function(text) {
|
||||
const m = this.buildMap();
|
||||
return [...text].map(c => m[c] || c).join('');
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[qwerty←]';
|
||||
return this.func(text.slice(0,8)) + (text.length>8?'...':'');
|
||||
},
|
||||
reverse: function(text) {
|
||||
const m = this.buildMap();
|
||||
const inv = {}; Object.keys(m).forEach(k => inv[m[k]] = k);
|
||||
return [...text].map(c => inv[c] || c).join('');
|
||||
}
|
||||
},
|
||||
|
||||
// Case/formatting transforms
|
||||
title_case: {
|
||||
|
||||
Reference in New Issue
Block a user