jpf 4.2.14 → 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.
- package/dist/controls/kendo/Menu/Menu.js.map +1 -1
- package/dist/framework/ViewModel.js +5 -3
- package/dist/framework/ViewModel.js.map +1 -1
- package/package.json +2 -1
- package/src/controls/codeMirror/HtmlEditor/HtmlEditor.ts +149 -0
- package/src/controls/codeMirror/JsonEditor/JsonEditor.ts +132 -0
- package/src/controls/codeMirror/index.ts +2 -0
- package/src/controls/custom/FileSelector/FileSelector.ts +70 -0
- package/src/controls/custom/LabeledControl/LabeledControl.ts +54 -0
- package/src/controls/custom/ListItem/ListItem.ts +91 -0
- package/src/controls/custom/index.ts +3 -0
- package/src/controls/html/Button/Button.ts +66 -0
- package/src/controls/html/Div/Div.ts +37 -0
- package/src/controls/html/Image/Image.ts +42 -0
- package/src/controls/html/Input/Input.ts +223 -0
- package/src/controls/html/Select/Select.ts +142 -0
- package/src/controls/html/Span/Span.ts +35 -0
- package/src/controls/html/index.ts +6 -0
- package/src/controls/index.ts +15 -0
- package/src/controls/jsonViewAwesome/index.ts +1 -0
- package/src/controls/jsonViewAwesome/jsonFormatter/JsonFormatter.ts +87 -0
- package/src/controls/kendo/Chart/Chart.ts +97 -0
- package/src/controls/kendo/Culture/Culture.ts +32 -0
- package/src/controls/kendo/DataSource/DataSource.ts +4 -0
- package/src/controls/kendo/Dialog/Dialog.ts +64 -0
- package/src/controls/kendo/Editor/Editor.ts +138 -0
- package/src/controls/kendo/Grid/Grid.ts +286 -0
- package/src/controls/kendo/Menu/Menu.ts +125 -0
- package/src/controls/kendo/ObservableObject/ObservableObject.ts +45 -0
- package/src/controls/kendo/Tree/Tree.ts +147 -0
- package/src/controls/kendo/index.ts +9 -0
- package/src/controls/leaflet/LabelControl/LabelControl.ts +42 -0
- package/src/controls/leaflet/Map/Map.ts +177 -0
- package/src/controls/leaflet/OpenStreetMapTileLayer/OpenStreetMapTileLayer.ts +19 -0
- package/src/controls/leaflet/PointerEvent/PointerEvent.ts +9 -0
- package/src/controls/leaflet/index.ts +4 -0
- package/src/controls/svg/Circle/Circle.ts +34 -0
- package/src/controls/svg/Ellipse/Ellipse.ts +36 -0
- package/src/controls/svg/ForeignObject/ForeignObject.ts +38 -0
- package/src/controls/svg/Group/Group.ts +38 -0
- package/src/controls/svg/Line/Line.ts +36 -0
- package/src/controls/svg/Pattern/Pattern.ts +49 -0
- package/src/controls/svg/Polygon/Polygon.ts +31 -0
- package/src/controls/svg/Polyline/Polyline.ts +31 -0
- package/src/controls/svg/Rectangle/Rectangle.ts +36 -0
- package/src/controls/svg/Svg/Svg.ts +43 -0
- package/src/controls/svg/Text/Text.ts +38 -0
- package/src/controls/svg/Title/Title.ts +28 -0
- package/src/controls/svg/index.ts +13 -0
- package/src/controls/svg/svg.ts +20 -0
- package/src/framework/View.ts +213 -0
- package/src/framework/ViewModel.ts +525 -0
- package/src/framework/attributes.ts +92 -0
- package/src/framework/event.ts +98 -0
- package/src/framework/observable.ts +80 -0
- package/src/framework/style.ts +3271 -0
- package/src/framework/types.ts +277 -0
- package/src/framework/userAgent.ts +51 -0
- package/src/index.ts +14 -0
- package/src/utilities/blob/blob.ts +19 -0
- package/src/utilities/cookie/cookie.ts +28 -0
- package/src/utilities/dataReaderTable/dataReaderTable.ts +34 -0
- package/src/utilities/fetch/fetch.ts +179 -0
- package/src/utilities/float/float.ts +3 -0
- package/src/utilities/formData/formData.ts +12 -0
- package/src/utilities/html/html.ts +8 -0
- package/src/utilities/htmlElement/htmlElement.ts +15 -0
- package/src/utilities/image/image.ts +1 -0
- package/src/utilities/index.ts +37 -0
- package/src/utilities/integer/integer.ts +31 -0
- package/src/utilities/key/key.ts +7 -0
- package/src/utilities/navigator/navigator.ts +7 -0
- package/src/utilities/notification/notification.ts +88 -0
- package/src/utilities/querystring/querystring.ts +61 -0
- package/src/utilities/router/router.ts +124 -0
- package/src/utilities/stylesheet/stylesheet.ts +58 -0
- package/src/utilities/uniqueId/uniqueId.ts +5 -0
- package/src/utilities/webSocket/webSocket.ts +72 -0
|
@@ -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,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
|
+
}
|