jpf 4.2.15 → 4.2.17

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.
Files changed (124) hide show
  1. package/dist/controls/codeMirror/HtmlEditor/HtmlEditor.d.ts +2 -1
  2. package/dist/controls/codeMirror/HtmlEditor/HtmlEditor.js +4 -0
  3. package/dist/controls/codeMirror/HtmlEditor/HtmlEditor.js.map +1 -1
  4. package/dist/controls/codeMirror/JsonEditor/JsonEditor.d.ts +2 -1
  5. package/dist/controls/codeMirror/JsonEditor/JsonEditor.js +4 -0
  6. package/dist/controls/codeMirror/JsonEditor/JsonEditor.js.map +1 -1
  7. package/dist/controls/custom/FileSelector/FileSelector.d.ts +2 -1
  8. package/dist/controls/custom/FileSelector/FileSelector.js +4 -0
  9. package/dist/controls/custom/FileSelector/FileSelector.js.map +1 -1
  10. package/dist/controls/custom/LabeledControl/LabeledControl.d.ts +2 -1
  11. package/dist/controls/custom/LabeledControl/LabeledControl.js +4 -0
  12. package/dist/controls/custom/LabeledControl/LabeledControl.js.map +1 -1
  13. package/dist/controls/custom/ListItem/ListItem.d.ts +4 -2
  14. package/dist/controls/custom/ListItem/ListItem.js +8 -0
  15. package/dist/controls/custom/ListItem/ListItem.js.map +1 -1
  16. package/dist/controls/html/Button/Button.d.ts +2 -1
  17. package/dist/controls/html/Button/Button.js +4 -0
  18. package/dist/controls/html/Button/Button.js.map +1 -1
  19. package/dist/controls/html/Div/Div.d.ts +2 -1
  20. package/dist/controls/html/Div/Div.js +4 -0
  21. package/dist/controls/html/Div/Div.js.map +1 -1
  22. package/dist/controls/html/Image/Image.d.ts +2 -1
  23. package/dist/controls/html/Image/Image.js +4 -0
  24. package/dist/controls/html/Image/Image.js.map +1 -1
  25. package/dist/controls/html/Input/Input.d.ts +2 -1
  26. package/dist/controls/html/Input/Input.js +4 -0
  27. package/dist/controls/html/Input/Input.js.map +1 -1
  28. package/dist/controls/html/Select/Select.d.ts +2 -1
  29. package/dist/controls/html/Select/Select.js +4 -0
  30. package/dist/controls/html/Select/Select.js.map +1 -1
  31. package/dist/controls/html/Span/Span.d.ts +2 -1
  32. package/dist/controls/html/Span/Span.js +4 -0
  33. package/dist/controls/html/Span/Span.js.map +1 -1
  34. package/dist/controls/jsonViewAwesome/jsonFormatter/JsonFormatter.d.ts +2 -1
  35. package/dist/controls/jsonViewAwesome/jsonFormatter/JsonFormatter.js +4 -0
  36. package/dist/controls/jsonViewAwesome/jsonFormatter/JsonFormatter.js.map +1 -1
  37. package/dist/controls/kendo/Editor/Editor.d.ts +2 -1
  38. package/dist/controls/kendo/Editor/Editor.js +4 -0
  39. package/dist/controls/kendo/Editor/Editor.js.map +1 -1
  40. package/dist/controls/kendo/Grid/Grid.d.ts +2 -1
  41. package/dist/controls/kendo/Grid/Grid.js +4 -0
  42. package/dist/controls/kendo/Grid/Grid.js.map +1 -1
  43. package/dist/controls/kendo/Menu/Menu.js.map +1 -1
  44. package/dist/controls/leaflet/Map/Map.d.ts +2 -1
  45. package/dist/controls/leaflet/Map/Map.js +4 -0
  46. package/dist/controls/leaflet/Map/Map.js.map +1 -1
  47. package/dist/framework/ViewModel.d.ts +2 -2
  48. package/dist/framework/ViewModel.js +2 -2
  49. package/dist/framework/ViewModel.js.map +1 -1
  50. package/package.json +3 -2
  51. package/src/controls/codeMirror/HtmlEditor/HtmlEditor.ts +153 -0
  52. package/src/controls/codeMirror/JsonEditor/JsonEditor.ts +136 -0
  53. package/src/controls/codeMirror/index.ts +2 -0
  54. package/src/controls/custom/FileSelector/FileSelector.ts +74 -0
  55. package/src/controls/custom/LabeledControl/LabeledControl.ts +58 -0
  56. package/src/controls/custom/ListItem/ListItem.ts +99 -0
  57. package/src/controls/custom/index.ts +3 -0
  58. package/src/controls/html/Button/Button.ts +70 -0
  59. package/src/controls/html/Div/Div.ts +41 -0
  60. package/src/controls/html/Image/Image.ts +46 -0
  61. package/src/controls/html/Input/Input.ts +228 -0
  62. package/src/controls/html/Select/Select.ts +146 -0
  63. package/src/controls/html/Span/Span.ts +38 -0
  64. package/src/controls/html/index.ts +6 -0
  65. package/src/controls/index.ts +15 -0
  66. package/src/controls/jsonViewAwesome/index.ts +1 -0
  67. package/src/controls/jsonViewAwesome/jsonFormatter/JsonFormatter.ts +91 -0
  68. package/src/controls/kendo/Chart/Chart.ts +97 -0
  69. package/src/controls/kendo/Culture/Culture.ts +32 -0
  70. package/src/controls/kendo/DataSource/DataSource.ts +4 -0
  71. package/src/controls/kendo/Dialog/Dialog.ts +64 -0
  72. package/src/controls/kendo/Editor/Editor.ts +142 -0
  73. package/src/controls/kendo/Grid/Grid.ts +291 -0
  74. package/src/controls/kendo/Menu/Menu.ts +125 -0
  75. package/src/controls/kendo/ObservableObject/ObservableObject.ts +45 -0
  76. package/src/controls/kendo/Tree/Tree.ts +147 -0
  77. package/src/controls/kendo/index.ts +9 -0
  78. package/src/controls/leaflet/LabelControl/LabelControl.ts +42 -0
  79. package/src/controls/leaflet/Map/Map.ts +180 -0
  80. package/src/controls/leaflet/OpenStreetMapTileLayer/OpenStreetMapTileLayer.ts +19 -0
  81. package/src/controls/leaflet/PointerEvent/PointerEvent.ts +9 -0
  82. package/src/controls/leaflet/index.ts +4 -0
  83. package/src/controls/svg/Circle/Circle.ts +34 -0
  84. package/src/controls/svg/Ellipse/Ellipse.ts +36 -0
  85. package/src/controls/svg/ForeignObject/ForeignObject.ts +38 -0
  86. package/src/controls/svg/Group/Group.ts +38 -0
  87. package/src/controls/svg/Line/Line.ts +36 -0
  88. package/src/controls/svg/Pattern/Pattern.ts +49 -0
  89. package/src/controls/svg/Polygon/Polygon.ts +31 -0
  90. package/src/controls/svg/Polyline/Polyline.ts +31 -0
  91. package/src/controls/svg/Rectangle/Rectangle.ts +36 -0
  92. package/src/controls/svg/Svg/Svg.ts +43 -0
  93. package/src/controls/svg/Text/Text.ts +38 -0
  94. package/src/controls/svg/Title/Title.ts +28 -0
  95. package/src/controls/svg/index.ts +13 -0
  96. package/src/controls/svg/svg.ts +20 -0
  97. package/src/framework/View.ts +213 -0
  98. package/src/framework/ViewModel.ts +525 -0
  99. package/src/framework/attributes.ts +92 -0
  100. package/src/framework/event.ts +98 -0
  101. package/src/framework/observable.ts +80 -0
  102. package/src/framework/style.ts +3271 -0
  103. package/src/framework/types.ts +277 -0
  104. package/src/framework/userAgent.ts +51 -0
  105. package/src/index.ts +14 -0
  106. package/src/utilities/blob/blob.ts +19 -0
  107. package/src/utilities/cookie/cookie.ts +28 -0
  108. package/src/utilities/dataReaderTable/dataReaderTable.ts +34 -0
  109. package/src/utilities/fetch/fetch.ts +179 -0
  110. package/src/utilities/float/float.ts +3 -0
  111. package/src/utilities/formData/formData.ts +12 -0
  112. package/src/utilities/html/html.ts +8 -0
  113. package/src/utilities/htmlElement/htmlElement.ts +15 -0
  114. package/src/utilities/image/image.ts +1 -0
  115. package/src/utilities/index.ts +37 -0
  116. package/src/utilities/integer/integer.ts +31 -0
  117. package/src/utilities/key/key.ts +7 -0
  118. package/src/utilities/navigator/navigator.ts +7 -0
  119. package/src/utilities/notification/notification.ts +88 -0
  120. package/src/utilities/querystring/querystring.ts +61 -0
  121. package/src/utilities/router/router.ts +124 -0
  122. package/src/utilities/stylesheet/stylesheet.ts +58 -0
  123. package/src/utilities/uniqueId/uniqueId.ts +5 -0
  124. package/src/utilities/webSocket/webSocket.ts +72 -0
