mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-05 13:57:10 -04:00
Merge b779beb695
into a07806cd15
This commit is contained in:
commit
cf693f09c0
5 changed files with 219 additions and 0 deletions
|
@ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter';
|
||||||
import { tool as base64StringConverter } from './base64-string-converter';
|
import { tool as base64StringConverter } from './base64-string-converter';
|
||||||
import { tool as basicAuthGenerator } from './basic-auth-generator';
|
import { tool as basicAuthGenerator } from './basic-auth-generator';
|
||||||
import { tool as textToUnicode } from './text-to-unicode';
|
import { tool as textToUnicode } from './text-to-unicode';
|
||||||
|
import { tool as urlTextFragmentMaker } from './url-text-fragment-maker';
|
||||||
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
|
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
|
||||||
import { tool as numeronymGenerator } from './numeronym-generator';
|
import { tool as numeronymGenerator } from './numeronym-generator';
|
||||||
import { tool as macAddressGenerator } from './mac-address-generator';
|
import { tool as macAddressGenerator } from './mac-address-generator';
|
||||||
|
@ -111,6 +112,7 @@ export const toolsByCategory: ToolCategory[] = [
|
||||||
urlEncoder,
|
urlEncoder,
|
||||||
htmlEntities,
|
htmlEntities,
|
||||||
urlParser,
|
urlParser,
|
||||||
|
urlTextFragmentMaker,
|
||||||
deviceInformation,
|
deviceInformation,
|
||||||
basicAuthGenerator,
|
basicAuthGenerator,
|
||||||
metaTagGenerator,
|
metaTagGenerator,
|
||||||
|
|
12
src/tools/url-text-fragment-maker/index.ts
Normal file
12
src/tools/url-text-fragment-maker/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { FileSearch } from '@vicons/tabler';
|
||||||
|
import { defineTool } from '../tool';
|
||||||
|
|
||||||
|
export const tool = defineTool({
|
||||||
|
name: 'Url Text Search Fragment Maker',
|
||||||
|
path: '/url-text-fragment-maker',
|
||||||
|
description: 'Create url that allows linking directly to a specific portion of text in a web document',
|
||||||
|
keywords: ['url', 'text', 'fragment'],
|
||||||
|
component: () => import('./url-text-fragment-maker.vue'),
|
||||||
|
icon: FileSearch,
|
||||||
|
createdAt: new Date('2024-01-17'),
|
||||||
|
});
|
|
@ -0,0 +1,76 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { getUrlWithTextFragment } from './url-text-fragment-maker.service';
|
||||||
|
|
||||||
|
describe('url-text-fragment-maker.service', () => {
|
||||||
|
describe('getUrlWithTextFragment', () => {
|
||||||
|
describe('compute url with text fragment', () => {
|
||||||
|
it('throws on invalid url', () => {
|
||||||
|
expect(() => getUrlWithTextFragment({
|
||||||
|
url: 'example',
|
||||||
|
textStartSearch: 'for',
|
||||||
|
})).toThrow('Invalid url');
|
||||||
|
expect(() => getUrlWithTextFragment({
|
||||||
|
url: 'htt://example',
|
||||||
|
textStartSearch: 'for',
|
||||||
|
})).toThrow('Url must have http:// or https:// prefix');
|
||||||
|
expect(() => getUrlWithTextFragment({
|
||||||
|
url: 'http:/example',
|
||||||
|
textStartSearch: 'for',
|
||||||
|
})).toThrow('Url must have http:// or https:// prefix');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle basic cases', () => {
|
||||||
|
expect(getUrlWithTextFragment({
|
||||||
|
url: 'https://example.com',
|
||||||
|
textStartSearch: 'for',
|
||||||
|
}))
|
||||||
|
.toBe('https://example.com#:~:text=for');
|
||||||
|
expect(getUrlWithTextFragment({
|
||||||
|
url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a',
|
||||||
|
textStartSearch: 'human',
|
||||||
|
}))
|
||||||
|
.toBe('https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#:~:text=human');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be url encoded', () => {
|
||||||
|
expect(getUrlWithTextFragment({
|
||||||
|
url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a',
|
||||||
|
textStartSearch: 'linked URL',
|
||||||
|
suffixSearch: '\'s format',
|
||||||
|
}))
|
||||||
|
.toBe('https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#:~:text=linked%20URL,-\'s%20format');
|
||||||
|
expect(getUrlWithTextFragment({
|
||||||
|
url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a',
|
||||||
|
textStartSearch: 'The Referer',
|
||||||
|
textStopSearch: 'be sent',
|
||||||
|
prefixSearch: 'downgrade:',
|
||||||
|
suffixSearch: 'to origins',
|
||||||
|
}))
|
||||||
|
.toBe('https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#:~:text=downgrade%3A-,The%20Referer,be%20sent,-to%20origins');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle multiple comma separated and encoded', () => {
|
||||||
|
expect(
|
||||||
|
getUrlWithTextFragment({
|
||||||
|
url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a',
|
||||||
|
textStartSearch: 'Causes,linked',
|
||||||
|
}))
|
||||||
|
.toBe('https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#:~:text=Causes&text=linked');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getUrlWithTextFragment({
|
||||||
|
url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a',
|
||||||
|
textStartSearch: 'Causes 1,linked 1',
|
||||||
|
}))
|
||||||
|
.toBe('https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#:~:text=Causes%201&text=linked%201');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getUrlWithTextFragment({
|
||||||
|
url: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a',
|
||||||
|
textStartSearch: 'Causes , linked',
|
||||||
|
}))
|
||||||
|
.toBe('https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#:~:text=Causes&text=linked');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,35 @@
|
||||||
|
export function getUrlWithTextFragment(
|
||||||
|
{ url, textStartSearch, textStopSearch, prefixSearch, suffixSearch }:
|
||||||
|
{ url: string
|
||||||
|
textStartSearch: string
|
||||||
|
textStopSearch?: string
|
||||||
|
prefixSearch?: string
|
||||||
|
suffixSearch?: string
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const isValidUrl = (urlString: string) => {
|
||||||
|
try {
|
||||||
|
return Boolean(new URL(urlString));
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!isValidUrl(url)) {
|
||||||
|
throw new Error('Invalid url');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!url.match(/^https?:\/\//)) {
|
||||||
|
throw new Error('Url must have http:// or https:// prefix');
|
||||||
|
}
|
||||||
|
|
||||||
|
const [textStartSearchFirstText, ...textStartSearchOtherTexts] = textStartSearch.split(',');
|
||||||
|
const text = `${encodeURIComponent(prefixSearch ?? '')}-,${encodeURIComponent(textStartSearchFirstText.trim())},${encodeURIComponent(textStopSearch ?? '')},-${encodeURIComponent(suffixSearch ?? '')}`
|
||||||
|
.replace(/^-,|,(?=,)|,-$/g, '')
|
||||||
|
.replace(/,+/g, ',');
|
||||||
|
let textStartSearchOtherTextEncoded = textStartSearchOtherTexts.map(t => `text=${encodeURIComponent(t.trim())}`).join('&');
|
||||||
|
if (textStartSearchOtherTextEncoded.length) {
|
||||||
|
textStartSearchOtherTextEncoded = `&${textStartSearchOtherTextEncoded}`;
|
||||||
|
}
|
||||||
|
return `${url.trim()}#:~:text=${text}${textStartSearchOtherTextEncoded}`;
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getUrlWithTextFragment } from './url-text-fragment-maker.service';
|
||||||
|
import TextareaCopyable from '@/components/TextareaCopyable.vue';
|
||||||
|
|
||||||
|
const url = ref('');
|
||||||
|
const prefixSearch = ref('');
|
||||||
|
const textStartSearch = ref('');
|
||||||
|
const textStopSearch = ref('');
|
||||||
|
const suffixSearch = ref('');
|
||||||
|
|
||||||
|
const searchableUrl = computed(() => {
|
||||||
|
try {
|
||||||
|
return getUrlWithTextFragment({
|
||||||
|
url: url.value,
|
||||||
|
textStartSearch: textStartSearch.value,
|
||||||
|
textStopSearch: textStopSearch.value,
|
||||||
|
prefixSearch: prefixSearch.value,
|
||||||
|
suffixSearch: suffixSearch.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (e: any) {
|
||||||
|
return e.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<n-p>
|
||||||
|
Url with Text Fragments allows to make link to content that has no anchor or @id.
|
||||||
|
<n-a href="https://developer.mozilla.org/en-US/docs/Web/Text_fragments" target="blank" rel="noopener">
|
||||||
|
See MDN for more info
|
||||||
|
</n-a>
|
||||||
|
</n-p>
|
||||||
|
<div>
|
||||||
|
<c-input-text
|
||||||
|
v-model:value="url"
|
||||||
|
label="Base url:"
|
||||||
|
placeholder="Base url..."
|
||||||
|
type="url"
|
||||||
|
clearable raw-text mb-5
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div flex justify-center gap-2>
|
||||||
|
<c-input-text
|
||||||
|
v-model:value="textStartSearch"
|
||||||
|
label="Start Search(es) (comma separated)"
|
||||||
|
placeholder="Start Search(es) (comma separated)..."
|
||||||
|
clearable
|
||||||
|
raw-text
|
||||||
|
mb-2
|
||||||
|
/>
|
||||||
|
<c-input-text
|
||||||
|
v-model:value="textStopSearch"
|
||||||
|
label="Stop Search"
|
||||||
|
placeholder="Stop Search text..."
|
||||||
|
clearable
|
||||||
|
raw-text
|
||||||
|
mb-2
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div flex justify-center gap-2>
|
||||||
|
<c-input-text
|
||||||
|
v-model:value="prefixSearch"
|
||||||
|
label="Prefix"
|
||||||
|
placeholder="Prefix search"
|
||||||
|
clearable
|
||||||
|
raw-text
|
||||||
|
mb-2
|
||||||
|
/>
|
||||||
|
<c-input-text
|
||||||
|
v-model:value="suffixSearch"
|
||||||
|
label="Suffix"
|
||||||
|
placeholder="Suffix search"
|
||||||
|
clearable
|
||||||
|
raw-text
|
||||||
|
mb-2
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<n-divider />
|
||||||
|
|
||||||
|
<n-form-item label="Searchable Url:">
|
||||||
|
<TextareaCopyable :value="searchableUrl" />
|
||||||
|
</n-form-item>
|
||||||
|
<div flex justify-center>
|
||||||
|
<n-a :href="searchableUrl" target="blank" rel="noopener">
|
||||||
|
Test Searchable Url
|
||||||
|
</n-a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
Loading…
Add table
Add a link
Reference in a new issue