@hotstaq/admin-panel 0.3.13 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -63,7 +63,18 @@ export class AdminDropdown extends HotComponent
63
63
  let value: string = result.value;
64
64
  let text: string = result.text;
65
65
 
66
- searchResultsDiv.append ($(`<li><a class=\"dropdown-item\" href=\"${url}\" data-value = "${value}" onclick = \"this.parentNode.parentNode.parentNode.parentNode.hotComponent.selected (${iIdx});\">${text}</a></li>`));
66
+ const $template = $(`<li><a class="dropdown-item" href="" data-value="" onclick=""></a></li>`);
67
+
68
+ const $a = $template.find("a");
69
+ $a.attr("href", url);
70
+ $a.attr("data-value", value);
71
+ $a.text(text);
72
+
73
+ $a.removeAttr("onclick").on("click", () => {
74
+ this.selected(iIdx);
75
+ });
76
+
77
+ searchResultsDiv.append($template);
67
78
  }
68
79
  });
69
80
  }
@@ -193,7 +193,7 @@ export class AdminEdit extends HotComponent
193
193
  * The event that can be called when the edit button is clicked.
194
194
  * This is called before the edit modal opens.
195
195
  */
196
- onEditClicked: () => Promise<boolean> = null;
196
+ onEditClicked: (clickedTable?: string, selectedFields?: any[]) => Promise<boolean> = null;
197
197
 
198
198
  /**
199
199
  * Get the attached lists.
@@ -236,11 +236,11 @@ export class AdminEdit extends HotComponent
236
236
  /**
237
237
  * Executes when the edit button is clicked.
238
238
  */
239
- async editClicked (selectedFields: any[] = []): Promise<void>
239
+ async editClicked (clickedTable: string = null, selectedFields: any[] = []): Promise<void>
240
240
  {
241
241
  if (this.onEditClicked != null)
242
242
  {
243
- let result = await this.onEditClicked ();
243
+ let result = await this.onEditClicked (clickedTable, selectedFields);
244
244
 
245
245
  if (result === false)
246
246
  return;
@@ -259,6 +259,12 @@ export class AdminEdit extends HotComponent
259
259
  let attachedList = attachedLists[iIdx];
260
260
  let table: AdminTable = (<AdminTable>attachedList);
261
261
 
262
+ if (clickedTable != null)
263
+ {
264
+ if (table.name !== clickedTable)
265
+ continue;
266
+ }
267
+
262
268
  table.attachedEdit = this;
263
269
  let selectedField = table.getSelected ();
264
270
 
@@ -419,7 +425,12 @@ export class AdminEdit extends HotComponent
419
425
  }
420
426
 
421
427
  if (hotComponent != null)
422
- await hotComponent.refreshList ();
428
+ {
429
+ const currentData = await hotComponent.refreshList ();
430
+ const preparedData = hotComponent.prepareData (currentData);
431
+
432
+ hotComponent.tableCallback (preparedData);
433
+ }
423
434
  }
424
435
  }
425
436
 
@@ -544,7 +555,10 @@ export class AdminEdit extends HotComponent
544
555
 
545
556
  table.attachedEdit = this;
546
557
 
547
- await table.refreshList ();
558
+ const currentData = await table.refreshList ();
559
+ const preparedData = table.prepareData (currentData);
560
+
561
+ table.tableCallback (preparedData);
548
562
  }
549
563
  }
550
564
 
@@ -628,7 +642,7 @@ export class AdminEdit extends HotComponent
628
642
  if (this.edit_place_here !== "")
629
643
  {
630
644
  outputObj.push ({
631
- html: `<button id = "${this.modalId}-edit-btn" type="button" class="btn btn-sm btn-outline-secondary" onclick = "this.editClicked ();">${this.edit_text}</button>`,
645
+ html: `<button id = "${this.modalId}-edit-btn" type="button" class="btn btn-sm btn-outline-secondary" onclick = "this.editClicked ('${this.modalId}');">${this.edit_text}</button>`,
632
646
  documentSelector: `hot-place-here[name="${this.edit_place_here}"]`
633
647
  });
634
648
  }
@@ -45,6 +45,10 @@ export interface IAPIResponse
45
45
  * The error message, if any.
46
46
  */
47
47
  error?: string;
48
+ /**
49
+ * Can enable/disable sanitization of the returning data.
50
+ */
51
+ hotSanitize?: boolean;
48
52
  }
49
53
 
50
54
  export class AdminTable extends HotComponent
@@ -90,6 +94,14 @@ export class AdminTable extends HotComponent
90
94
  * }