@@ -0,0 +1,97 @@
1
+ import * as kendo from "@progress/kendo-ui/js/dataviz/chart/chart.js";
2
+ import { View } from "../../../framework/View";
3
+ import { Properties, extendProperties} from "../../../framework/ViewModel";
4
+ import { Subscribable, unwrap, isSubscribable } from "knockout";
5
+
6
+ export interface ChartProperties extends Properties {
7
+ data?: Array<any> | Subscribable<Array<any>>;
8
+ chartArea?: kendo.dataviz.ui.ChartChartArea | undefined;
9
+ series?: kendo.dataviz.ui.ChartSeriesItem[] | Subscribable<kendo.dataviz.ui.ChartSeriesItem[]>;
10
+ categoryAxis?: kendo.dataviz.ui.ChartCategoryAxisItem | kendo.dataviz.ui.ChartCategoryAxisItem[] | Subscribable<kendo.dataviz.ui.ChartCategoryAxisItem | kendo.dataviz.ui.ChartCategoryAxisItem[]>;
11
+ valueAxis?: kendo.dataviz.ui.ChartValueAxisItem | kendo.dataviz.ui.ChartValueAxisItem[] | undefined;
12
+ legend?: kendo.dataviz.ui.ChartLegend | undefined;
13
+ }
14
+
15
+ export class ChartView extends View<ChartProperties>{
16
+ constructor(properties: ChartProperties) {
17
+ super(
18
+ {
19
+ tagName: "div",
20
+ properties: extendProperties(
21
+ {
22
+ viewType: "KendoChart"
23
+ },
24
+ properties
25
+ )
26
+ }
27
+ );
28
+ }
29
+
30
+ private chart: kendo.dataviz.ui.Chart;
31
+ private dataSource: kendo.data.DataSource;
32
+
33
+ build(): void {
34
+ super.build();
35
+
36
+ const viewModel = this.properties;
37
+
38
+ if (viewModel.data) {
39
+ this.dataSource = new kendo.data.DataSource(
40
+ {
41
+ data: unwrap(viewModel.data)
42
+ }
43
+ );
44
+ }
45
+
46
+ if (isSubscribable(viewModel.data)) {
47
+ this.subscriptions.push(
48
+ viewModel.data.subscribe((data) => {
49
+ this.dataSource.data(data);
50
+ })
51
+ );
52
+ }
53
+
54
+ setTimeout(() => {
55
+ this.chart = new kendo.dataviz.ui.Chart(
56
+ this.element,
57
+ {
58
+ autoBind: false,
59
+ legend: viewModel.legend,
60
+ dataSource: this.dataSource,
61
+ chartArea: viewModel.chartArea,
62
+ series: unwrap(viewModel.series),
63
+ categoryAxis: unwrap(viewModel.categoryAxis),
64
+ valueAxis: viewModel.valueAxis
65
+ }
66
+ );
67
+ });
68
+
69
+ if (isSubscribable(viewModel.series)) {
70
+ this.subscriptions.push(
71
+ viewModel.series.subscribe((series) => {
72
+ if (this.chart) {
73
+ this.chart.setOptions({
74
+ series: series
75
+ });
76
+ }
77
+ })
78
+ );
79
+ }
80
+
81
+ if (isSubscribable(viewModel.categoryAxis)) {
82
+ this.subscriptions.push(
83
+ viewModel.categoryAxis.subscribe((categoryAxis) => {
84
+ if (this.chart) {
85
+ this.chart.setOptions({
86
+ categoryAxis: categoryAxis
87
+ });
88
+ }
89
+ })
90
+ );
91
+ }
92
+ }
93
+ }
94
+
95
+ export function chartView(properties: ChartProperties) {
96
+ return new ChartView(properties);
97
+ }
@@ -0,0 +1,32 @@
1
+ import { getScript } from "jquery";
2
+ import kendo from "@progress/kendo-ui/js/kendo.core";
3
+
4
+ export async function setCulture(cultureCode: string) {
5
+ if (!cultureCode || cultureCode === "en-US") return;
6
+
7
+ const kendoVersion = "2021.1.330";
8
+ const urlPrefix = "https://kendo.cdn.telerik.com/" + kendoVersion + "/js/";
9
+ const urlPostfix = "." + cultureCode + ".min.js";
10
+
11
+ try {
12
+ await getScript(urlPrefix + "cultures/kendo.culture" + urlPostfix);
13
+
14
+ //If the culture has been successfully loaded then we set the culture as active culture
15
+ kendo.culture(cultureCode);
16
+ //console.log("Culture loaded for " + cultureCode);
17
+ } catch (ec) {
18
+ const error = ec as Error;
19
+ //If the culture can not be loaded then we fall back to en-US
20
+ kendo.culture("en-US");
21
+ console.log("Failed loading culture for " + cultureCode + ": " + error.message);
22
+ }
23
+
24
+ try {
25
+ await getScript(urlPrefix + "messages/kendo.messages" + urlPostfix);
26
+
27
+ //console.log("Messages loaded for " + cultureCode);
28
+ } catch (em) {
29
+ const error = em as Error;
30
+ console.log("Failed loading messages for " + cultureCode + ": " + error.message);
31
+ }
32
+ }
@@ -0,0 +1,4 @@
1
+ export interface ChangedItem {
2
+ key: string;
3
+ dirtyFields: object;
4
+ }
@@ -0,0 +1,64 @@
1
+ import * as kendo from "@progress/kendo-ui/js/kendo.window.js";
2
+ import { View } from "../../../framework/View";
3
+ import { DivView } from "../../html/Div/Div";
4
+ import { ButtonView } from "../../html/Button/Button";
5
+
6
+ export interface DialogOptions {
7
+ content?: View;
8
+ buttons?: Array<ButtonView>;
9
+ }
10
+
11
+ export class Dialog {
12
+ constructor(options: DialogOptions) {
13
+ this.options = options;
14
+ }
15
+
16
+ private options: DialogOptions;
17
+ private dialog: kendo.ui.Window;
18
+
19
+ open() {
20
+ this.dialog = new kendo.ui.Window(
21
+ document.createElement("div"),
22
+ {
23
+ modal: true,
24
+ maxHeight: (window as Window).innerHeight * 0.9,
25
+ maxWidth: (window as Window).innerWidth * 0.9,
26
+ open: (x) => {
27
+ console.log(x);
28
+ this.dialog.center();
29
+ const wrapper = this.dialog.wrapper.get(0) as HTMLElement;
30
+ if (this.options.content) {
31
+ const content = wrapper.querySelector(".k-window-content");
32
+ if (content) {
33
+ content.appendChild(this.options.content.render());
34
+ }
35
+ }
36
+ if (this.options.buttons) {
37
+ const footer = new DivView({
38
+ children: this.options.buttons,
39
+ style: {
40
+ display: "flex",
41
+ justifyContent: "flex-end",
42
+ borderTop: "1px solid gray",
43
+ padding: "5px"
44
+ }
45
+ });
46
+ wrapper.appendChild(footer.render());
47
+ }
48
+ }
49
+ }
50
+ );
51
+
52
+ this.dialog.open();
53
+ }
54
+
55
+ close() {
56
+ if (this.dialog) {
57
+ this.dialog.close();
58
+ }
59
+ }
60
+ }
61
+
62
+ export function dialog(options: DialogOptions) {
63
+ return new Dialog(options);
64
+ }
@@ -0,0 +1,142 @@
1
+ import * as kendo from "@progress/kendo-ui/js/kendo.editor.js";
2
+ import { View, registerView } from "../../../framework/View";
3
+ import { Properties, ViewModel, extendProperties } from "../../../framework/ViewModel";
4
+ import { unwrap, isObservable, computed, observable } from "knockout";
5
+ import { isObservableProperty, ObservableProperty } from "../../../framework/observable";
6
+ import { DivView } from "../../html/Div/Div";
7
+ import { ButtonView } from "../../html/Button/Button";
8
+ import { prettifyHtml } from "../../../utilities/html/html";
9
+
10
+ export interface EditorProperties extends Properties {
11
+ value?: string | ObservableProperty<string>;
12
+ tools?: string[] | kendo.ui.EditorTool[];
13
+ }
14
+
15
+ export class EditorView extends View<EditorProperties> {
16
+ constructor(properties: EditorProperties) {
17
+ super(
18
+ {
19
+ tagName: "div",
20
+ properties: extendProperties(
21
+ {
22
+ viewType: "KendoEditor",
23
+ style: {
24
+ display: "flex",
25
+ flexDirection: "column"
26
+ }
27
+ },
28
+ properties
29
+ )
30
+ }
31
+ );
32
+ }
33
+
34
+ private editor: kendo.ui.Editor;
35
+
36
+ build(): void {
37
+ super.build();
38
+
39
+ const viewModel = this.properties;
40
+
41
+ const htmlMode = observable<boolean>(false);
42
+
43
+ const divHeader = new DivView({
44
+ children: [
45
+ new ButtonView({
46
+ content: computed<string>(() => {
47
+ return htmlMode() ? "wysiwyg" : "view html source";
48
+ }),
49
+ eventListeners: {
50
+ click: {
51
+ listener: () => {
52
+ htmlMode(!htmlMode());
53
+ }
54
+ }
55
+ },
56
+ style: {
57
+ width: "120px",
58
+ marginTop: "2px"
59
+ }
60
+ })
61
+ ]
62
+ }).render();
63
+
64
+ const divElement = new DivView({
65
+ visible: computed<boolean>(() => {
66
+ return !htmlMode();
67
+ }),
68
+ style: {
69
+ flexGrow: 1
70
+ }
71
+ }).render();
72
+
73
+ const textAreaElement = new View({
74
+ tagName: "textarea",
75
+ properties: {
76
+ visible: htmlMode,
77
+ style: {
78
+ flexGrow: 1,
79
+ borderColor: "transparent",
80
+ borderRadius: "4px"
81
+ }
82
+ }
83
+ }).render() as HTMLTextAreaElement;
84
+
85
+ this.element.appendChild(divElement);
86
+ this.element.appendChild(textAreaElement);
87
+ this.element.appendChild(divHeader);
88
+
89
+ const html = unwrap(viewModel.value);
90
+ divElement.innerHTML = html;
91
+ textAreaElement.value = prettifyHtml(html);
92
+
93
+ if (isObservable(viewModel.value)) {
94
+ this.subscriptions.push(
95
+ viewModel.value.subscribe((value) => {
96
+ divElement.innerHTML = value;
97
+ textAreaElement.value = value;
98
+ })
99
+ );
100
+ }
101
+
102
+ this.editor = new kendo.ui.Editor(
103
+ divElement,
104
+ {
105
+ tools: viewModel.tools
106
+ }
107
+ );
108
+
109
+ this.editor.bind(
110
+ "change",
111
+ () => {
112
+ if (isObservableProperty(viewModel.value)) {
113
+ viewModel.value.set(divElement.innerHTML);
114
+ }
115
+ }
116
+ );
117
+
118
+ textAreaElement.addEventListener("change", () => {
119
+ if (isObservableProperty(viewModel.value)) {
120
+ viewModel.value.set(textAreaElement.value);
121
+ }
122
+ });
123
+ }
124
+ }
125
+
126
+ export function editorView(properties: EditorProperties) {
127
+ return new EditorView(properties);
128
+ }
129
+
130
+ export class EditorViewModel extends ViewModel implements EditorProperties {
131
+ constructor(properties: EditorProperties) {
132
+ super();
133
+ this.setProperties(this, properties);
134
+ }
135
+ value?: string | ObservableProperty<string>;
136
+ tools?: string[] | kendo.ui.EditorTool[];
137
+ }
138
+
139
+ registerView(
140
+ EditorViewModel,
141
+ EditorView
142
+ )
@@ -0,0 +1,291 @@
1
+ import * as kendo from "@progress/kendo-ui/js/kendo.grid.js";
2
+ import { View, registerView } from "../../../framework/View";
3
+ import { Properties, ViewModel, extendProperties } from "../../../framework/ViewModel";
4
+ import { ObservableArrayProperty, ObservableProperty } from "../../../framework/observable";
5
+ import { unwrap, utils, Subscribable, isSubscribable } from "knockout";
6
+ import { ChangedItem } from "../DataSource/DataSource";
7
+ import { knockoutObservableToKendoObservableArray, getUnderlyingObject } from "../ObservableObject/ObservableObject";
8
+
9
+ export interface GridProperties<TItem> extends Properties {
10
+ items?: Array<TItem> | Subscribable<Array<TItem>>;
11
+ idProperty?: keyof TItem;
12
+ columns?: Array<kendo.ui.GridColumn>;
13
+ pageSize?: number;
14
+ sortable?: boolean | kendo.ui.GridSortable;
15
+ scrollable?: kendo.ui.GridScrollable;
16
+ editable?: kendo.ui.GridEditable;
17
+ filterable?: boolean | kendo.ui.GridFilterable | Subscribable<boolean | kendo.ui.GridFilterable>;
18
+ toolbar?: string | Array<string>;
19
+ selectable?: boolean | string;
20
+ selectedItem?: TItem | Subscribable<TItem>;
21
+ selectedItems?: Array<TItem> | Subscribable<Array<TItem>>;
22
+ onDataSourceChange?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
23
+ onDataSourceAdd?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
24
+ onDataSourceRemove?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
25
+ onGridChange?: (selectedItems: Array<any>, grid: kendo.ui.Grid) => void;
26
+ onRowContextMenu?: (event: PointerEvent, dataItem: any) => void;
27
+ }
28
+
29
+ export class GridView<TItem = any> extends View<GridProperties<TItem>> {
30
+ constructor(properties: GridProperties<TItem>) {
31
+ super(
32
+ {
33
+ tagName: "div",
34
+ properties: extendProperties(
35
+ {
36
+ viewType: "KendoGrid"
37
+ },
38
+ properties
39
+ )
40
+ }
41
+ );
42
+ }
43
+
44
+ private grid: kendo.ui.Grid;
45
+ private dataSource: kendo.data.DataSource;
46
+
47
+ private getItemById(id) {
48
+ if (this.properties.idProperty) {
49
+ const items = this.dataSource.data() as any as Array<any>;
50
+ return utils.arrayFirst(items, (item) => { return item[this.properties.idProperty] === id });
51
+ }
52
+
53
+ throw "Can only getItem when idProperty is set";
54
+ }
55
+
56
+ build(): void {
57
+ super.build();
58
+
59
+ const viewModel = this.properties;
60
+
61
+ this.dataSource = new kendo.data.DataSource({
62
+ data: knockoutObservableToKendoObservableArray(viewModel.items),
63
+ pageSize: this.properties.pageSize || 30,
64
+ change: (event: kendo.data.DataSourceChangeEvent) => {
65
+ var items = event.items as Array<ChangedItem>;
66
+ switch (event.action) {
67
+ case "itemchange":
68
+ if (viewModel.onDataSourceChange) {
69
+ viewModel.onDataSourceChange(items, event.sender);
70
+ }
71
+ break;
72
+
73
+ case "add":
74
+ if (viewModel.onDataSourceAdd) {
75
+ viewModel.onDataSourceAdd(items, event.sender);
76
+ }
77
+ break;
78
+
79
+ case "remove":
80
+ if (viewModel.onDataSourceRemove) {
81
+ viewModel.onDataSourceRemove(items, event.sender);
82
+ }
83
+ break;
84
+ }
85
+ }
86
+ });
87
+
88
+ this.grid = new kendo.ui.Grid(this.element, {
89
+ dataSource: this.dataSource,
90
+ columns: this.properties.columns,
91
+ toolbar: this.properties.toolbar,
92
+ scrollable: this.properties.scrollable,
93
+ sortable: this.properties.sortable,
94
+ editable: this.properties.editable,
95
+ filterable: unwrap(this.properties.filterable),
96
+ change: (event: kendo.ui.GridChangeEvent) => {
97
+ if (this.properties.selectedItem) {
98
+ const selectedItem = getSelectedDataItem(event.sender);
99
+ const observableProperty = this.properties.selectedItem as ObservableProperty;
100
+ if (observableProperty.set) {
101
+ observableProperty.set(selectedItem);
102
+ }
103
+ }
104
+ if (this.properties.selectedItems) {
105
+ const selectedItems = getSelectedDataItems<TItem>(event.sender);
106
+ const observableArrayProperty = this.properties.selectedItems as ObservableArrayProperty<TItem>;
107
+ if (observableArrayProperty.set) {
108
+ observableArrayProperty.set(selectedItems);
109
+ }
110
+ }
111
+
112
+ if (this.properties.onGridChange) {
113
+ this.properties.onGridChange(getSelectedDataItems<TItem>(event.sender), event.sender);
114
+ }
115
+ },
116
+ selectable: this.properties.selectable
117
+ });
118
+
119
+ if (viewModel.onRowContextMenu) {
120
+ this.grid.table.contextmenu((event: PointerEvent) => {
121
+ event.preventDefault();
122
+ var target = event.target;
123
+ var row: HTMLTableRowElement;
124
+
125
+ if (target instanceof HTMLElement) {
126
+ switch (target.tagName.toLowerCase()) {
127
+ case "td":
128
+ row = target.parentElement as HTMLTableRowElement;
129
+ break;
130
+
131
+ case "tr":
132
+ row = target as HTMLTableRowElement;
133
+ break;
134
+ }
135
+ }
136
+
137
+ if (row) {
138
+ let dataItem = this.grid.dataItem(row);
139
+ if (dataItem) {
140
+ const underlyingObject = getUnderlyingObject(dataItem);
141
+ if (underlyingObject) {
142
+ dataItem = underlyingObject as any;
143
+ }
144
+ setTimeout(() => {
145
+ viewModel.onRowContextMenu(event, dataItem);
146
+ });
147
+
148
+ };
149
+ }
150
+ });
151
+ }
152
+ if (isSubscribable(viewModel.items)) {
153
+ this.subscriptions.push(
154
+ viewModel.items.subscribe((items) => {
155
+ if (items) {
156
+ this.dataSource.data(new kendo.data.ObservableArray(knockoutObservableToKendoObservableArray(items)));
157
+ } else {
158
+ this.dataSource.data([]);
159
+ }
160
+ })
161
+ );
162
+ }
163
+ if (isSubscribable(viewModel.filterable)) {
164
+ this.subscriptions.push(
165
+ viewModel.filterable.subscribe((filterable) => {
166
+ this.grid.setOptions({ filterable: filterable });
167
+ })
168
+ );
169
+ }
170
+
171
+ if (isSubscribable(viewModel.selectedItem)) {
172
+ this.subscriptions.push(
173
+ viewModel.selectedItem.subscribe((selectedItem: TItem) => {
174
+ if (selectedItem && viewModel.idProperty) {
175
+ setTimeout(
176
+ () => {
177
+ const id = selectedItem[viewModel.idProperty];
178
+ const item = this.getItemById(id);
179
+ //Remove previous selected row
180
+ this.grid.tbody.find("tr.k-state-selected").removeClass("k-state-selected");
181
+ //Add the selected class to the newly selected row
182
+ this.grid.tbody.find("tr[data-uid='" + item.uid + "']").addClass("k-state-selected");
183
+ },
184
+ 10
185
+ );
186
+ } else {
187
+ this.grid.select();
188
+ }
189
+ })
190
+ );
191
+ }
192
+
193
+ if (isSubscribable(viewModel.selectedItems)) {
194
+ this.subscriptions.push(
195
+ viewModel.selectedItems.subscribe((selectedItems: Array<TItem>) => {
196
+ if (selectedItems && selectedItems.length > 0 && viewModel.idProperty) {
197
+ setTimeout(
198
+ () => {
199
+ //Remove all previous selected rows
200
+ this.grid.tbody.find("tr.k-state-selected").removeClass("k-state-selected");
201
+ for (let index = 0; index < selectedItems.length; index++) {
202
+ const selectedItem = selectedItems[index];
203
+ const id = selectedItem[viewModel.idProperty];
204
+ const item = this.getItemById(id);
205
+
206
+ //Add the selected class to the newly selected row
207
+ this.grid.tbody.find("tr[data-uid='" + item.uid + "']").addClass("k-state-selected");
208
+ }
209
+ },
210
+ 10
211
+ );
212
+ } else {
213
+ this.grid.select();
214
+ }
215
+ })
216
+ );
217
+ }
218
+
219
+ //Force the grid to repaint to show the scrollbar properly
220
+ setTimeout(() => {
221
+ this.grid.resize(true);
222
+ }, 5);
223
+ }
224
+ }
225
+
226
+ export function gridView<TItem>(properties: GridProperties<TItem>) {
227
+ return new GridView(properties);
228
+ }
229
+
230
+ export function getSelectedDataItem<TDataItem>(grid: kendo.ui.Grid): TDataItem {
231
+ const selection = grid.select() as any as Array<any>;
232
+ if (selection.length === 1) {
233
+ const dataItem = grid.dataItem(selection[0]);
234
+ const underlyingObject = getUnderlyingObject(dataItem);
235
+ if (underlyingObject) {
236
+ return underlyingObject as any as TDataItem;
237
+ }
238
+ return dataItem.toJSON() as TDataItem;
239
+ }
240
+
241
+ return null;
242
+ }
243
+
244
+ export function getSelectedDataItems<TItem>(grid: kendo.ui.Grid): Array<TItem> {
245
+ const selection = grid.select() as any as Array<any>;
246
+ const selectedDataItems = new Array();
247
+ if (selection && selection.length > 0) {
248
+ for (let index = 0; index < selection.length; index++) {
249
+ const dataItem = grid.dataItem(selection[index]);
250
+ const underlyingObject = getUnderlyingObject(dataItem);
251
+ if (underlyingObject) {
252
+ selectedDataItems.push(underlyingObject);
253
+ } else {
254
+ selectedDataItems.push(dataItem.toJSON());
255
+ }
256
+ }
257
+ }
258
+
259
+ return selectedDataItems;
260
+ }
261
+
262
+ export class GridViewModel<TItem = any> extends ViewModel implements GridProperties<TItem>
263
+ {
264
+ constructor(properties: GridProperties<TItem>) {
265
+ super();
266
+ this.setProperties(this, properties);
267
+ }
268
+
269
+ items?: Array<TItem> | Subscribable<Array<TItem>>;
270
+ idProperty?: keyof TItem;
271
+ columns?: Array<kendo.ui.GridColumn>;
272
+ pageSize?: number;
273
+ sortable?: boolean | kendo.ui.GridSortable;
274
+ scrollable?: kendo.ui.GridScrollable;
275
+ editable?: kendo.ui.GridEditable;
276
+ filterable?: boolean | kendo.ui.GridFilterable | Subscribable<boolean | kendo.ui.GridFilterable>;
277
+ toolbar?: string | Array<string>;
278
+ selectable?: boolean | string;
279
+ selectedItem?: TItem | Subscribable<TItem>;
280
+ selectedItems?: Array<TItem> | Subscribable<Array<TItem>>;
281
+ onDataSourceChange?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
282
+ onDataSourceAdd?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
283
+ onDataSourceRemove?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
284
+ onGridChange?: (selectedItems: Array<any>, grid: kendo.ui.Grid) => void;
285
+ onRowContextMenu?: (event: PointerEvent, dataItem: any) => void;
286
+ }
287
+
288
+ registerView(
289
+ GridViewModel,
290
+ GridView
291
+ );