jpf 4.2.15 → 4.2.16

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 (76) hide show
  1. package/dist/controls/kendo/Menu/Menu.js.map +1 -1
  2. package/package.json +2 -1
  3. package/src/controls/codeMirror/HtmlEditor/HtmlEditor.ts +149 -0
  4. package/src/controls/codeMirror/JsonEditor/JsonEditor.ts +132 -0
  5. package/src/controls/codeMirror/index.ts +2 -0
  6. package/src/controls/custom/FileSelector/FileSelector.ts +70 -0
  7. package/src/controls/custom/LabeledControl/LabeledControl.ts +54 -0
  8. package/src/controls/custom/ListItem/ListItem.ts +91 -0
  9. package/src/controls/custom/index.ts +3 -0
  10. package/src/controls/html/Button/Button.ts +66 -0
  11. package/src/controls/html/Div/Div.ts +37 -0
  12. package/src/controls/html/Image/Image.ts +42 -0
  13. package/src/controls/html/Input/Input.ts +223 -0
  14. package/src/controls/html/Select/Select.ts +142 -0
  15. package/src/controls/html/Span/Span.ts +35 -0
  16. package/src/controls/html/index.ts +6 -0
  17. package/src/controls/index.ts +15 -0
  18. package/src/controls/jsonViewAwesome/index.ts +1 -0
  19. package/src/controls/jsonViewAwesome/jsonFormatter/JsonFormatter.ts +87 -0
  20. package/src/controls/kendo/Chart/Chart.ts +97 -0
  21. package/src/controls/kendo/Culture/Culture.ts +32 -0
  22. package/src/controls/kendo/DataSource/DataSource.ts +4 -0
  23. package/src/controls/kendo/Dialog/Dialog.ts +64 -0
  24. package/src/controls/kendo/Editor/Editor.ts +138 -0
  25. package/src/controls/kendo/Grid/Grid.ts +286 -0
  26. package/src/controls/kendo/Menu/Menu.ts +125 -0
  27. package/src/controls/kendo/ObservableObject/ObservableObject.ts +45 -0
  28. package/src/controls/kendo/Tree/Tree.ts +147 -0
  29. package/src/controls/kendo/index.ts +9 -0
  30. package/src/controls/leaflet/LabelControl/LabelControl.ts +42 -0
  31. package/src/controls/leaflet/Map/Map.ts +177 -0
  32. package/src/controls/leaflet/OpenStreetMapTileLayer/OpenStreetMapTileLayer.ts +19 -0
  33. package/src/controls/leaflet/PointerEvent/PointerEvent.ts +9 -0
  34. package/src/controls/leaflet/index.ts +4 -0
  35. package/src/controls/svg/Circle/Circle.ts +34 -0
  36. package/src/controls/svg/Ellipse/Ellipse.ts +36 -0
  37. package/src/controls/svg/ForeignObject/ForeignObject.ts +38 -0
  38. package/src/controls/svg/Group/Group.ts +38 -0
  39. package/src/controls/svg/Line/Line.ts +36 -0
  40. package/src/controls/svg/Pattern/Pattern.ts +49 -0
  41. package/src/controls/svg/Polygon/Polygon.ts +31 -0
  42. package/src/controls/svg/Polyline/Polyline.ts +31 -0
  43. package/src/controls/svg/Rectangle/Rectangle.ts +36 -0
  44. package/src/controls/svg/Svg/Svg.ts +43 -0
  45. package/src/controls/svg/Text/Text.ts +38 -0
  46. package/src/controls/svg/Title/Title.ts +28 -0
  47. package/src/controls/svg/index.ts +13 -0
  48. package/src/controls/svg/svg.ts +20 -0
  49. package/src/framework/View.ts +213 -0
  50. package/src/framework/ViewModel.ts +525 -0
  51. package/src/framework/attributes.ts +92 -0
  52. package/src/framework/event.ts +98 -0
  53. package/src/framework/observable.ts +80 -0
  54. package/src/framework/style.ts +3271 -0
  55. package/src/framework/types.ts +277 -0
  56. package/src/framework/userAgent.ts +51 -0
  57. package/src/index.ts +14 -0
  58. package/src/utilities/blob/blob.ts +19 -0
  59. package/src/utilities/cookie/cookie.ts +28 -0
  60. package/src/utilities/dataReaderTable/dataReaderTable.ts +34 -0
  61. package/src/utilities/fetch/fetch.ts +179 -0
  62. package/src/utilities/float/float.ts +3 -0
  63. package/src/utilities/formData/formData.ts +12 -0
  64. package/src/utilities/html/html.ts +8 -0
  65. package/src/utilities/htmlElement/htmlElement.ts +15 -0
  66. package/src/utilities/image/image.ts +1 -0
  67. package/src/utilities/index.ts +37 -0
  68. package/src/utilities/integer/integer.ts +31 -0
  69. package/src/utilities/key/key.ts +7 -0
  70. package/src/utilities/navigator/navigator.ts +7 -0
  71. package/src/utilities/notification/notification.ts +88 -0
  72. package/src/utilities/querystring/querystring.ts +61 -0
  73. package/src/utilities/router/router.ts +124 -0
  74. package/src/utilities/stylesheet/stylesheet.ts +58 -0
  75. package/src/utilities/uniqueId/uniqueId.ts +5 -0
  76. package/src/utilities/webSocket/webSocket.ts +72 -0
