Merge 55b4a8ce57 into 07eea0f484
				
					
				
			This commit is contained in:
		
						commit
						857c8e86c7
					
				
							
								
								
									
										14258
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14258
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -128,7 +128,7 @@ function activateOption(option: PaletteOption) { | ||||
|       <c-input-text ref="inputRef" v-model:value="searchPrompt" raw-text placeholder="Type to search a tool or a command..." autofocus clearable /> | ||||
| 
 | ||||
|       <div v-for="(options, category) in filteredSearchResult" :key="category"> | ||||
|         <div ml-3 mt-3 text-sm font-bold text-primary op-60> | ||||
|         <div ml-3 mt-3 text-sm text-primary font-bold op-60> | ||||
|           {{ category }} | ||||
|         </div> | ||||
|         <command-palette-option v-for="option in options" :key="option.name" :option="option" :selected="selectedOptionIndex === getOptionIndex(option)" @activated="activateOption" /> | ||||
|  | ||||
| @ -1,11 +1,10 @@ | ||||
| import { Link } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: translate('tools.url-encoder.title'), | ||||
|   name: 'Encode/decode url formatted strings', | ||||
|   path: '/url-encoder', | ||||
|   description: translate('tools.url-encoder.description'), | ||||
|   description: 'Encode to url-encoded format (also known as "percent-encoded") or decode from it.', | ||||
|   keywords: ['url', 'encode', 'decode', 'percent', '%20', 'format'], | ||||
|   component: () => import('./url-encoder.vue'), | ||||
|   icon: Link, | ||||
|  | ||||
| @ -1,17 +1,82 @@ | ||||
| <script setup lang="ts"> | ||||
| import { useCopy } from '@/composable/copy'; | ||||
| import { useQueryParamOrStorage } from '@/composable/queryParams'; | ||||
| import { useValidation } from '@/composable/validation'; | ||||
| import { isNotThrowing } from '@/utils/boolean'; | ||||
| import { withDefaultOnError } from '@/utils/defaults'; | ||||
| 
 | ||||
| const encodings = [ | ||||
|   { value: 'URIComponent', label: 'URIComponent' }, | ||||
|   { value: 'RFC3986URIComponent', label: 'RFC3986 - URIComponent' }, | ||||
|   { value: 'RFC5987', label: 'RFC5987 (Link - Content-Disposition)' }, | ||||
|   { value: 'URI', label: 'URI' }, | ||||
|   { value: 'RFC3986URI', label: 'RFC3986 - URI' }, | ||||
| ]; | ||||
| const encoding = useQueryParamOrStorage({ name: 'enc', storageName: 'url-encode:enc', defaultValue: 'URIComponent' }); | ||||
| 
 | ||||
| function encodeRFC3986URIComponent(str: string) { | ||||
|   return encodeURIComponent(str).replace( | ||||
|     /[!'()*]/g, | ||||
|     (c: string) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`, | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function encodeRFC5987ValueChars(str: string) { | ||||
|   return ( | ||||
|     encodeURIComponent(str) | ||||
|       // The following creates the sequences %27 %28 %29 %2A (Note that | ||||
|       // the valid encoding of "*" is %2A, which necessitates calling | ||||
|       // toUpperCase() to properly encode). Although RFC3986 reserves "!", | ||||
|       // RFC5987 does not, so we do not need to escape it. | ||||
|       .replace( | ||||
|         /['()*]/g, | ||||
|         c => `%${c.charCodeAt(0).toString(16).toUpperCase()}`, | ||||
|       ) | ||||
|       // The following are not required for percent-encoding per RFC5987, | ||||
|       // so we can allow for a little better readability over the wire: |`^ | ||||
|       .replace(/%(7C|60|5E)/g, (str, hex) => | ||||
|         String.fromCharCode(Number.parseInt(hex, 16)), | ||||
|       ) | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function encodeRFC3986URI(str: string) { | ||||
|   return encodeURI(str) | ||||
|     .replace(/%5B/g, '[') | ||||
|     .replace(/%5D/g, ']') | ||||
|     .replace( | ||||
|       /[!'()*]/g, | ||||
|       c => `%${c.charCodeAt(0).toString(16).toUpperCase()}`, | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| function encode(str: string) { | ||||
|   if (encoding.value === 'URIComponent') { | ||||
|     return encodeURIComponent(str); | ||||
|   } | ||||
|   if (encoding.value === 'RFC3986URIComponent') { | ||||
|     return encodeRFC3986URIComponent(str); | ||||
|   } | ||||
|   if (encoding.value === 'RFC5987') { | ||||
|     return encodeRFC5987ValueChars(str); | ||||
|   } | ||||
|   if (encoding.value === 'URI') { | ||||
|     return encodeURI(str); | ||||
|   } | ||||
|   if (encoding.value === 'RFC3986URI') { | ||||
|     return encodeRFC3986URI(str); | ||||
|   } | ||||
|   return str; | ||||
| } | ||||
| 
 | ||||
| const encodeInput = ref('Hello world :)'); | ||||
| const encodeOutput = computed(() => withDefaultOnError(() => encodeURIComponent(encodeInput.value), '')); | ||||
| const encodeOutput = computed(() => withDefaultOnError(() => encode(encodeInput.value), '')); | ||||
| 
 | ||||
| const encodedValidation = useValidation({ | ||||
|   source: encodeInput, | ||||
|   rules: [ | ||||
|     { | ||||
|       validator: value => isNotThrowing(() => encodeURIComponent(value)), | ||||
|       validator: value => isNotThrowing(() => encode(value)), | ||||
|       message: 'Impossible to parse this string', | ||||
|     }, | ||||
|   ], | ||||
| @ -23,7 +88,7 @@ const decodeInput = ref('Hello%20world%20%3A)'); | ||||
| const decodeOutput = computed(() => withDefaultOnError(() => decodeURIComponent(decodeInput.value), '')); | ||||
| 
 | ||||
| const decodeValidation = useValidation({ | ||||
|   source: decodeInput, | ||||
|   source: encodeInput, | ||||
|   rules: [ | ||||
|     { | ||||
|       validator: value => isNotThrowing(() => decodeURIComponent(value)), | ||||
| @ -37,6 +102,15 @@ const { copy: copyDecoded } = useCopy({ source: decodeOutput, text: 'Decoded str | ||||
| 
 | ||||
| <template> | ||||
|   <c-card title="Encode"> | ||||
|     <c-select | ||||
|       v-model:value="encoding" | ||||
|       label="Encoding Kind:" | ||||
|       label-position="left" | ||||
|       :options="encodings" | ||||
|     /> | ||||
| 
 | ||||
|     <n-divider /> | ||||
| 
 | ||||
|     <c-input-text | ||||
|       v-model:value="encodeInput" | ||||
|       label="Your string :" | ||||
|  | ||||
| @ -151,7 +151,7 @@ function onSearchInput() { | ||||
|       > | ||||
|         <div flex-1 truncate> | ||||
|           <slot name="displayed-value"> | ||||
|             <input v-if="searchable && isOpen" ref="searchInputRef" v-model="searchQuery" type="text" placeholder="Search..." class="search-input" w-full lh-normal color-current @input="onSearchInput"> | ||||
|             <input v-if="searchable && isOpen" ref="searchInputRef" v-model="searchQuery" type="text" placeholder="Search..." class="search-input" w-full color-current lh-normal @input="onSearchInput"> | ||||
|             <span v-else-if="selectedOption" lh-normal> | ||||
|               {{ selectedOption.label }} | ||||
|             </span> | ||||
|  | ||||
| @ -39,7 +39,7 @@ const headers = computed(() => { | ||||
| <template> | ||||
|   <div class="relative overflow-x-auto rounded"> | ||||
|     <table class="w-full border-collapse text-left text-sm text-gray-500 dark:text-gray-400" role="table" :aria-label="description"> | ||||
|       <thead v-if="!hideHeaders" class="bg-#ffffff uppercase text-gray-700 dark:bg-#333333 dark:text-gray-400" border-b="1px solid dark:transparent #efeff5"> | ||||
|       <thead v-if="!hideHeaders" class="bg-#ffffff text-gray-700 uppercase dark:bg-#333333 dark:text-gray-400" border-b="1px solid dark:transparent #efeff5"> | ||||
|         <tr> | ||||
|           <th v-for="header in headers" :key="header.key" scope="col" class="px-6 py-3 text-xs"> | ||||
|             {{ header.label }} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user