91
95
  */
92
96
  rowElements: { fields: any[]; element: HTMLElement; }[] = [];
97
+ /**
98
+ * The table callback for when updating data.
99
+ */
100
+ tableCallback: ((data: any) => void);
101
+ /**
102
+ * The table data for when updating data.
103
+ */
104
+ protected tableData: any;
93
105
  /**
94
106
  * The selected row indicies. Each index maps to the rowElements array.
95
107
  *
@@ -148,6 +160,8 @@ export class AdminTable extends HotComponent
148
160
  indicies: []
149
161
  };
150
162
  this.rowElements = [];
163
+ this.tableCallback = null;
164
+ this.tableData = null;
151
165
  //this.selectedRows = [];
152
166
  this.onlist = null;
153
167
  this.listurl = "";
@@ -234,7 +248,7 @@ export class AdminTable extends HotComponent
234
248
  if (this.singleclickedit === true)
235
249
  {
236
250
  if (this.attachedEdit != null)
237
- await this.attachedEdit.editClicked ();
251
+ await this.attachedEdit.editClicked (this.name);
238
252
  }
239
253
 
240
254
  if (this.onselectedrow != null)
@@ -243,6 +257,10 @@ export class AdminTable extends HotComponent
243
257
  this.onselectedrow = (<(rowIndex: number, item: any[]) => Promise<boolean>>new Function (this.onselectedrow));
244
258
 
245
259
  let item: any[] = this.getSelected ();
260
+
261
+ if (item == null)
262
+ return;
263
+
246
264
  let result = await this.onselectedrow (rowIndex, item);
247
265
 
248
266
  if (result === false)
@@ -454,7 +472,7 @@ export class AdminTable extends HotComponent
454
472
  //this.rows.push (rowsFields);
455
473
  /*rowStr += "</tr>";
456
474
 
457
- let newObj = HotStaq.addHtml (tbody, rowStr);
475
+ let newObj = HotStaq.addHtmlUnsafe (tbody, rowStr);
458
476
 
459
477
  this.rowElements.push ({
460
478
  fields: fields,
@@ -548,12 +566,51 @@ export class AdminTable extends HotComponent
548
566
  return (null);
549
567
  }
550
568
 
551
- /*for (let iIdx = 0; iIdx < list.data.length; iIdx++)
569
+ if (list.data == null)
570
+ throw new Error (`Returning list data to "${this.name}" component has a null data field. API response does not match the "IAPIResponse" schema.`);
571
+
572
+ for (let iIdx = 0; iIdx < list.data.length; iIdx++)
552
573
  {
553
- let fields = list.data[iIdx];
574
+ let elm = list.data[iIdx];
575
+
576
+ for (let key in elm)
577
+ {
578
+ let value = elm[key];
579
+ let fieldType: string = this.getFieldType (key);
554
580
 
555
- this.addRow (fields);
556
- }*/
581
+ if (fieldType == null)
582
+ fieldType = "text";
583
+
584
+ if (fieldType !== "remove")
585
+ {
586
+ const orgField = this.headers.fields[key];
587
+ let defaultOutput: boolean = true;
588
+
589
+ if (orgField != null)
590
+ {
591
+ if (orgField.oninput != null)
592
+ {
593
+ if (typeof (orgField.oninput) === "string")
594
+ this.headers.fields[key].oninput = (<(item: any) => any>new Function (orgField.oninput));
595
+
596
+ value = orgField.oninput (value);
597
+ }
598
+
599
+ if (orgField.onoutput != null)
600
+ {
601
+ if (typeof (orgField.onoutput) === "string")
602
+ this.headers.fields[key].onoutput = (<(index: number, value: string) => string>new Function (orgField.onoutput));
603
+
604
+ defaultOutput = false;
605
+ const newOutput: string = orgField.onoutput (iIdx, value);
606
+ value = newOutput;
607
+ }
608
+ }
609
+
610
+ list.data[iIdx][key] = value;
611
+ }
612
+ }
613
+ }
557
614
  }
558
615
 
559
616
  let tbody = this.htmlElements[1].getElementsByTagName ("tbody")[0];
@@ -564,7 +621,17 @@ export class AdminTable extends HotComponent
564
621
  const hotComponent: AdminTable = this.parentNode.hotComponent;
565
622
  // @ts-ignore
566
623
  const index = hotComponent.dataTable.row (this).index ();