@@ -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,138 @@
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<EditorProperties> implements EditorProperties {
131
+ value?: string | ObservableProperty<string>;
132
+ tools?: string[] | kendo.ui.EditorTool[];
133
+ }
134
+
135
+ registerView(
136
+ EditorViewModel,
137
+ EditorView
138
+ )
@@ -0,0 +1,286 @@
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<GridProperties<TItem>> implements GridProperties<TItem>
263
+ {
264
+ items?: Array<TItem> | Subscribable<Array<TItem>>;
265
+ idProperty?: keyof TItem;
266
+ columns?: Array<kendo.ui.GridColumn>;
267
+ pageSize?: number;
268
+ sortable?: boolean | kendo.ui.GridSortable;
269
+ scrollable?: kendo.ui.GridScrollable;
270
+ editable?: kendo.ui.GridEditable;
271
+ filterable?: boolean | kendo.ui.GridFilterable | Subscribable<boolean | kendo.ui.GridFilterable>;
272
+ toolbar?: string | Array<string>;
273
+ selectable?: boolean | string;
274
+ selectedItem?: TItem | Subscribable<TItem>;
275
+ selectedItems?: Array<TItem> | Subscribable<Array<TItem>>;
276
+ onDataSourceChange?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
277
+ onDataSourceAdd?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
278
+ onDataSourceRemove?: (items: Array<ChangedItem>, dataSource: kendo.data.DataSource) => void;
279
+ onGridChange?: (selectedItems: Array<any>, grid: kendo.ui.Grid) => void;
280
+ onRowContextMenu?: (event: PointerEvent, dataItem: any) => void;
281
+ }
282
+
283
+ registerView(
284
+ GridViewModel,
285
+ GridView
286
+ );
@@ -0,0 +1,125 @@
1
+ import * as kendo from "@progress/kendo-ui/js/kendo.menu.js";
2
+ import { isObservable, unwrap, Subscribable } from "knockout";
3
+ import { View, render } from "../../../framework/View";
4
+ import { ViewModel, Properties, applyBindings as applyViewModelToElement, extendProperties } from "../../../framework/ViewModel";
5
+ import { HierarchicalListItemProperties , HierarchicalListItemViewModel} from "../../custom/ListItem/ListItem";
6
+ const getContent = "getContent";
7
+
8
+ export interface MenuProperties extends Properties {
9
+ items?: Array<HierarchicalListItemProperties| HierarchicalListItemViewModel > | Subscribable<Array<HierarchicalListItemProperties| HierarchicalListItemViewModel>>;
10
+ }
11
+
12
+ export class MenuView extends View<MenuProperties> {
13
+ constructor(properties: MenuProperties) {
14
+ super(
15
+ {
16
+ tagName: "div",
17
+ properties: extendProperties(
18
+ {
19
+ classNames: ["Menu"],
20
+ viewType: "KendoMenu"
21
+ },
22
+ properties
23
+ )
24
+ }
25
+ );
26
+ }
27
+
28
+ private menu: kendo.ui.Menu;
29
+ private dataSource: kendo.data.HierarchicalDataSource;
30
+
31
+ build(): void {
32
+ super.build();
33
+
34
+ const viewModel = this.properties;
35
+
36
+ this.dataSource = new kendo.data.HierarchicalDataSource({});
37
+ this.menu = new kendo.ui.Menu(this.element, {
38
+ dataTextField: "text",
39
+ dataSource: this.dataSource
40
+ });
41
+
42
+ this.menu.bind(
43
+ "dataBound",
44
+ (event) => {
45
+ //Find all menuitems that needs to be post rendered.
46
+ event.sender.wrapper.find(".k-menu-item[postrender]").each((index, element: HTMLElement) => {
47
+ const uid = element.getAttribute("data-uid");
48
+ const hierarchicalListItemViewModel = this.dataSource.getByUid(uid) as any as HierarchicalListItemProperties;
49
+ if (hierarchicalListItemViewModel) {
50
+ applyViewModelToElement(hierarchicalListItemViewModel, element, this.subscriptions);
51
+
52
+
53
+ if (hierarchicalListItemViewModel[getContent]) {
54
+ const content = hierarchicalListItemViewModel[getContent]();
55
+ if (content instanceof ViewModel) {
56
+ const firstChild = element.firstElementChild as HTMLElement;
57
+ firstChild.style.padding = "0";
58
+ firstChild.innerHTML = "";
59
+ firstChild.appendChild(render(content));
60
+ }
61
+ }
62
+ }
63
+ element.removeAttribute("postrender");
64
+ });
65
+ }
66
+ );
67
+
68
+ this.buildItems(unwrap(viewModel.items));
69
+ if (isObservable(viewModel.items)) {
70
+ this.subscriptions.push(
71
+ viewModel.items.subscribe((items) => {
72
+ this.buildItems(items);
73
+ })
74
+ );
75
+ }
76
+ }
77
+
78
+ private buildItems(listItems: Array<HierarchicalListItemProperties| HierarchicalListItemViewModel>) {
79
+ const itemDictionary: { [id: string]: HierarchicalListItemProperties } = {};
80
+ const topLevelItems = new Array<HierarchicalListItemProperties>();
81
+
82
+ if (listItems) {
83
+ //Add all visible menuItems to a dictionary
84
+ listItems.forEach((listItem) => {
85
+ if (listItem as any instanceof ViewModel) {
86
+ listItem["attr"] = { postrender: true };
87
+ }
88
+
89
+ if (typeof listItem.text !== "string") {
90
+ var content = listItem.text;
91
+ listItem[getContent] = () => { return content };
92
+ listItem.text = "<post>";
93
+ }
94
+ if (unwrap(listItem.visible) !== false) {
95
+ itemDictionary[listItem.id] = listItem;
96
+ }
97
+ });
98
+
99
+ //Add all the children to their parent
100
+ Object.keys(itemDictionary).forEach((key) => {
101
+ const menuItem = itemDictionary[key];
102
+
103
+ if (menuItem.parentId) {
104
+ //Add the menuItem to its parent
105
+ const parent = itemDictionary[menuItem.parentId];
106
+ if (parent) {
107
+ if (!parent.items) {
108
+ parent.items = [];
109
+ }
110
+ parent.items.push(itemDictionary[menuItem.id]);
111
+ }
112
+ } else {
113
+ //Add the menuItem to the top level items
114
+ topLevelItems.push(itemDictionary[menuItem.id]);
115
+ }
116
+ });
117
+ }
118
+
119
+ this.dataSource.data(topLevelItems);
120
+ }
121
+ }
122
+
123
+ export function menuView(properties: MenuProperties) {
124
+ return new MenuView(properties);
125
+ }
@@ -0,0 +1,45 @@
1
+ import { Subscribable, isObservable, unwrap } from "knockout";
2
+ import * as kendo from "@progress/kendo-ui/js/kendo.data.js";
3
+
4
+ var getUnderlyingObjectFunctionName = "getUnderlyingObject";
5
+
6
+ export function knockoutObservableToKendoObservable(object: object): kendo.data.ObservableObject {
7
+ var observableObject = new kendo.data.ObservableObject();
8
+ observableObject[getUnderlyingObjectFunctionName] = () => {
9
+ return object;
10
+ }
11
+ Object.keys(object).forEach((key: string) => {
12
+ var value = object[key];
13
+
14
+ observableObject[key] = unwrap(value);
15
+
16
+ if (isObservable(value)) {
17
+ value.subscribe(
18
+ (newValue) => {
19
+ observableObject.set(key, newValue);
20
+ }
21
+ );
22
+ }
23
+ });
24
+
25
+ return observableObject;
26
+ }
27
+
28
+ export function getUnderlyingObject(observableObject: kendo.data.ObservableObject): object {
29
+ if (observableObject[getUnderlyingObjectFunctionName]) {
30
+ return observableObject[getUnderlyingObjectFunctionName]();
31
+ }
32
+ return null;
33
+ }
34
+
35
+ export function knockoutObservableToKendoObservableArray(array: Array<any> | Subscribable<Array<any>>): Array<kendo.data.ObservableObject> {
36
+
37
+ var observableObjects = new Array<kendo.data.ObservableObject>();
38
+ if (array) {
39
+ unwrap(array).forEach((object) => {
40
+ observableObjects.push(knockoutObservableToKendoObservable(object));
41
+ });
42
+ }
43
+
44
+ return observableObjects;
45
+ }