483 lines
11 KiB
TypeScript
483 lines
11 KiB
TypeScript
/**
|
|
* Class model for Individual Interface
|
|
*/
|
|
|
|
import { reactive } from 'vue'
|
|
import { generateUrid, generateKey } from "../utils/key-generator";
|
|
import type {
|
|
IndividualAnniversary,
|
|
IndividualCrypto,
|
|
IndividualEmail,
|
|
IndividualInterface,
|
|
IndividualLanguage,
|
|
IndividualMedia,
|
|
IndividualName,
|
|
IndividualNote,
|
|
IndividualOrganization,
|
|
IndividualPhone,
|
|
IndividualPhysicalLocation,
|
|
IndividualTitle,
|
|
IndividualVirtualLocation
|
|
} from "@/types/individual";
|
|
|
|
export class IndividualObject implements IndividualInterface {
|
|
|
|
_data: IndividualInterface;
|
|
|
|
constructor() {
|
|
this._data = reactive({
|
|
type: 'individual',
|
|
version: 1,
|
|
urid: generateUrid(),
|
|
created: null,
|
|
modified: null,
|
|
label: '',
|
|
names: {
|
|
family: null,
|
|
given: null,
|
|
additional: null,
|
|
prefix: null,
|
|
suffix: null,
|
|
phoneticFamily: null,
|
|
phoneticGiven: null,
|
|
phoneticAdditional: null,
|
|
aliases: []
|
|
},
|
|
titles: {},
|
|
anniversaries: [],
|
|
physicalLocations: {},
|
|
phones: {},
|
|
emails: {},
|
|
virtualLocations: {},
|
|
media: {},
|
|
organizations: {},
|
|
tags: [],
|
|
notes: {},
|
|
language: null,
|
|
languages: [],
|
|
crypto: {},
|
|
});
|
|
}
|
|
|
|
fromJson(data: IndividualInterface) : IndividualObject {
|
|
// Normalize arrays to Records for properties that should be Record types
|
|
const normalized = {
|
|
...data,
|
|
titles: Array.isArray(data.titles) ? {} : (data.titles || {}),
|
|
physicalLocations: Array.isArray(data.physicalLocations) ? {} : (data.physicalLocations || {}),
|
|
phones: Array.isArray(data.phones) ? {} : (data.phones || {}),
|
|
emails: Array.isArray(data.emails) ? {} : (data.emails || {}),
|
|
virtualLocations: Array.isArray(data.virtualLocations) ? {} : (data.virtualLocations || {}),
|
|
media: Array.isArray(data.media) ? {} : (data.media || {}),
|
|
notes: Array.isArray(data.notes) ? {} : (data.notes || {}),
|
|
crypto: Array.isArray(data.crypto) ? {} : (data.crypto || {}),
|
|
};
|
|
this._data = reactive(normalized);
|
|
return this;
|
|
}
|
|
|
|
toJson(): IndividualInterface {
|
|
return this._data;
|
|
}
|
|
|
|
clone(): IndividualObject {
|
|
const cloned = new IndividualObject()
|
|
cloned._data = JSON.parse(JSON.stringify(this._data))
|
|
return cloned
|
|
}
|
|
|
|
/** Immutable Properties */
|
|
get type(): string {
|
|
return this._data.type;
|
|
}
|
|
|
|
get version(): number {
|
|
return this._data.version;
|
|
}
|
|
|
|
get urid(): string | null {
|
|
return this._data.urid;
|
|
}
|
|
|
|
/** Mutable Properties */
|
|
|
|
get created(): Date | null {
|
|
return this._data.created;
|
|
}
|
|
|
|
set created(value: Date | null) {
|
|
this._data.created = value;
|
|
}
|
|
|
|
get modified(): Date | null {
|
|
return this._data.modified;
|
|
}
|
|
|
|
set modified(value: Date | null) {
|
|
this._data.modified = value;
|
|
}
|
|
|
|
get label(): string | null {
|
|
return this._data.label;
|
|
}
|
|
|
|
set label(value: string | null) {
|
|
this._data.label = value;
|
|
}
|
|
|
|
get names(): IndividualName {
|
|
return this._data.names;
|
|
}
|
|
|
|
set names(value: IndividualName) {
|
|
this._data.names = value;
|
|
}
|
|
|
|
get titles(): Record<string, IndividualTitle> {
|
|
return this._data.titles;
|
|
}
|
|
|
|
set titles(value: Record<string, IndividualTitle>) {
|
|
this._data.titles = value;
|
|
}
|
|
|
|
get anniversaries(): IndividualAnniversary[] {
|
|
return this._data.anniversaries;
|
|
}
|
|
|
|
set anniversaries(value: IndividualAnniversary[]) {
|
|
this._data.anniversaries = value;
|
|
}
|
|
|
|
get physicalLocations(): Record<string, IndividualPhysicalLocation> {
|
|
return this._data.physicalLocations;
|
|
}
|
|
|
|
set physicalLocations(value: Record<string, IndividualPhysicalLocation>) {
|
|
this._data.physicalLocations = value;
|
|
}
|
|
|
|
get phones(): Record<string, IndividualPhone> {
|
|
return this._data.phones;
|
|
}
|
|
|
|
set phones(value: Record<string, IndividualPhone>) {
|
|
this._data.phones = value;
|
|
}
|
|
|
|
get emails(): Record<string, IndividualEmail> {
|
|
return this._data.emails;
|
|
}
|
|
|
|
set emails(value: Record<string, IndividualEmail>) {
|
|
this._data.emails = value;
|
|
}
|
|
|
|
get virtualLocations(): Record<string, IndividualVirtualLocation> {
|
|
return this._data.virtualLocations;
|
|
}
|
|
|
|
set virtualLocations(value: Record<string, IndividualVirtualLocation>) {
|
|
this._data.virtualLocations = value;
|
|
}
|
|
|
|
get media(): Record<string, IndividualMedia> {
|
|
return this._data.media;
|
|
}
|
|
|
|
set media(value: Record<string, IndividualMedia>) {
|
|
this._data.media = value;
|
|
}
|
|
|
|
get organizations(): Record<string, IndividualOrganization> {
|
|
return this._data.organizations;
|
|
}
|
|
|
|
set organizations(value: Record<string, IndividualOrganization>) {
|
|
this._data.organizations = value;
|
|
}
|
|
|
|
get tags(): string[] {
|
|
return this._data.tags;
|
|
}
|
|
|
|
set tags(value: string[]) {
|
|
this._data.tags = value;
|
|
}
|
|
|
|
get notes(): Record<string, IndividualNote> {
|
|
return this._data.notes;
|
|
}
|
|
|
|
set notes(value: Record<string, IndividualNote>) {
|
|
this._data.notes = value;
|
|
}
|
|
|
|
get language(): string | null {
|
|
return this._data.language;
|
|
}
|
|
|
|
set language(value: string | null) {
|
|
this._data.language = value;
|
|
}
|
|
|
|
get languages(): IndividualLanguage[] {
|
|
return this._data.languages;
|
|
}
|
|
|
|
set languages(value: IndividualLanguage[]) {
|
|
this._data.languages = value;
|
|
}
|
|
|
|
get crypto(): Record<string, IndividualCrypto> {
|
|
return this._data.crypto;
|
|
}
|
|
|
|
set crypto(value: Record<string, IndividualCrypto>) {
|
|
this._data.crypto = value;
|
|
}
|
|
|
|
/**
|
|
* Mutation helpers for complex properties
|
|
*/
|
|
|
|
addTitle(initial?: Partial<IndividualTitle>): string {
|
|
if (!this._data.titles) {
|
|
this._data.titles = {};
|
|
}
|
|
const key = generateKey();
|
|
this._data.titles[key] = {
|
|
kind: null,
|
|
label: null,
|
|
relation: null,
|
|
context: null,
|
|
priority: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removeTitle(key: string): void {
|
|
if (this._data.titles) {
|
|
delete this._data.titles[key];
|
|
}
|
|
}
|
|
|
|
addAnniversary(initial?: Partial<IndividualAnniversary>): number {
|
|
const anniversaries = this._data.anniversaries || (this._data.anniversaries = []);
|
|
const entry: IndividualAnniversary = {
|
|
type: null,
|
|
when: null,
|
|
location: null,
|
|
...initial,
|
|
};
|
|
anniversaries.push(entry);
|
|
return anniversaries.length - 1;
|
|
}
|
|
|
|
removeAnniversary(index: number): void {
|
|
const anniversaries = this._data.anniversaries;
|
|
if (index >= 0 && index < anniversaries.length) {
|
|
anniversaries.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
addPhysicalLocation(initial?: Partial<IndividualPhysicalLocation>): string {
|
|
const locations = this._data.physicalLocations || (this._data.physicalLocations = {});
|
|
const key = generateKey();
|
|
locations[key] = {
|
|
box: null,
|
|
unit: null,
|
|
street: null,
|
|
locality: null,
|
|
region: null,
|
|
code: null,
|
|
country: null,
|
|
label: null,
|
|
coordinates: null,
|
|
timeZone: null,
|
|
context: null,
|
|
priority: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removePhysicalLocation(key: string): void {
|
|
if (this._data.physicalLocations) {
|
|
delete this._data.physicalLocations[key];
|
|
}
|
|
}
|
|
|
|
addPhone(initial?: Partial<IndividualPhone>): string {
|
|
const phones = this._data.phones || (this._data.phones = {});
|
|
const key = generateKey();
|
|
phones[key] = {
|
|
number: null,
|
|
label: null,
|
|
context: null,
|
|
priority: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removePhone(key: string): void {
|
|
if (this._data.phones) {
|
|
delete this._data.phones[key];
|
|
}
|
|
}
|
|
|
|
addEmail(initial?: Partial<IndividualEmail>): string {
|
|
const emails = this._data.emails || (this._data.emails = {});
|
|
const key = generateKey();
|
|
emails[key] = {
|
|
address: null,
|
|
context: null,
|
|
priority: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removeEmail(key: string): void {
|
|
if (this._data.emails) {
|
|
delete this._data.emails[key];
|
|
}
|
|
}
|
|
|
|
addVirtualLocation(initial?: Partial<IndividualVirtualLocation>): string {
|
|
const virtualLocations = this._data.virtualLocations || (this._data.virtualLocations = {});
|
|
const key = generateKey();
|
|
virtualLocations[key] = {
|
|
location: null,
|
|
label: null,
|
|
context: null,
|
|
priority: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removeVirtualLocation(key: string): void {
|
|
if (this._data.virtualLocations) {
|
|
delete this._data.virtualLocations[key];
|
|
}
|
|
}
|
|
|
|
addMedia(initial?: Partial<IndividualMedia>): string {
|
|
const media = this._data.media || (this._data.media = {});
|
|
const key = generateKey();
|
|
media[key] = {
|
|
type: "photo",
|
|
kind: "photo",
|
|
uri: "",
|
|
mediaType: null,
|
|
contexts: null,
|
|
pref: null,
|
|
label: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removeMedia(key: string): void {
|
|
if (this._data.media) {
|
|
delete this._data.media[key];
|
|
}
|
|
}
|
|
|
|
addOrganization(initial?: Partial<IndividualOrganization>): string {
|
|
const organizations = this._data.organizations || (this._data.organizations = {});
|
|
const key = generateKey();
|
|
organizations[key] = {
|
|
Label: null,
|
|
Units: [],
|
|
sortName: null,
|
|
context: null,
|
|
priority: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removeOrganization(key: string): void {
|
|
if (this._data.organizations) {
|
|
delete this._data.organizations[key];
|
|
}
|
|
}
|
|
|
|
addNote(initial?: Partial<IndividualNote>): string {
|
|
const notes = this._data.notes || (this._data.notes = {});
|
|
const key = generateKey();
|
|
notes[key] = {
|
|
content: null,
|
|
date: null,
|
|
authorUri: null,
|
|
authorName: null,
|
|
context: null,
|
|
priority: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removeNote(key: string): void {
|
|
if (this._data.notes) {
|
|
delete this._data.notes[key];
|
|
}
|
|
}
|
|
|
|
addLanguage(initial?: Partial<IndividualLanguage>): number {
|
|
const languages = this._data.languages || (this._data.languages = []);
|
|
const entry: IndividualLanguage = {
|
|
Data: null,
|
|
Id: null,
|
|
Priority: null,
|
|
Context: null,
|
|
...initial,
|
|
};
|
|
languages.push(entry);
|
|
return languages.length - 1;
|
|
}
|
|
|
|
removeLanguage(index: number): void {
|
|
const languages = this._data.languages;
|
|
if (index >= 0 && index < languages.length) {
|
|
languages.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
addCrypto(initial?: Partial<IndividualCrypto>): string {
|
|
const cryptoEntries = this._data.crypto || (this._data.crypto = {});
|
|
const key = generateKey();
|
|
cryptoEntries[key] = {
|
|
data: null,
|
|
type: null,
|
|
context: null,
|
|
priority: null,
|
|
...initial,
|
|
};
|
|
return key;
|
|
}
|
|
|
|
removeCrypto(key: string): void {
|
|
if (this._data.crypto) {
|
|
delete this._data.crypto[key];
|
|
}
|
|
}
|
|
|
|
addTag(value: string): void {
|
|
const tags = this._data.tags || (this._data.tags = []);
|
|
tags.push(value);
|
|
}
|
|
|
|
removeTag(value: string): void {
|
|
const tags = this._data.tags;
|
|
const index = tags.indexOf(value);
|
|
if (index >= 0) {
|
|
tags.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
} |