567
- hotComponent.selectRow (this, index);
624
+
625
+ if (index != null)
626
+ hotComponent.selectRow (this, index);
627
+ else
628
+ {
629
+ if (hotComponent.attachedEdit != null)
630
+ {
631
+ if (hotComponent.attachedEdit.addClicked != null)
632
+ hotComponent.attachedEdit.addClicked ();
633
+ }
634
+ }
568
635
  });
569
636
 
570
637
  this.isListRefreshing = false;
@@ -572,6 +639,62 @@ export class AdminTable extends HotComponent
572
639
  return (list);
573
640
  }
574
641
 
642
+ /**
643
+ * Prepare data.
644
+ */
645
+ prepareData (currentData: any[] | IAPIResponse): {
646
+ draw: any;
647
+ data: any[];
648
+ recordsTotal: number;
649
+ recordsFiltered: number;
650
+ }
651
+ {
652
+ const callbackObj: any = {
653
+ draw: this.tableData,
654
+ data: [],
655
+ recordsTotal: 0,
656
+ recordsFiltered: 0
657
+ };
658
+
659
+ if (currentData != null)
660
+ {
661
+ if (! (currentData instanceof Array))
662
+ {
663
+ if (currentData.length != null)
664
+ {
665
+ callbackObj.recordsTotal = currentData.length;
666
+ callbackObj.recordsFiltered = currentData.length;
667
+ }
668
+
669
+ if (currentData.data != null)
670
+ callbackObj.data = currentData.data;
671
+ }
672
+ else
673
+ {
674
+ callbackObj.data = currentData;
675
+ callbackObj.recordsTotal = currentData.length;
676
+ callbackObj.recordsFiltered = currentData.length;
677
+ }
678
+
679
+ let sanitize = true;
680
+
681
+ if (callbackObj.data.hotSanitize != null)
682
+ sanitize = callbackObj.data.hotSanitize;
683
+
684
+ for (let iIdx = 0; iIdx < callbackObj.data.length; iIdx++)
685
+ {
686
+ const row = callbackObj.data[iIdx];
687
+
688
+ if (sanitize === true)
689
+ callbackObj.data[iIdx] = HotStaq.sanitizeJSON (row);
690
+ else
691
+ callbackObj.data[iIdx] = row;
692
+ }
693
+ }
694
+
695
+ return (callbackObj);
696
+ }
697
+
575
698
  /**
576
699
  * Get the list of data from the server.
577
700
  */
@@ -579,9 +702,10 @@ export class AdminTable extends HotComponent
579
702
  {
580
703
  setTimeout (async () =>
581
704
  {
582
-
583
705
  const table = $(htmlElement).find("table");
584
706
 
707
+ // The data stored in columns should be considered safe as it comes directly from
708
+ // the HTML after load.
585
709
  let columns: ConfigColumns[] = [];
586
710
  $(table).find ("thead th").each (function ()
587
711
  {
@@ -621,48 +745,17 @@ export class AdminTable extends HotComponent
621
745
  if (this.isListRefreshing === true)
622
746
  return;
623
747
 
624
- let currentData = await this.refreshList ();
625
-
626
- const callbackObj: any = {
627
- // @ts-ignore
628
- draw: data.draw,
629
- data: [],
630
- recordsTotal: 0,
631
- recordsFiltered: 0
632
- };
748
+ this.tableCallback = callback;
749
+ // @ts-ignore
750
+ this.tableData = data.draw;
633
751
 
634
- if (currentData != null)
635
- {
636
- if (! (currentData instanceof Array))
637
- {
638
- if (currentData.length != null)
639
- {
640
- callbackObj.recordsTotal = currentData.length;
641
- callbackObj.recordsFiltered = currentData.length;
642
- }
643
-
644
- if (currentData.data != null)
645
- callbackObj.data = currentData.data;
646
- }
647
- else
648
- {
649
- callbackObj.data = currentData;
650
- callbackObj.recordsTotal = currentData.length;
651
- callbackObj.recordsFiltered = currentData.length;
652
- }
653
-
654
- for (let iIdx = 0; iIdx < currentData.data.length; iIdx++)
655
- {
656
- const row = currentData.data[iIdx];
657
-
658
- currentData.data[iIdx] = HotStaq.sanitizeJSON (row);
659
- }
660
- }
752
+ let currentData = await this.refreshList ();
753
+ const preparedData = this.prepareData (currentData);
661
754
 
662
- callback (callbackObj);
755
+ this.tableCallback (preparedData);
663
756
  }
664
757
  });
665
- }, 50);
758
+ }, 50); /// @todo Fix this stupid hack. This should happen slightly after the document has been loaded.
666
759
 
667
760
  return (null);
668
761
  }