HEX
Server: nginx/1.24.0
System: Linux nowruzgan 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025 x86_64
User: babak (1000)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: /var/dev/nowruzgan/travelogue/src/app/data.types.ts
export type Dataset = {
  sources: Source[],
  notes: Note[],
  pois: Poi[],
  tags: Tag[],
  timestamp: number
};

export type TimelineRecord = {date: Date, active: boolean, timelineX: number, notes: Note[]};

export type PoiRel = {poi: Poi, order: number, flagMilestone: boolean, flagNoway: boolean};

export class Entity {
  constructor(data?: any) {
    if(data) this.absorb(data);
  }

  absorb(data: any) {
    if(typeof data == 'number' || typeof data == 'string') {
      (this as any).id = data;
      return;
    }
    for(let key in data) (this as any)[key] = data[key];
  }

  meta: any = {};
}

export class Source extends Entity {
  constructor(data?: any) {
    super(data);
    if(data) this.absorb(data);
  }

  override absorb(data: any) {
    super.absorb(data);
    if(data.citation) {
      try{
        this.citation = JSON.parse(data.citation);
      }catch{
        this.citation = [data.citation];
      }
    }else
      this.citation = [''];
  }

  id: number = 0;
  title: string = '';
  code: string = '';
  author: string = '';
  citation: string[] = [''];
  defaultCalendar: string = '';
  era: number = 0;
  sourceDesc: string = '';
  authorsDesc: string = '';
  notes: Note[] = [];
  tags: Tag[] = [];
  timeline: TimelineRecord[] = [];
  borderBox?: {minLat: number, maxLat: number, minLon: number, maxLon: number};
}

export class Note extends Entity {
  constructor(data?: any) {
    super(data);
    if(data) this.absorb(data);
  }

  override absorb(data: any) {
    super.absorb(data);

    if(data.dateFrom) this.dateFrom = new Date(data.dateFrom);
    if(data.dateTo) this.dateTo = new Date(data.dateTo);

    this.text = this.text
      .replace(/<(\w+) [^>]*\/?>/g, '<$1>')
      .replace(/<p>(&nbsp;|[ \t\n]*)+/g, '<p>')
      .replace(/(&nbsp;|[ \t\n]*)+<\/p>/g, '</p>')
      .replace(/<p>(<br>)?<\/p>/g, '')

    if(this.desc)
      this.meta.desc = `<p>${this.desc.split('\n').join('</p><p>')}</p>`;
  }

  get allTags(): Tag[] {
    return [...this.tags, ...this.indexPerson, ...this.indexPlace, ...this.indexOther];
  }

  id: number = 0;
  dateFrom: Date | null = null;
  dateTo: Date | null = null;
  dateGranularity: number = 0;
  order: number = 0;
  flagQuote: boolean = false;
  flagShort: boolean = false;
  flagTime: boolean = false;
  desc: string = '';
  text: string = '';
  source: Source = new Source();
  citation: string = '';
  poiRels: PoiRel[] = [];
  tags: Tag[] = [];
  indexPlace: Tag[] = [];
  indexPerson: Tag[] = [];
  indexOther: Tag[] = [];
}

export class Poi extends Entity {
  static GRANULARITY_CITY = 40;

  constructor(data?: any) {
    super(data);
    if(data) this.absorb(data);
  }

  id: number = 0;
  title: string = '';
  latin: string = '';
  altNames: {title: string, citation: string}[] = [];
  lat: number = 0;
  lon: number = 0;
  granularity: number = 0;
  flagAmbiguous: boolean = false;
  flagRuined: boolean = false;
  desc: string = '';
  notes: Note[] = [];
  sources: Source[] = [];
}

export class Tag extends Entity {
  constructor(data?: any) {
    super(data);
    if(data) this.absorb(data);
  }

  override absorb(data: any) {
    super.absorb(data);

    this.meta.sources = (data.sources as string || '').split(',').map(i => parseInt(i));
    delete (this as any).sources;
  }

  id: number = 0;
  title: string = '';
  titleEn: string = '';
  taxonomy: string = '';
  notes: Note[] = [];
}