| 1 |
( function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var useState = wp.element.useState; |
| 4 |
var Fragment = wp.element.Fragment; |
| 5 |
var registerBlockType = wp.blocks.registerBlockType; |
| 6 |
var __ = wp.i18n.__; |
| 7 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 8 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 9 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 10 |
var PanelBody = wp.components.PanelBody; |
| 11 |
var RangeControl = wp.components.RangeControl; |
| 12 |
var SelectControl = wp.components.SelectControl; |
| 13 |
var TextControl = wp.components.TextControl; |
| 14 |
var TextareaControl = wp.components.TextareaControl; |
| 15 |
var ToggleControl = wp.components.ToggleControl; |
| 16 |
|
| 17 |
var _tc, _tvf; |
| 18 |
Object.defineProperty(window, '_tc', { get: function () { return _tc || (_tc = window.bkbgTypographyControl); } }); |
| 19 |
Object.defineProperty(window, '_tvf', { get: function () { return _tvf || (_tvf = window.bkbgTypoCssVars); } }); |
| 20 |
function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); } |
| 21 |
function getTypoCssVars(attrs) { |
| 22 |
var v = {}; |
| 23 |
_tvf(v, 'titleTypo', attrs, '--bkue-tt-'); |
| 24 |
_tvf(v, 'subtitleTypo', attrs, '--bkue-st-'); |
| 25 |
return v; |
| 26 |
} |
| 27 |
|
| 28 |
var TABS = [ |
| 29 |
{id:'encode', label:'URL Encode'}, |
| 30 |
{id:'decode', label:'URL Decode'}, |
| 31 |
{id:'b64', label:'Base64'} |
| 32 |
]; |
| 33 |
|
| 34 |
function urlEncode(text) { return encodeURIComponent(text); } |
| 35 |
function urlDecode(text) { try { return decodeURIComponent(text); } catch(e){ return null; } } |
| 36 |
function b64Encode(text) { try { return btoa(unescape(encodeURIComponent(text))); } catch(e){ return null; } } |
| 37 |
function b64Decode(text) { try { return decodeURIComponent(escape(atob(text))); } catch(e){ return null; } } |
| 38 |
|
| 39 |
function process(mode, text) { |
| 40 |
if (!text) return {result:'', error:''}; |
| 41 |
if (mode === 'encode') return {result: urlEncode(text), error:''}; |
| 42 |
if (mode === 'decode') { |
| 43 |
var r = urlDecode(text); |
| 44 |
return r === null ? {result:'', error:'Invalid URI sequence — cannot decode.'} : {result:r, error:''}; |
| 45 |
} |
| 46 |
if (mode === 'b64') { |
| 47 |
var enc = b64Encode(text); |
| 48 |
return enc === null ? {result:'', error:'Encoding failed.'} : {result:enc, error:''}; |
| 49 |
} |
| 50 |
if (mode === 'b64dec') { |
| 51 |
var dec = b64Decode(text); |
| 52 |
return dec === null ? {result:'', error:'Invalid Base64 string — cannot decode.'} : {result:dec, error:''}; |
| 53 |
} |
| 54 |
return {result:'', error:''}; |
| 55 |
} |
| 56 |
|
| 57 |
function UEPreview(props) { |
| 58 |
var a = props.attributes; |
| 59 |
var accent = a.accentColor || '#6c3fb5'; |
| 60 |
|
| 61 |
var _tab = useState(a.defaultMode || 'encode'); |
| 62 |
var tab = _tab[0]; var setTab = _tab[1]; |
| 63 |
|
| 64 |
var _sub = useState('enc'); // enc | dec (for b64 sub-mode) |
| 65 |
var b64Sub = _sub[0]; var setB64Sub = _sub[1]; |
| 66 |
|
| 67 |
var _txt = useState(a.defaultText || ''); |
| 68 |
var text = _txt[0]; var setText = _txt[1]; |
| 69 |
|
| 70 |
var activeMode = tab === 'b64' ? (b64Sub === 'enc' ? 'b64' : 'b64dec') : tab; |
| 71 |
var proc = process(activeMode, text); |
| 72 |
|
| 73 |
var tabs = a.showBase64Tab ? TABS : TABS.slice(0,2); |
| 74 |
|
| 75 |
var tabBarStyle = {display:'flex',gap:'4px',marginBottom:'18px',background:a.tabInactiveBg||'#f3f4f6',borderRadius:(a.tabRadius||8)+'px',padding:'4px'}; |
| 76 |
var inpStyle = {width:'100%',padding:'10px 12px',borderRadius:(a.inputRadius||10)+'px',border:'1.5px solid '+(a.inputBorder||'#e5e7eb'),background:a.inputBg||'#f9fafb',color:a.inputColor||'#1f2937',fontSize:'14px',fontFamily:'ui-monospace,monospace',resize:'vertical',minHeight:((a.textareaRows||5)*1.6+2.5)+'em',boxSizing:'border-box',outline:'none',lineHeight:1.6}; |
| 77 |
var outStyle = Object.assign({},inpStyle,{background:a.outputBg||'#f3f4f6',border:'1.5px solid '+(a.outputBorder||'#e5e7eb'),color:a.outputColor||'#1f2937',cursor:'text',userSelect:'all'}); |
| 78 |
var lblStyle = {display:'block',fontSize:'12px',fontWeight:600,color:a.labelColor||'#374151',marginBottom:'5px'}; |
| 79 |
var btnStyle = {padding:'8px 18px',background:accent,color:a.btnColor||'#fff',border:'none',borderRadius:(a.inputRadius||10)+'px',fontWeight:700,cursor:'pointer',fontSize:'13px',fontFamily:'inherit'}; |
| 80 |
|
| 81 |
return el('div',{style:{paddingTop:(a.paddingTop||60)+'px',paddingBottom:(a.paddingBottom||60)+'px',background:a.sectionBg||undefined}}, |
| 82 |
el('div',{style:{background:a.cardBg||'#fff',borderRadius:(a.cardRadius||16)+'px',padding:'32px',maxWidth:(a.maxWidth||680)+'px',margin:'0 auto',boxShadow:'0 4px 24px rgba(0,0,0,.09)'}}, |
| 83 |
|
| 84 |
(a.showTitle || a.showSubtitle) && el('div',{style:{marginBottom:'22px'}}, |
| 85 |
a.showTitle && el('div',{className:'bkbg-ue-title',style:{color:a.titleColor||'#1e1b4b'}},a.title), |
| 86 |
a.showSubtitle && el('div',{className:'bkbg-ue-subtitle',style:{color:a.subtitleColor||'#6b7280'}},a.subtitle) |
| 87 |
), |
| 88 |
|
| 89 |
// Tab bar |
| 90 |
el('div',{style:tabBarStyle}, |
| 91 |
tabs.map(function(t){ |
| 92 |
var active = tab===t.id; |
| 93 |
return el('button',{key:t.id,onClick:function(){setTab(t.id);setText('');},style:{flex:1,padding:'8px',borderRadius:(a.tabRadius||8)+'px',border:'none',cursor:'pointer',fontWeight:active?700:500,fontSize:'14px',fontFamily:'inherit',background:active?(a.tabActiveBg||accent):(a.tabInactiveBg||'transparent'),color:active?(a.tabActiveColor||'#fff'):(a.tabInactiveColor||'#6b7280'),transition:'all .2s'}},t.label); |
| 94 |
}) |
| 95 |
), |
| 96 |
|
| 97 |
// Base64 sub-mode |
| 98 |
tab==='b64' && el('div',{style:{display:'flex',gap:'6px',marginBottom:'14px'}}, |
| 99 |
el('button',{onClick:function(){setB64Sub('enc');setText('');},style:{padding:'5px 14px',borderRadius:'6px',border:'1.5px solid '+(b64Sub==='enc'?accent:'#d1d5db'),background:b64Sub==='enc'?accent+'18':'#fff',color:b64Sub==='enc'?accent:'#6b7280',fontWeight:b64Sub==='enc'?700:400,cursor:'pointer',fontSize:'13px',fontFamily:'inherit'}},'Encode'), |
| 100 |
el('button',{onClick:function(){setB64Sub('dec');setText('');},style:{padding:'5px 14px',borderRadius:'6px',border:'1.5px solid '+(b64Sub==='dec'?accent:'#d1d5db'),background:b64Sub==='dec'?accent+'18':'#fff',color:b64Sub==='dec'?accent:'#6b7280',fontWeight:b64Sub==='dec'?700:400,cursor:'pointer',fontSize:'13px',fontFamily:'inherit'}},'Decode') |
| 101 |
), |
| 102 |
|
| 103 |
// Input |
| 104 |
el('div',{style:{marginBottom:'16px'}}, |
| 105 |
el('label',{style:lblStyle},tab==='b64'?'Input Text':(tab==='encode'?'Text to Encode':'Encoded URL')), |
| 106 |
el('textarea',{value:text,onChange:function(e){setText(e.target.value);},placeholder:a.defaultText,rows:a.textareaRows||5,style:inpStyle}) |
| 107 |
), |
| 108 |
|
| 109 |
// Char count |
| 110 |
a.showCharCount && el('div',{style:{textAlign:'right',fontSize:'12px',color:'#9ca3af',marginTop:'-12px',marginBottom:'12px'}}, |
| 111 |
(text||'').length,' characters' |
| 112 |
), |
| 113 |
|
| 114 |
// Error |
| 115 |
proc.error && el('div',{style:{background:a.errorBg||'#fef2f2',border:'1px solid '+(a.errorColor||'#ef4444'),color:a.errorColor||'#ef4444',padding:'10px 14px',borderRadius:'8px',fontSize:'14px',marginBottom:'12px'}},proc.error), |
| 116 |
|
| 117 |
// Output |
| 118 |
el('div',{style:{marginBottom:'14px'}}, |
| 119 |
el('label',{style:lblStyle},'Result'), |
| 120 |
el('textarea',{readOnly:true,value:proc.result,rows:a.textareaRows||5,style:outStyle}) |
| 121 |
), |
| 122 |
|
| 123 |
a.showCharCount && el('div',{style:{textAlign:'right',fontSize:'12px',color:'#9ca3af',marginTop:'-10px',marginBottom:'12px'}}, |
| 124 |
(proc.result||'').length,' characters' |
| 125 |
), |
| 126 |
|
| 127 |
// Buttons row |
| 128 |
el('div',{style:{display:'flex',gap:'8px',flexWrap:'wrap'}}, |
| 129 |
a.showCopyButton && el('button',{style:btnStyle},'Copy Result'), |
| 130 |
a.showClearButton && el('button',{onClick:function(){setText('');},style:{...btnStyle,background:'#f3f4f6',color:'#374151'}},'Clear') |
| 131 |
) |
| 132 |
) |
| 133 |
); |
| 134 |
} |
| 135 |
|
| 136 |
registerBlockType('blockenberg/url-encoder', { |
| 137 |
edit: function(props) { |
| 138 |
var a = props.attributes; var set = props.setAttributes; |
| 139 |
var blockProps = useBlockProps((function () { var _tv = getTypoCssVars(a); return { style: _tv }; })()); |
| 140 |
var colorSettings = [ |
| 141 |
{value:a.accentColor, onChange:function(v){set({accentColor:v});}, label:'Accent Color'}, |
| 142 |
{value:a.cardBg, onChange:function(v){set({cardBg:v});}, label:'Card Background'}, |
| 143 |
{value:a.tabActiveBg, onChange:function(v){set({tabActiveBg:v});}, label:'Active Tab Background'}, |
| 144 |
{value:a.tabActiveColor, onChange:function(v){set({tabActiveColor:v});}, label:'Active Tab Text'}, |
| 145 |
{value:a.tabInactiveBg, onChange:function(v){set({tabInactiveBg:v});}, label:'Inactive Tab Background'}, |
| 146 |
{value:a.tabInactiveColor, onChange:function(v){set({tabInactiveColor:v});}, label:'Inactive Tab Text'}, |
| 147 |
{value:a.inputBg, onChange:function(v){set({inputBg:v});}, label:'Input Background'}, |
| 148 |
{value:a.inputBorder, onChange:function(v){set({inputBorder:v});}, label:'Input Border'}, |
| 149 |
{value:a.inputColor, onChange:function(v){set({inputColor:v});}, label:'Input Text Color'}, |
| 150 |
{value:a.outputBg, onChange:function(v){set({outputBg:v});}, label:'Output Background'}, |
| 151 |
{value:a.outputBorder, onChange:function(v){set({outputBorder:v});}, label:'Output Border'}, |
| 152 |
{value:a.outputColor, onChange:function(v){set({outputColor:v});}, label:'Output Text Color'}, |
| 153 |
{value:a.errorColor, onChange:function(v){set({errorColor:v});}, label:'Error Text Color'}, |
| 154 |
{value:a.errorBg, onChange:function(v){set({errorBg:v});}, label:'Error Background'}, |
| 155 |
{value:a.btnBg, onChange:function(v){set({btnBg:v});}, label:'Button Background'}, |
| 156 |
{value:a.btnColor, onChange:function(v){set({btnColor:v});}, label:'Button Text'}, |
| 157 |
{value:a.labelColor, onChange:function(v){set({labelColor:v});}, label:'Label Color'}, |
| 158 |
{value:a.titleColor, onChange:function(v){set({titleColor:v});}, label:'Title Color'}, |
| 159 |
{value:a.subtitleColor, onChange:function(v){set({subtitleColor:v});}, label:'Subtitle Color'}, |
| 160 |
{value:a.sectionBg, onChange:function(v){set({sectionBg:v});}, label:'Section Background'} |
| 161 |
]; |
| 162 |
return el(Fragment, null, |
| 163 |
el(InspectorControls, null, |
| 164 |
el(PanelBody,{title:'Header',initialOpen:false}, |
| 165 |
el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Title', checked:a.showTitle, onChange:function(v){set({showTitle:v});}}), |
| 166 |
el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Subtitle',checked:a.showSubtitle,onChange:function(v){set({showSubtitle:v});}}), |
| 167 |
el(TextControl,{label:'Title', value:a.title, onChange:function(v){set({title:v});}}), |
| 168 |
el(TextControl,{label:'Subtitle',value:a.subtitle,onChange:function(v){set({subtitle:v});}}) |
| 169 |
), |
| 170 |
el(PanelBody,{title:'Encoder Settings',initialOpen:true}, |
| 171 |
el(SelectControl,{label:'Default Tab',value:a.defaultMode,options:[{label:'URL Encode',value:'encode'},{label:'URL Decode',value:'decode'},{label:'Base64',value:'b64'}],onChange:function(v){set({defaultMode:v});}}), |
| 172 |
el(TextareaControl,{label:'Default Input Text',value:a.defaultText,onChange:function(v){set({defaultText:v});},rows:3}), |
| 173 |
el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Base64 Tab', checked:a.showBase64Tab, onChange:function(v){set({showBase64Tab:v});}}), |
| 174 |
el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Copy Button', checked:a.showCopyButton, onChange:function(v){set({showCopyButton:v});}}), |
| 175 |
el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Clear Button', checked:a.showClearButton,onChange:function(v){set({showClearButton:v});}}), |
| 176 |
el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Char Count', checked:a.showCharCount, onChange:function(v){set({showCharCount:v});}}) |
| 177 |
), |
| 178 |
|
| 179 |
el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false }, |
| 180 |
getTypoControl(__('Title', 'blockenberg'), 'titleTypo', a, set), |
| 181 |
getTypoControl(__('Subtitle', 'blockenberg'), 'subtitleTypo', a, set) |
| 182 |
), |
| 183 |
el(PanelColorSettings,{title:'Colors',initialOpen:false,colorSettings:colorSettings}), |
| 184 |
el(PanelBody,{title:'Sizing & Layout',initialOpen:false}, |
| 185 |
el(RangeControl,{label:'Textarea Rows', value:a.textareaRows, min:3, max:16,step:1, onChange:function(v){set({textareaRows:v});}}), |
| 186 |
el(RangeControl,{label:'Card Border Radius',value:a.cardRadius, min:0, max:40,step:1, onChange:function(v){set({cardRadius:v});}}), |
| 187 |
el(RangeControl,{label:'Input Border Radius',value:a.inputRadius, min:0, max:20,step:1, onChange:function(v){set({inputRadius:v});}}), |
| 188 |
el(RangeControl,{label:'Tab Border Radius', value:a.tabRadius, min:0, max:20,step:1, onChange:function(v){set({tabRadius:v});}}), |
| 189 |
el(RangeControl,{label:'Max Width (px)', value:a.maxWidth, min:360,max:1100,step:10,onChange:function(v){set({maxWidth:v});}}), |
| 190 |
el(RangeControl,{label:'Padding Top', value:a.paddingTop, min:0, max:160,step:4, onChange:function(v){set({paddingTop:v});}}), |
| 191 |
el(RangeControl,{label:'Padding Bottom', value:a.paddingBottom,min:0, max:160,step:4, onChange:function(v){set({paddingBottom:v});}}) |
| 192 |
) |
| 193 |
), |
| 194 |
el('div', blockProps, el(UEPreview, {attributes:a})) |
| 195 |
); |
| 196 |
}, |
| 197 |
save: function(props) { |
| 198 |
var a = props.attributes; |
| 199 |
return el('div', wp.blockEditor.useBlockProps.save((function () { var _tv = getTypoCssVars(a); return { style: _tv }; })()), |
| 200 |
el('div',{className:'bkbg-ue-app','data-opts':JSON.stringify(a)})); |
| 201 |
} |
| 202 |
}); |
| 203 |
}() ); |
| 204 |
|