Browse Source

working on vcard display

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
module/contact
Stephan Richter 4 weeks ago
parent
commit
0ceeba0701
  1. 15
      frontend/src/routes/contact/Card.svelte
  2. 9
      frontend/src/routes/contact/FN.svelte
  3. 58
      frontend/src/routes/contact/Index.svelte
  4. 23
      frontend/src/routes/contact/Name.svelte
  5. 9
      frontend/src/routes/contact/Org.svelte
  6. 82
      frontend/src/vcard.js

15
frontend/src/routes/contact/Card.svelte

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
<script>
import FN from './FN.svelte';
import Name from './Name.svelte';
import Org from './Org.svelte';
let { contact } = $props();
</script>
<div>
<Org vcard={contact.vcard} /><br/>
<FN vcard={contact.vcard} /><br/>
<Name vcard={contact.vcard} />
<hr/>
<pre>{contact.vcard}</pre>
</div>

9
frontend/src/routes/contact/FN.svelte

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<script>
import { fn } from '../../vcard.js';
let { vcard } = $props();
let name = $derived(fn(vcard));
</script>
<span class="formatted name">{name}</span>

58
frontend/src/routes/contact/Index.svelte

@ -1,58 +1,15 @@ @@ -1,58 +1,15 @@
<script>
import Card from './Card.svelte';
import { onMount } from 'svelte';
import { api } from '../../urls.svelte';
import { error, yikes } from '../../warn.svelte';
import { t } from '../../translations.svelte';
let contacts = $state(null)
import { byName } from '../../vcard.js';
function parseAdr(key,val){
var parts = val.split(';');
var adr = {
postbox : parts[0],
ext : parts[1],
street : parts[2],
locality : parts[3],
region : parts[4],
code : parts[5],
country : parts[6]
}
parts = key.split(';');
for (let part of parts){
let inner = part.split('=');
if (inner.length<2) continue;
const k = inner[0];
const v = inner.slice(1).join('=');
adr[k] = v;
}
return adr;
}
let contacts = $state(null)
function parse(data){
var code = data.vcard;
const lines = code.split("\n");
let unprocessed = null;
var o = {};
for (var line of lines){
if (unprocessed = null) unprocessed = line;
if (line.startsWith(' ')) { // extend line
unprocessed += line.substring(1);
} else {
// process complete line
const parts = line.split(':');
var prefix = parts[0];
var val = parts.slice(1).join(':');
var key = prefix.split(';')[0].toUpperCase();
switch (key) {
case "ADR": o[key] = parseAdr(prefix,val); break;
default:
if (key) o[prefix]=val;
}
unprocessed = line;
}
}
console.log(o);
}
async function load(){
const url = api('contact/list');
@ -60,7 +17,7 @@ @@ -60,7 +17,7 @@
if (res.ok){
yikes();
var data = await res.json();
contacts = Object.values(data).map(parse).sort((a,b) => a.FN.localeCompare(b.FN));
contacts = Object.values(data).sort(byName);
console.log(contacts);
} else {
error(res);
@ -70,4 +27,7 @@ @@ -70,4 +27,7 @@
onMount(load);
</script>
<h1>{t('contacts')}</h1>
<h1>{t('contacts')}</h1>
{#each contacts as contact}
<Card {contact} />
{/each}

23
frontend/src/routes/contact/Name.svelte

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
<script>
import { name } from '../../vcard.js';
let { vcard } = $props();
let n = $derived(name(vcard));
</script>
{#if n.prefix}
<span class="name prefix">{n.prefix}</span>
{/if}
{#if n.given}
<span class="given name">{n.given}</span>
{/if}
{#if n.family}
<span class="family name">{n.family}</span>
{/if}
{#if n.additional}
<span class="additional name">{n.additional}</span>
{/if}
{#if n.suffix}
<span class="name suffix">{n.suffix}</span>
{/if}

9
frontend/src/routes/contact/Org.svelte

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<script>
import { org } from '../../vcard.js';
let { vcard } = $props();
let o = $derived(org(vcard));
</script>
<span class="organization">{o}</span>

82
frontend/src/vcard.js

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
export function parse(data){
var code = data.vcard;
const lines = code.split("\n");
let unprocessed = null;
var o = {};
for (var line of lines){
if (unprocessed = null) unprocessed = line;
if (line.startsWith(' ')) { // extend line
unprocessed += line.substring(1);
} else {
// process complete line
const parts = line.split(':');
var prefix = parts[0];
var val = parts.slice(1).join(':');
var key = prefix.split(';')[0].toUpperCase();
switch (key) {
case "ADR": o[key] = parseAdr(prefix,val); break;
default:
if (key) o[prefix]=val;
}
unprocessed = line;
}
}
console.log(o);
}
function parseAdr(key,val){
var parts = val.split(';');
var adr = {
postbox : parts[0],
ext : parts[1],
street : parts[2],
locality : parts[3],
region : parts[4],
code : parts[5],
country : parts[6]
}
parts = key.split(';');
for (let part of parts){
let inner = part.split('=');
if (inner.length<2) continue;
const k = inner[0];
const v = inner.slice(1).join('=');
adr[k] = v;
}
return adr;
}
export function fn(vcard){
const match = vcard.match(/^FN:(.+)$/m);
return match ? match[1].trim() : '';
}
export function org(vcard){
const match = vcard.match(/^ORG:(.+)$/m);
return match ? match[1].trim() : '';
}
export function name(vcard){
const match = vcard.match(/^N:(.+)$/m);
let name = {
family: null,
given: null,
additional: null,
prefix: null,
suffix: null
}
if (match){
const parts = match[1].trim().split(';');
name.family = parts[0];
name.given = parts[1];
name.additional = parts[2];
name.prefix = parts[3];
name.suffix = parts[4];
}
return name;
}
export function byName(a,b){
return fn(a.vcard).localeCompare(fn(b.vcard));
}
Loading…
Cancel
Save