journal-notes.component.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import {
  2. Component,
  3. OnInit,
  4. OnDestroy,
  5. inject,
  6. TemplateRef,
  7. ViewChild,
  8. ViewContainerRef,
  9. Renderer2,
  10. ElementRef,
  11. } from '@angular/core';
  12. import { Editor } from 'ngx-editor';
  13. import { DateAdapter } from '@angular/material/core';
  14. import { JournalEntry } from 'src/interfaces/interfaces';
  15. import localeDe from '@angular/common/locales/de';
  16. import { registerLocaleData } from '@angular/common';
  17. import { DataService } from 'src/services/data/data.service';
  18. import { TooltipService } from 'src/services/tooltip/tooltip.service';
  19. import { HighlightComponent } from 'src/app/shared-components/highlight/highlight.component';
  20. @Component({
  21. selector: 'app-journal-notes',
  22. templateUrl: './journal-notes.component.html',
  23. styleUrl: './journal-notes.component.scss',
  24. })
  25. export class JournalNotesComponent implements OnInit, OnDestroy {
  26. /** Reference to the tooltip */
  27. @ViewChild('tooltip', { read: TemplateRef }) tooltip!: TemplateRef<any>;
  28. /** Reference to the creation anchor */
  29. @ViewChild('creationAnchor', { read: ViewContainerRef })
  30. creationAnchor!: ViewContainerRef;
  31. editor: Editor = new Editor();
  32. toolbar: any = [
  33. // default value
  34. ['bold', 'italic'],
  35. ['bullet_list'],
  36. [{ heading: ['h3', 'h4', 'h5', 'h6'] }],
  37. ];
  38. public entries: JournalEntry[] = [];
  39. public currentEntry: JournalEntry = {
  40. title: '',
  41. content: '',
  42. created: new Date(),
  43. };
  44. public isInEditMode = false;
  45. public currentIndex: number = -1;
  46. private backupIndex: number = -1;
  47. public isNewEntry = false;
  48. public tooltipText: string = '';
  49. public npcDescriptions: any = {};
  50. tooltipifiedEntry: JournalEntry = {
  51. title: 'Title',
  52. content: 'Content',
  53. created: new Date(),
  54. };
  55. private _adapter: DateAdapter<any> = inject(DateAdapter);
  56. private dataService: DataService = inject(DataService);
  57. private tooltipService: TooltipService = inject(TooltipService);
  58. private renderer: Renderer2 = inject(Renderer2);
  59. private el: ElementRef = inject(ElementRef);
  60. ngOnInit(): void {
  61. registerLocaleData(localeDe);
  62. this._adapter.setLocale('de');
  63. this.entries = this.dataService.notesData;
  64. // if the list is empty, set the currentIndex to -1 to hide the entry-container
  65. if (this.entries.length === 0) {
  66. this.currentIndex = -1;
  67. } else {
  68. this.selectEntry(0);
  69. }
  70. }
  71. // ACTIONS FROM THE TEMPLATE
  72. /**
  73. * Sets the currentEntry variable when being clicked on in the entries list on the left.
  74. * It also modifies the content of the entry by highlighting names and adding tooltips.
  75. * Is only called when the entry is not in edit mode or a different entry is selected.
  76. * @param index The index of the selected entry.
  77. */
  78. public selectEntry(index: number): void {
  79. // hier
  80. if (this.isInEditMode || index !== this.currentIndex) {
  81. this.currentIndex = index;
  82. this.currentEntry = this.getEntryAt(index);
  83. this.isNewEntry = false;
  84. this.isInEditMode = false;
  85. this.tooltipify();
  86. }
  87. }
  88. /**
  89. * Adds an new empty entry, switches to edit mode and removes the highlighting of the selected entry.
  90. */
  91. public addEntry(): void {
  92. this.currentEntry = {
  93. title: '',
  94. content: '',
  95. created: new Date(),
  96. };
  97. this.isNewEntry = true;
  98. this.isInEditMode = true;
  99. this.backupIndex = this.currentIndex;
  100. // Hightlight no entry because the placeholder is shown as active
  101. this.currentIndex = -1;
  102. }
  103. /**
  104. * Switches to edit mode.
  105. */
  106. public editEntry(): void {
  107. this.isInEditMode = true;
  108. }
  109. /**
  110. * If the current entry is a new entry, it will be prepended to the entries list.
  111. * Else it is saved at the current index.
  112. * The content is the tooltipified and saved in the database.
  113. */
  114. public saveEntry(): void {
  115. if (this.isNewEntry) {
  116. // Prepend the new JournalEntry
  117. this.entries.unshift(this.currentEntry);
  118. this.isNewEntry = false;
  119. this.currentIndex = 0;
  120. }
  121. this.isInEditMode = false;
  122. this.entries[this.currentIndex] = this.currentEntry;
  123. this.tooltipify();
  124. this.uploadNotes();
  125. }
  126. /**
  127. * Discards the current entry and resets the currentEntry to the last saved version.
  128. * If the entry was a new entry, the currentIndex is reset to the last selected entry.
  129. * The content is also tooltipified again.
  130. */
  131. public discardEntry(): void {
  132. if (this.isNewEntry) {
  133. this.currentIndex = this.backupIndex;
  134. this.isNewEntry = false;
  135. }
  136. if (this.entries.length > 0) {
  137. // Reset the currentEntry to the last saved version
  138. this.currentEntry = this.getEntryAt(this.currentIndex);
  139. }
  140. this.isInEditMode = false;
  141. this.tooltipify();
  142. }
  143. /**
  144. * Deletes the current entry and removes it from the entries list.
  145. * If the last entry was deleted, the currentIndex is reset to -1.
  146. * The content is saved in the database.
  147. */
  148. public deleteEntry(): void {
  149. this.entries.splice(this.currentIndex, 1);
  150. if (this.entries.length === 0) {
  151. this.currentIndex = -1;
  152. } else {
  153. this.currentIndex = Math.max(this.currentIndex - 1, 0);
  154. this.currentEntry = this.getEntryAt(this.currentIndex);
  155. // Update the tooltipified entry
  156. this.tooltipify();
  157. }
  158. this.uploadNotes();
  159. }
  160. /**
  161. * Returns a deep copy of the entry at the given index.
  162. * @param index Defines the index of the entry that should be returned.
  163. * @returns A deep copy of the entry at the given index.
  164. */
  165. private getEntryAt(index: number): JournalEntry {
  166. return JSON.parse(JSON.stringify(this.entries[index]));
  167. }
  168. /**
  169. * Saves the current entries in the data service.
  170. */
  171. private uploadNotes(): void {
  172. this.dataService.notesData = this.entries;
  173. }
  174. /**
  175. * Converts the content of the current entry to a tooltipified version.
  176. * It then adds the highlights to the names and sets the tooltip text.
  177. * Is called on every refresh of an entry (selecting, saving, discarding, deleting, adding, etc.)
  178. */
  179. public tooltipify(): void {
  180. let result: any = this.tooltipService.tooltipifyEntry(
  181. this.getEntryAt(this.currentIndex).content,
  182. );
  183. this.tooltipifiedEntry.content = result.content;
  184. this.npcDescriptions = result.npcDescriptions;
  185. setTimeout(() => {
  186. result.npcs.forEach((name: string) => {
  187. this.addHighlightsToText(name);
  188. });
  189. });
  190. }
  191. /**
  192. * Adds a highlight component to the names that are mentioned in the current entry.
  193. * Highlights and adds tooltips to the names that are mentioned in the current entry.
  194. * @param name The name of the person which is currently highlighted.
  195. */
  196. private addHighlightsToText(name: string) {
  197. // get all elements where a highlight component should be added to
  198. const parent = this.el.nativeElement.querySelectorAll('.' + name);
  199. parent.forEach((element: any) => {
  200. const componentRef =
  201. this.creationAnchor.createComponent(HighlightComponent);
  202. componentRef.instance.text = name;
  203. componentRef.instance.tooltip = this.tooltip;
  204. this.renderer.appendChild(element, componentRef.location.nativeElement);
  205. // add a mouseover event listener to the highlight component, when it is hovered over, the tooltip-text is set
  206. this.renderer.listen(
  207. componentRef.location.nativeElement,
  208. 'mouseover',
  209. () => {
  210. this.tooltipText = this.npcDescriptions[name];
  211. },
  212. );
  213. });
  214. }
  215. ngOnDestroy(): void {
  216. this.editor.destroy();
  217. }
  218. }