@holoviz/panel 1.4.2 → 1.5.0-a.1
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/bundled/notificationarea/panel/1.5.0-a.1/dist/bundled/font-awesome/css/all.min.css +2 -0
- package/dist/bundled/panel/1.5.0-a.1/dist/bundled/bootstrap5/css/bootstrap.min.css +2 -0
- package/dist/bundled/panel/1.5.0-a.1/dist/bundled/bootstrap5/js/bootstrap.bundle.min.js +2 -0
- package/dist/bundled/panel/1.5.0-a.1/dist/bundled/font-awesome/css/all.min.css +2 -0
- package/dist/bundled/panel/1.5.0-a.1/dist/bundled/jquery/jquery.slim.min.js +2 -0
- package/dist/bundled/plotlyplot/panel/1.5.0-a.1/dist/bundled/jquery/jquery.slim.min.js +2 -0
- package/dist/bundled/theme/fast.css +0 -1
- package/dist/css/models/card.css +11 -0
- package/dist/lib/models/comm_manager.d.ts +1 -1
- package/dist/lib/models/comm_manager.js +16 -18
- package/dist/lib/models/comm_manager.js.map +1 -1
- package/dist/lib/models/html.d.ts +7 -7
- package/dist/lib/models/html.js +28 -25
- package/dist/lib/models/html.js.map +1 -1
- package/dist/lib/models/index.d.ts +1 -0
- package/dist/lib/models/index.js +1 -0
- package/dist/lib/models/index.js.map +1 -1
- package/dist/lib/models/layout.d.ts +5 -4
- package/dist/lib/models/layout.js +41 -36
- package/dist/lib/models/layout.js.map +1 -1
- package/dist/lib/models/pdf.js +2 -2
- package/dist/lib/models/pdf.js.map +1 -1
- package/dist/lib/models/reactive_html.d.ts +18 -17
- package/dist/lib/models/reactive_html.js +159 -138
- package/dist/lib/models/reactive_html.js.map +1 -1
- package/dist/lib/models/text_input.d.ts +25 -0
- package/dist/lib/models/text_input.js +38 -0
- package/dist/lib/models/text_input.js.map +1 -0
- package/dist/lib/styles/models/card.css.js +1 -1
- package/dist/panel.js +335 -261
- package/dist/panel.js.map +1 -1
- package/dist/panel.json +1 -1
- package/dist/panel.min.js +33 -32
- package/package.json +1 -1
- package/dist/bundled/notificationarea/panel/1.4.2/dist/bundled/font-awesome/css/all.min.css +0 -2
- package/dist/bundled/panel/1.4.2/dist/bundled/bootstrap5/css/bootstrap.min.css +0 -2
- package/dist/bundled/panel/1.4.2/dist/bundled/bootstrap5/js/bootstrap.bundle.min.js +0 -2
- package/dist/bundled/panel/1.4.2/dist/bundled/font-awesome/css/all.min.css +0 -2
- package/dist/bundled/panel/1.4.2/dist/bundled/jquery/jquery.slim.min.js +0 -2
- package/dist/bundled/plotlyplot/panel/1.4.2/dist/bundled/jquery/jquery.slim.min.js +0 -2
package/dist/lib/models/pdf.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Markup } from "@bokehjs/models/widgets/markup";
|
|
2
2
|
import { PanelMarkupView } from "./layout";
|
|
3
|
-
import {
|
|
3
|
+
import { html_decode } from "./html";
|
|
4
4
|
export class PDFView extends PanelMarkupView {
|
|
5
5
|
static __name__ = "PDFView";
|
|
6
6
|
connect_signals() {
|
|
@@ -19,7 +19,7 @@ export class PDFView extends PanelMarkupView {
|
|
|
19
19
|
this.container.innerHTML = `<embed src="${url}#page=${this.model.start_page}" type="application/pdf" width="100%" height="100%"></embed>`;
|
|
20
20
|
}
|
|
21
21
|
else {
|
|
22
|
-
const html =
|
|
22
|
+
const html = html_decode(this.model.text);
|
|
23
23
|
this.container.innerHTML = html || "";
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../../models/pdf.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAA;AACrD,OAAO,EAAC,eAAe,EAAC,MAAM,UAAU,CAAA;AACxC,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../../models/pdf.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAA;AACrD,OAAO,EAAC,eAAe,EAAC,MAAM,UAAU,CAAA;AACxC,OAAO,EAAC,WAAW,EAAC,MAAM,QAAQ,CAAA;AAElC,MAAM,OAAO,OAAQ,SAAQ,eAAe;;IAGjC,eAAe;QACtB,KAAK,CAAC,eAAe,EAAE,CAAA;QACvB,MAAM,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAC,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAA;QACtE,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA,CAAC,CAAC,CAAC,CAAA;IACnF,CAAC;IAEQ,MAAM;QACb,KAAK,CAAC,MAAM,EAAE,CAAA;QACd,IAAI,CAAC,MAAM,EAAE,CAAA;IACf,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAA;YAC1C,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;YACrC,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,eAAe,GAAG,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU,8DAA8D,CAAA;QAC3I,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACzC,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;QACvC,CAAC;IACH,CAAC;IAES,sBAAsB;QAC9B,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC7C,MAAM,UAAU,GAAG,GAAG,CAAA;QACtB,MAAM,WAAW,GAAG,EAAE,CAAA;QACtB,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC,MAAM,EAAE,MAAM,IAAI,UAAU,EAAE,CAAC;YAC3E,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,CAAA;YAChE,MAAM,YAAY,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;YACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,YAAY,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;YACvC,CAAC;YACD,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAChC,CAAC;QACD,OAAO,IAAI,IAAI,CAAC,WAAW,EAAE,EAAC,IAAI,EAAE,iBAAiB,EAAC,CAAC,CAAA;IACzD,CAAC;;AAcH,MAAM,OAAO,GAAI,SAAQ,MAAM;;IAG7B,YAAY,KAA0B;QACpC,KAAK,CAAC,KAAK,CAAC,CAAA;IACd,CAAC;IAED,MAAM,CAAU,UAAU,GAAG,qBAAqB,CAAA;IAClD;QACE,IAAI,CAAC,SAAS,CAAC,YAAY,GAAG,OAAO,CAAA;QACrC,IAAI,CAAC,MAAM,CAAY,CAAC,EAAC,GAAG,EAAE,IAAI,EAAC,EAAE,EAAE,CAAC,CAAC;YACvC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;YACpB,UAAU,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;SACrB,CAAC,CAAC,CAAA;IACL,CAAC"}
|
|
@@ -1,30 +1,31 @@
|
|
|
1
|
+
import type { Dict } from "@bokehjs/core/types";
|
|
1
2
|
import type * as p from "@bokehjs/core/properties";
|
|
2
|
-
import
|
|
3
|
+
import { Model } from "@bokehjs/model";
|
|
4
|
+
import { UIElement } from "@bokehjs/models/ui/ui_element";
|
|
3
5
|
import { HTMLBox, HTMLBoxView } from "./layout";
|
|
4
6
|
export declare class ReactiveHTMLView extends HTMLBoxView {
|
|
5
7
|
model: ReactiveHTML;
|
|
6
8
|
html: string;
|
|
7
9
|
container: HTMLDivElement;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
_state: any;
|
|
10
|
+
protected _changing: boolean;
|
|
11
|
+
protected readonly _event_listeners: Map<string, Map<string, (event: Event) => void>>;
|
|
12
|
+
protected _mutation_observers: MutationObserver[];
|
|
13
|
+
protected _script_fns: Map<string, Function>;
|
|
14
|
+
protected _state: any;
|
|
14
15
|
initialize(): void;
|
|
15
|
-
_recursive_connect(model:
|
|
16
|
+
_recursive_connect(model: Model, update_children: boolean, path: string): void;
|
|
16
17
|
connect_signals(): void;
|
|
17
18
|
connect_scripts(): void;
|
|
18
19
|
run_script(property: string, silent?: boolean): void;
|
|
19
|
-
get_records(
|
|
20
|
+
get_records(property_name: string, index?: boolean): unknown[];
|
|
20
21
|
disconnect_signals(): void;
|
|
21
22
|
remove(): void;
|
|
22
|
-
get child_models():
|
|
23
|
+
get child_models(): UIElement[];
|
|
23
24
|
_after_layout(): void;
|
|
24
25
|
render(): void;
|
|
25
26
|
private _send_event;
|
|
26
27
|
private _render_child;
|
|
27
|
-
_render_node(node:
|
|
28
|
+
_render_node(node: string, children: (string | UIElement)[]): void;
|
|
28
29
|
private _render_children;
|
|
29
30
|
private _render_html;
|
|
30
31
|
private _render_script;
|
|
@@ -38,16 +39,16 @@ export declare class ReactiveHTMLView extends HTMLBoxView {
|
|
|
38
39
|
export declare namespace ReactiveHTML {
|
|
39
40
|
type Attrs = p.AttrsOf<Props>;
|
|
40
41
|
type Props = HTMLBox.Props & {
|
|
41
|
-
attrs: p.Property<
|
|
42
|
-
callbacks: p.Property<
|
|
43
|
-
children: p.Property<
|
|
44
|
-
data: p.Property<
|
|
42
|
+
attrs: p.Property<Dict<[string, string[], string][]>>;
|
|
43
|
+
callbacks: p.Property<Dict<[string, string][]>>;
|
|
44
|
+
children: p.Property<Dict<(UIElement | string)[] | string>>;
|
|
45
|
+
data: p.Property<Model>;
|
|
45
46
|
event_params: p.Property<string[]>;
|
|
46
|
-
events: p.Property<
|
|
47
|
+
events: p.Property<Dict<Dict<boolean>>>;
|
|
47
48
|
html: p.Property<string>;
|
|
48
49
|
looped: p.Property<string[]>;
|
|
49
50
|
nodes: p.Property<string[]>;
|
|
50
|
-
scripts: p.Property<
|
|
51
|
+
scripts: p.Property<Dict<string[]>>;
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
export interface ReactiveHTML extends ReactiveHTML.Attrs {
|
|
@@ -2,71 +2,78 @@ import { render } from "preact";
|
|
|
2
2
|
import { useCallback } from "preact/hooks";
|
|
3
3
|
import { html } from "htm/preact";
|
|
4
4
|
import { div } from "@bokehjs/core/dom";
|
|
5
|
+
import { assert, unreachable } from "@bokehjs/core/util/assert";
|
|
6
|
+
import { enumerate } from "@bokehjs/core/util/iterator";
|
|
5
7
|
import { isArray, isString } from "@bokehjs/core/util/types";
|
|
8
|
+
import { dict, keys, entries } from "@bokehjs/core/util/object";
|
|
9
|
+
import { Model } from "@bokehjs/model";
|
|
10
|
+
import { UIElement } from "@bokehjs/models/ui/ui_element";
|
|
6
11
|
import { dict_to_records } from "./data";
|
|
7
12
|
import { serializeEvent } from "./event-to-object";
|
|
8
|
-
import { DOMEvent,
|
|
13
|
+
import { DOMEvent, html_decode } from "./html";
|
|
9
14
|
import { HTMLBox, HTMLBoxView } from "./layout";
|
|
10
15
|
function serialize_attrs(attrs) {
|
|
11
16
|
const serialized = {};
|
|
12
|
-
for (const attr
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
for (const [attr, value] of entries(attrs)) {
|
|
18
|
+
const serialized_value = (() => {
|
|
19
|
+
if (isString(value)) {
|
|
20
|
+
if (value !== "" && (value === "NaN" || !isNaN(Number(value)))) {
|
|
21
|
+
return Number(value);
|
|
22
|
+
}
|
|
23
|
+
else if (value === "false" || value === "true") {
|
|
24
|
+
return value === "true" ? true : false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
})();
|
|
29
|
+
serialized[attr] = serialized_value;
|
|
23
30
|
}
|
|
24
31
|
return serialized;
|
|
25
32
|
}
|
|
26
|
-
function
|
|
33
|
+
function escape_regex(string) {
|
|
27
34
|
return string.replace(/[-\/\\^$*+?.()|[\]]/g, "\\$&");
|
|
28
35
|
}
|
|
29
|
-
function
|
|
30
|
-
const
|
|
36
|
+
function extract_token(template, str, tokens) {
|
|
37
|
+
const token_mapping = new Map();
|
|
31
38
|
for (const match of tokens) {
|
|
32
|
-
|
|
39
|
+
token_mapping.set(`{${match}}`, "(.*)");
|
|
33
40
|
}
|
|
34
|
-
const
|
|
35
|
-
let
|
|
41
|
+
const token_list = [];
|
|
42
|
+
let regexp_template = `^${escape_regex(template)}$`;
|
|
36
43
|
// Find the order of the tokens
|
|
37
|
-
let i,
|
|
38
|
-
for (const m
|
|
39
|
-
|
|
44
|
+
let i, token_index, token_entry;
|
|
45
|
+
for (const [m, replacement] of token_mapping) {
|
|
46
|
+
token_index = template.indexOf(m);
|
|
40
47
|
// Token found
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
index:
|
|
48
|
+
if (token_index > -1) {
|
|
49
|
+
regexp_template = regexp_template.replace(m, replacement);
|
|
50
|
+
token_entry = {
|
|
51
|
+
index: token_index,
|
|
45
52
|
token: m,
|
|
46
53
|
};
|
|
47
|
-
for (i = 0; i <
|
|
48
|
-
;
|
|
49
|
-
}
|
|
54
|
+
for (i = 0; i < token_list.length && token_list[i].index < token_index; i++) { }
|
|
50
55
|
// Insert it at index i
|
|
51
|
-
if (i <
|
|
52
|
-
|
|
56
|
+
if (i < token_list.length) {
|
|
57
|
+
token_list.splice(i, 0, token_entry);
|
|
53
58
|
}
|
|
54
59
|
else {
|
|
55
|
-
|
|
60
|
+
token_list.push(token_entry);
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
|
-
|
|
60
|
-
const match = new RegExp(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
result = {};
|
|
64
|
+
regexp_template = regexp_template.replace(/\{[^{}]+\}/g, ".*");
|
|
65
|
+
const match = new RegExp(regexp_template).exec(str);
|
|
66
|
+
if (match != null) {
|
|
67
|
+
const result = {};
|
|
64
68
|
// Find your token entry
|
|
65
|
-
for (i = 0; i <
|
|
66
|
-
result[
|
|
69
|
+
for (i = 0; i < token_list.length; i++) {
|
|
70
|
+
result[token_list[i].token.slice(1, -1)] = match[i + 1];
|
|
67
71
|
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
return null;
|
|
68
76
|
}
|
|
69
|
-
return result;
|
|
70
77
|
}
|
|
71
78
|
function element_lookup(root, el_id) {
|
|
72
79
|
let el = root.getElementById(el_id);
|
|
@@ -79,37 +86,30 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
79
86
|
static __name__ = "ReactiveHTMLView";
|
|
80
87
|
html;
|
|
81
88
|
container;
|
|
82
|
-
_parent = null;
|
|
83
89
|
_changing = false;
|
|
84
|
-
_event_listeners =
|
|
90
|
+
_event_listeners = new Map();
|
|
85
91
|
_mutation_observers = [];
|
|
86
|
-
_script_fns =
|
|
92
|
+
_script_fns = new Map();
|
|
87
93
|
_state = {};
|
|
88
94
|
initialize() {
|
|
89
95
|
super.initialize();
|
|
90
|
-
this.html =
|
|
96
|
+
this.html = html_decode(this.model.html) ?? this.model.html;
|
|
91
97
|
}
|
|
92
98
|
_recursive_connect(model, update_children, path) {
|
|
93
|
-
for (const prop
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
subpath = `${path}.${prop}`;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
subpath = prop;
|
|
100
|
-
}
|
|
101
|
-
const obj = model[prop];
|
|
99
|
+
for (const prop of model) {
|
|
100
|
+
const subpath = path.length != 0 ? `${path}.${prop.attr}` : prop.attr;
|
|
101
|
+
const obj = prop.get_value();
|
|
102
102
|
if (obj == null) {
|
|
103
103
|
continue;
|
|
104
104
|
}
|
|
105
|
-
if (obj
|
|
105
|
+
if (obj instanceof Model) {
|
|
106
106
|
this._recursive_connect(obj, true, subpath);
|
|
107
107
|
}
|
|
108
|
-
this.on_change(
|
|
108
|
+
this.on_change(prop, () => {
|
|
109
109
|
if (update_children) {
|
|
110
|
-
for (const node
|
|
111
|
-
if (
|
|
112
|
-
let children =
|
|
110
|
+
for (const [node, attr] of entries(this.model.children)) {
|
|
111
|
+
if (attr == prop.attr) {
|
|
112
|
+
let children = prop.get_value();
|
|
113
113
|
if (!isArray(children)) {
|
|
114
114
|
children = [children];
|
|
115
115
|
}
|
|
@@ -128,7 +128,7 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
128
128
|
super.connect_signals();
|
|
129
129
|
const { children, events } = this.model.properties;
|
|
130
130
|
this.on_change(children, async () => {
|
|
131
|
-
this.html =
|
|
131
|
+
this.html = html_decode(this.model.html) ?? this.model.html;
|
|
132
132
|
await this.build_child_views();
|
|
133
133
|
this.invalidate_render();
|
|
134
134
|
});
|
|
@@ -140,32 +140,33 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
140
140
|
this.connect_scripts();
|
|
141
141
|
}
|
|
142
142
|
connect_scripts() {
|
|
143
|
-
const id = this.model.data
|
|
144
|
-
for (const prop
|
|
145
|
-
const scripts = this.model.scripts[prop];
|
|
143
|
+
const { id } = this.model.data;
|
|
144
|
+
for (const [prop, scripts] of entries(this.model.scripts)) {
|
|
146
145
|
let data_model = this.model.data;
|
|
147
146
|
let attr;
|
|
148
|
-
if (prop.
|
|
147
|
+
if (prop.includes(".")) {
|
|
149
148
|
const path = prop.split(".");
|
|
150
149
|
attr = path[path.length - 1];
|
|
151
150
|
for (const p of path.slice(0, -1)) {
|
|
152
|
-
|
|
151
|
+
const value = data_model.property(p).get_value();
|
|
152
|
+
assert(value instanceof Model);
|
|
153
|
+
data_model = value;
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
else {
|
|
156
157
|
attr = prop;
|
|
157
158
|
}
|
|
158
159
|
for (const script of scripts) {
|
|
159
|
-
const decoded_script =
|
|
160
|
+
const decoded_script = html_decode(script) ?? script;
|
|
160
161
|
const script_fn = this._render_script(decoded_script, id);
|
|
161
|
-
this._script_fns
|
|
162
|
-
|
|
163
|
-
if (property == null) {
|
|
162
|
+
this._script_fns.set(prop, script_fn);
|
|
163
|
+
if (!(attr in data_model.properties)) {
|
|
164
164
|
continue;
|
|
165
165
|
}
|
|
166
|
+
const property = data_model.property(attr);
|
|
166
167
|
const is_event_param = this.model.event_params.includes(prop);
|
|
167
168
|
this.on_change(property, () => {
|
|
168
|
-
if (!this._changing && !(is_event_param && !data_model
|
|
169
|
+
if (!this._changing && !(is_event_param && !data_model.property(prop).get_value())) {
|
|
169
170
|
this.run_script(prop);
|
|
170
171
|
if (is_event_param) {
|
|
171
172
|
data_model.setv({ [prop]: false });
|
|
@@ -176,7 +177,7 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
176
177
|
}
|
|
177
178
|
}
|
|
178
179
|
run_script(property, silent = false) {
|
|
179
|
-
const script_fn = this._script_fns
|
|
180
|
+
const script_fn = this._script_fns.get(property);
|
|
180
181
|
if (script_fn === undefined) {
|
|
181
182
|
if (!silent) {
|
|
182
183
|
console.log(`Script '${property}' could not be found.`);
|
|
@@ -184,15 +185,17 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
184
185
|
return;
|
|
185
186
|
}
|
|
186
187
|
const this_obj = {
|
|
187
|
-
get_records
|
|
188
|
+
get_records(property, index) {
|
|
189
|
+
return this.get_records(property, index);
|
|
190
|
+
},
|
|
188
191
|
};
|
|
189
|
-
for (const name
|
|
192
|
+
for (const name of this._script_fns.keys()) {
|
|
190
193
|
this_obj[name] = () => this.run_script(name);
|
|
191
194
|
}
|
|
192
195
|
return script_fn(this.model, this.model.data, this._state, this, (s) => this.run_script(s), this_obj);
|
|
193
196
|
}
|
|
194
|
-
get_records(
|
|
195
|
-
return dict_to_records(this.model.data
|
|
197
|
+
get_records(property_name, index = true) {
|
|
198
|
+
return dict_to_records(this.model.data.property(property_name), index);
|
|
196
199
|
}
|
|
197
200
|
disconnect_signals() {
|
|
198
201
|
super.disconnect_signals();
|
|
@@ -205,8 +208,8 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
205
208
|
}
|
|
206
209
|
get child_models() {
|
|
207
210
|
const models = [];
|
|
208
|
-
for (const
|
|
209
|
-
for (const model of
|
|
211
|
+
for (const [_parent, children] of entries(this.model.children)) {
|
|
212
|
+
for (const model of children) {
|
|
210
213
|
if (!isString(model)) {
|
|
211
214
|
models.push(model);
|
|
212
215
|
}
|
|
@@ -241,33 +244,40 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
241
244
|
}
|
|
242
245
|
this.model.trigger_event(new DOMEvent(elname, serialized));
|
|
243
246
|
}
|
|
244
|
-
_render_child(
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
el.innerHTML = htmlDecode(model) || model;
|
|
247
|
+
_render_child(child, el) {
|
|
248
|
+
if (isString(child)) {
|
|
249
|
+
el.innerHTML = html_decode(child) ?? child;
|
|
248
250
|
}
|
|
249
251
|
else {
|
|
250
|
-
|
|
251
|
-
view
|
|
252
|
-
|
|
252
|
+
const view = this._child_views.get(child);
|
|
253
|
+
if (view == null) {
|
|
254
|
+
el.innerHTML = "";
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
el.appendChild(view.el);
|
|
258
|
+
view.render();
|
|
259
|
+
view.after_render();
|
|
260
|
+
}
|
|
253
261
|
}
|
|
254
262
|
}
|
|
255
263
|
_render_node(node, children) {
|
|
256
|
-
const id = this.model.data
|
|
257
|
-
if (this.model.looped.
|
|
258
|
-
for (
|
|
259
|
-
const
|
|
264
|
+
const { id } = this.model.data;
|
|
265
|
+
if (this.model.looped.includes(node)) {
|
|
266
|
+
for (const [child, i] of enumerate(children)) {
|
|
267
|
+
const el_id = `${node}-${i}-${id}`;
|
|
268
|
+
const el = element_lookup(this.shadow_el, el_id);
|
|
260
269
|
if (el == null) {
|
|
261
|
-
console.warn(`DOM node '${
|
|
270
|
+
console.warn(`DOM node '${el_id}' could not be found. Cannot render children.`);
|
|
262
271
|
continue;
|
|
263
272
|
}
|
|
264
|
-
this._render_child(
|
|
273
|
+
this._render_child(child, el);
|
|
265
274
|
}
|
|
266
275
|
}
|
|
267
276
|
else {
|
|
268
|
-
const
|
|
277
|
+
const el_id = `${node}-${id}`;
|
|
278
|
+
const el = element_lookup(this.shadow_el, el_id);
|
|
269
279
|
if (el == null) {
|
|
270
|
-
console.warn(`DOM node '${
|
|
280
|
+
console.warn(`DOM node '${el_id}' could not be found. Cannot render children.`);
|
|
271
281
|
return;
|
|
272
282
|
}
|
|
273
283
|
for (const child of children) {
|
|
@@ -276,24 +286,33 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
276
286
|
}
|
|
277
287
|
}
|
|
278
288
|
_render_children() {
|
|
279
|
-
for (const node
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
289
|
+
for (const [node, children] of entries(this.model.children)) {
|
|
290
|
+
const computed_children = (() => {
|
|
291
|
+
if (isString(children)) {
|
|
292
|
+
const value = this.model.data.property(children).get_value();
|
|
293
|
+
if (isString(value)) {
|
|
294
|
+
return [value];
|
|
295
|
+
}
|
|
296
|
+
else if (isArray(value)) {
|
|
297
|
+
return value;
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
unreachable();
|
|
301
|
+
}
|
|
285
302
|
}
|
|
286
|
-
|
|
287
|
-
|
|
303
|
+
else {
|
|
304
|
+
return children;
|
|
305
|
+
}
|
|
306
|
+
})();
|
|
307
|
+
this._render_node(node, computed_children);
|
|
288
308
|
}
|
|
289
309
|
}
|
|
290
310
|
_render_html(literal, state = {}) {
|
|
291
311
|
let htm = literal.replace(/[`]/g, "\\$&");
|
|
292
|
-
let
|
|
312
|
+
let collected_callbacks = "";
|
|
293
313
|
const methods = [];
|
|
294
|
-
for (const
|
|
295
|
-
for (const
|
|
296
|
-
const [cb, method] = callback;
|
|
314
|
+
for (const [el_name, callbacks] of entries(this.model.callbacks)) {
|
|
315
|
+
for (const [cb, method] of callbacks) {
|
|
297
316
|
let definition;
|
|
298
317
|
htm = htm.replaceAll(`\${${method}}`, `$--{${method}}`);
|
|
299
318
|
if (method.startsWith("script(")) {
|
|
@@ -314,7 +333,7 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
314
333
|
else {
|
|
315
334
|
definition = `
|
|
316
335
|
const ${method} = (event) => {
|
|
317
|
-
let elname = "${
|
|
336
|
+
let elname = "${el_name}"
|
|
318
337
|
if (RegExp("\{\{.*loop\.index.*\}\}").test(elname)) {
|
|
319
338
|
const pattern = RegExp(elname.replace(/\{\{(.+?)\}\}/g, String.fromCharCode(92) + "d+"))
|
|
320
339
|
for (const p of event.path) {
|
|
@@ -332,27 +351,28 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
332
351
|
continue;
|
|
333
352
|
}
|
|
334
353
|
methods.push(method);
|
|
335
|
-
|
|
354
|
+
collected_callbacks += definition;
|
|
336
355
|
}
|
|
337
356
|
}
|
|
338
|
-
htm =
|
|
357
|
+
htm = htm
|
|
339
358
|
.replaceAll("${model.", "$-{model.")
|
|
340
359
|
.replaceAll("${", "${data.")
|
|
341
360
|
.replaceAll("$-{model.", "${model.")
|
|
342
|
-
.replaceAll("$--{", "${")
|
|
343
|
-
return new Function("view, model, data, state, html, useCallback", `${
|
|
361
|
+
.replaceAll("$--{", "${");
|
|
362
|
+
return new Function("view, model, data, state, html, useCallback", `${collected_callbacks}return html\`${htm}\`;`)(this, this.model, this.model.data, state, html, useCallback);
|
|
344
363
|
}
|
|
345
364
|
_render_script(literal, id) {
|
|
346
365
|
const scripts = [];
|
|
347
366
|
for (const elname of this.model.nodes) {
|
|
348
367
|
const elvar = elname.replace("-", "_");
|
|
349
|
-
if (literal.
|
|
368
|
+
if (!literal.includes(elvar)) {
|
|
350
369
|
continue;
|
|
351
370
|
}
|
|
352
371
|
const script = `
|
|
353
372
|
let ${elvar} = view.shadow_el.getElementById('${elname}-${id}')
|
|
354
|
-
if (${elvar} == null)
|
|
373
|
+
if (${elvar} == null) {
|
|
355
374
|
${elvar} = document.getElementById('${elname}-${id}')
|
|
375
|
+
}
|
|
356
376
|
if (${elvar} == null) {
|
|
357
377
|
console.warn("DOM node '${elname}' could not be found. Cannot execute callback.")
|
|
358
378
|
return
|
|
@@ -377,8 +397,8 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
377
397
|
this._mutation_observers = [];
|
|
378
398
|
}
|
|
379
399
|
_setup_mutation_observers() {
|
|
380
|
-
const id = this.model.data
|
|
381
|
-
for (const name
|
|
400
|
+
const { id } = this.model.data;
|
|
401
|
+
for (const name of keys(this.model.attrs)) {
|
|
382
402
|
const el = element_lookup(this.shadow_el, `${name}-${id}`);
|
|
383
403
|
if (el == null) {
|
|
384
404
|
console.warn(`DOM node '${name}-${id}' could not be found. Cannot set up MutationObserver.`);
|
|
@@ -392,45 +412,45 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
392
412
|
}
|
|
393
413
|
}
|
|
394
414
|
_remove_event_listeners() {
|
|
395
|
-
const id = this.model.data
|
|
396
|
-
for (const node
|
|
415
|
+
const { id } = this.model.data;
|
|
416
|
+
for (const [node, callbacks] of this._event_listeners) {
|
|
397
417
|
const el = element_lookup(this.shadow_el, `${node}-${id}`);
|
|
398
418
|
if (el == null) {
|
|
399
419
|
continue;
|
|
400
420
|
}
|
|
401
|
-
for (const event_name
|
|
402
|
-
const event_callback = this._event_listeners[node][event_name];
|
|
421
|
+
for (const [event_name, event_callback] of callbacks) {
|
|
403
422
|
el.removeEventListener(event_name, event_callback);
|
|
404
423
|
}
|
|
405
424
|
}
|
|
406
|
-
this._event_listeners
|
|
425
|
+
this._event_listeners.clear();
|
|
407
426
|
}
|
|
408
427
|
_setup_event_listeners() {
|
|
409
|
-
const id = this.model.data
|
|
410
|
-
|
|
428
|
+
const { id } = this.model.data;
|
|
429
|
+
const attrs = dict(this.model.attrs);
|
|
430
|
+
for (const [node, node_events] of entries(this.model.events)) {
|
|
411
431
|
const el = element_lookup(this.shadow_el, `${node}-${id}`);
|
|
412
432
|
if (el == null) {
|
|
413
433
|
console.warn(`DOM node '${node}-${id}' could not be found. Cannot subscribe to DOM events.`);
|
|
414
434
|
continue;
|
|
415
435
|
}
|
|
416
|
-
const node_events
|
|
417
|
-
for (const event_name in node_events) {
|
|
436
|
+
for (const [event_name, event_doit] of entries(node_events)) {
|
|
418
437
|
const event_callback = (event) => {
|
|
419
438
|
this._send_event(node, event_name, event);
|
|
420
|
-
if (node
|
|
439
|
+
if (attrs.has(node) && event_doit) {
|
|
421
440
|
this._update_model(el, node);
|
|
422
441
|
}
|
|
423
442
|
};
|
|
424
443
|
el.addEventListener(event_name, event_callback);
|
|
425
|
-
|
|
426
|
-
|
|
444
|
+
let callbacks = this._event_listeners.get(node);
|
|
445
|
+
if (callbacks === undefined) {
|
|
446
|
+
this._event_listeners.set(node, callbacks = new Map());
|
|
427
447
|
}
|
|
428
|
-
|
|
448
|
+
callbacks.set(event_name, event_callback);
|
|
429
449
|
}
|
|
430
450
|
}
|
|
431
451
|
}
|
|
432
452
|
_update(property = null) {
|
|
433
|
-
if (property == null ||
|
|
453
|
+
if (property == null || this.html.includes(`\${${property}}`)) {
|
|
434
454
|
const rendered = this._render_html(this.html);
|
|
435
455
|
if (rendered == null) {
|
|
436
456
|
return;
|
|
@@ -448,25 +468,26 @@ export class ReactiveHTMLView extends HTMLBoxView {
|
|
|
448
468
|
if (this._changing) {
|
|
449
469
|
return;
|
|
450
470
|
}
|
|
471
|
+
const attr_infos = dict(this.model.attrs).get(name) ?? [];
|
|
451
472
|
const attrs = {};
|
|
452
|
-
for (const attr_info of
|
|
473
|
+
for (const attr_info of attr_infos) {
|
|
453
474
|
const [attr, tokens, template] = attr_info;
|
|
454
|
-
let value = attr
|
|
475
|
+
let value = attr == "children" ? el.innerHTML : el[attr];
|
|
455
476
|
if (tokens.length === 1 && (`{${tokens[0]}}` === template)) {
|
|
456
477
|
attrs[tokens[0]] = value;
|
|
457
478
|
}
|
|
458
479
|
else if (isString(value)) {
|
|
459
|
-
value =
|
|
480
|
+
value = extract_token(template, value, tokens);
|
|
460
481
|
if (value == null) {
|
|
461
482
|
console.warn(`Could not resolve parameters in ${name} element ${attr} attribute value ${value}.`);
|
|
462
483
|
}
|
|
463
484
|
else {
|
|
464
|
-
for (const param
|
|
465
|
-
if (
|
|
485
|
+
for (const [param, param_val] of entries(value)) {
|
|
486
|
+
if (param_val === undefined) {
|
|
466
487
|
console.warn(`Could not resolve ${param} in ${name} element ${attr} attribute value ${value}.`);
|
|
467
488
|
}
|
|
468
489
|
else {
|
|
469
|
-
attrs[param] =
|
|
490
|
+
attrs[param] = param_val;
|
|
470
491
|
}
|
|
471
492
|
}
|
|
472
493
|
}
|
|
@@ -492,17 +513,17 @@ export class ReactiveHTML extends HTMLBox {
|
|
|
492
513
|
static __module__ = "panel.models.reactive_html";
|
|
493
514
|
static {
|
|
494
515
|
this.prototype.default_view = ReactiveHTMLView;
|
|
495
|
-
this.define(({ List,
|
|
496
|
-
attrs: [
|
|
497
|
-
callbacks: [
|
|
498
|
-
children: [
|
|
499
|
-
data: [
|
|
516
|
+
this.define(({ Bool, Str, List, Dict, Tuple, Or, Ref }) => ({
|
|
517
|
+
attrs: [Dict(List(Tuple(Str, List(Str), Str))), {}],
|
|
518
|
+
callbacks: [Dict(List(Tuple(Str, Str))), {}],
|
|
519
|
+
children: [Dict(Or(List(Or(Ref(UIElement), Str)), Str)), {}],
|
|
520
|
+
data: [Ref(Model)],
|
|
500
521
|
event_params: [List(Str), []],
|
|
501
|
-
events: [
|
|
522
|
+
events: [Dict(Dict(Bool)), {}],
|
|
502
523
|
html: [Str, ""],
|
|
503
524
|
looped: [List(Str), []],
|
|
504
525
|
nodes: [List(Str), []],
|
|
505
|
-
scripts: [
|
|
526
|
+
scripts: [Dict(List(Str)), {}],
|
|
506
527
|
}));
|
|
507
528
|
}
|
|
508
529
|
}
|