196 lines
6.2 KiB
JavaScript
196 lines
6.2 KiB
JavaScript
var bricks = window.bricks || {};
|
|
|
|
/*
|
|
* ResourceBrowser — a composite widget: tree (left) + browser (right).
|
|
*
|
|
* use case:
|
|
* {
|
|
* "widgettype": "ResourceBrowser",
|
|
* "options": {
|
|
* "title": "optional title",
|
|
* "description": "optional description",
|
|
* "tree_options": {
|
|
* "widgettype": "Tree",
|
|
* "options": { "idField": "id", "textField": "text", "dataurl": "..." },
|
|
* "tools": [ { "widgettype": "Button", "options": {...}, "binds": [...] } ] // optional
|
|
* },
|
|
* "browser_options": {
|
|
* "widgettype": "urlwidget",
|
|
* "options": { "url": "...", "method": "GET", "params": {...} },
|
|
* "tools": [ ... ] // optional
|
|
* },
|
|
* "tree_width": "280px" // optional, tree column width (default 280px)
|
|
* }
|
|
* }
|
|
*
|
|
* behaviour:
|
|
* - on create, calls browser render with id=null
|
|
* - tree node click only selects (never unselects); on selection change,
|
|
* calls browser render with the newly selected node's id
|
|
*
|
|
* layout:
|
|
* -------------------------
|
|
* | Title |
|
|
* | description |
|
|
* | tools | tools |
|
|
* | tree | browser |
|
|
* -------------------------
|
|
* both tree and browser are scrollable.
|
|
*/
|
|
bricks.ResourceBrowser = class extends bricks.VBox {
|
|
constructor(opts){
|
|
opts = opts || {};
|
|
opts.width = opts.width || '100%';
|
|
opts.height = opts.height || '100%';
|
|
super(opts);
|
|
this.tree_options = opts.tree_options || {};
|
|
this.browser_options = opts.browser_options || {};
|
|
this.current_id = undefined;
|
|
this.id_param_name = opts.id_param_name || 'id';
|
|
schedule_once(this.build_all.bind(this), 0.1);
|
|
}
|
|
|
|
async build_all(){
|
|
// ensure column flex so the body can fill the remaining height
|
|
this.dom_element.style.display = 'flex';
|
|
this.dom_element.style.flexDirection = 'column';
|
|
|
|
this.build_title();
|
|
this.build_description();
|
|
this.build_tools_row();
|
|
await this.build_body();
|
|
|
|
// initial render with id=null
|
|
await this.render_browser(null);
|
|
}
|
|
|
|
/*
|
|
* The base Layout.build_title()/build_description() read this.title /
|
|
* this.description (copied from opts by opts_set_style). Keep the optional
|
|
* title/description rendering through them.
|
|
*/
|
|
|
|
/*
|
|
* tools row: "tools | tools" — one toolbar above the tree column and one
|
|
* above the browser column. tools are widget descriptors.
|
|
*/
|
|
build_tools_row(){
|
|
var tree_tools = this.tree_options.tools || [];
|
|
var browser_tools = this.browser_options.tools || [];
|
|
if (tree_tools.length == 0 && browser_tools.length == 0){
|
|
return;
|
|
}
|
|
var row = new bricks.HBox({width:'100%', height:'auto'});
|
|
row.dom_element.style.flexShrink = '0';
|
|
this.add_widget(row);
|
|
|
|
var tree_toolbar = new bricks.HBox({width:this.get_tree_width(), height:'auto'});
|
|
tree_toolbar.dom_element.style.flexShrink = '0';
|
|
row.add_widget(tree_toolbar);
|
|
tree_tools.forEach(async (t) => {
|
|
var w = await bricks.widgetBuild(t, tree_toolbar);
|
|
if (w) tree_toolbar.add_widget(w);
|
|
});
|
|
|
|
var browser_toolbar = new bricks.HBox({width:'100%', height:'auto'});
|
|
browser_toolbar.dom_element.style.flex = '1';
|
|
row.add_widget(browser_toolbar);
|
|
browser_tools.forEach(async (t) => {
|
|
var w = await bricks.widgetBuild(t, browser_toolbar);
|
|
if (w) browser_toolbar.add_widget(w);
|
|
});
|
|
}
|
|
|
|
get_tree_width(){
|
|
return this.opts.tree_width || '280px';
|
|
}
|
|
|
|
async build_body(){
|
|
var body = new bricks.HBox({width:'100%', height:'100%'});
|
|
body.dom_element.style.flex = '1';
|
|
body.dom_element.style.overflow = 'hidden';
|
|
body.dom_element.style.minHeight = '0';
|
|
this.add_widget(body);
|
|
|
|
// ── tree column (fixed width, scrollable) ──
|
|
var tree_col = new bricks.VBox({width:this.get_tree_width(), height:'100%'});
|
|
tree_col.dom_element.style.flexShrink = '0';
|
|
tree_col.dom_element.style.overflow = 'hidden';
|
|
tree_col.dom_element.style.minHeight = '0';
|
|
body.add_widget(tree_col);
|
|
|
|
var tree_copy = bricks.extend({}, this.tree_options);
|
|
delete tree_copy.tools;
|
|
var tree_desc = this.clone_descriptor(tree_copy);
|
|
// select-only: clicking the same node must not unselect it
|
|
tree_desc.options = tree_desc.options || {};
|
|
tree_desc.options.select_only = true;
|
|
this.tree = await bricks.widgetBuild(tree_desc, tree_col);
|
|
if (this.tree){
|
|
tree_col.add_widget(this.tree);
|
|
this.tree.bind('node_selected', this.node_selected.bind(this));
|
|
}
|
|
|
|
// ── browser column (fills remaining width, scrollable) ──
|
|
var browser_col = new bricks.VBox({width:'100%', height:'100%'});
|
|
browser_col.dom_element.style.flex = '1';
|
|
browser_col.dom_element.style.overflow = 'hidden';
|
|
browser_col.dom_element.style.minHeight = '0';
|
|
body.add_widget(browser_col);
|
|
|
|
this.browser_panel = new bricks.VScrollPanel({width:'100%', height:'100%'});
|
|
this.browser_panel.dom_element.style.flex = '1';
|
|
this.browser_panel.dom_element.style.minHeight = '0';
|
|
browser_col.add_widget(this.browser_panel);
|
|
}
|
|
|
|
/* tree node selected → render browser with the new node id */
|
|
async node_selected(event){
|
|
var d = event.params || {};
|
|
var id_field = (this.tree && this.tree.idField) || 'id';
|
|
var id = d[id_field];
|
|
if (id === undefined){
|
|
id = d.id;
|
|
}
|
|
await this.render_browser(id);
|
|
}
|
|
|
|
/*
|
|
* render the browser for a given node id.
|
|
* deep-copies browser_options, injects the id param, re-builds content.
|
|
*/
|
|
async render_browser(id){
|
|
if (id === this.current_id){
|
|
return;
|
|
}
|
|
this.current_id = id;
|
|
if (!this.browser_panel){
|
|
return;
|
|
}
|
|
|
|
var browser_copy = bricks.extend({}, this.browser_options);
|
|
delete browser_copy.tools;
|
|
var desc = this.clone_descriptor(browser_copy);
|
|
desc.options = desc.options || {};
|
|
desc.options.params = bricks.extend({}, desc.options.params || {});
|
|
if (id === null || id === undefined){
|
|
delete desc.options.params[this.id_param_name];
|
|
} else {
|
|
desc.options.params[this.id_param_name] = id;
|
|
}
|
|
|
|
this.browser_panel.clear_widgets();
|
|
var w = await bricks.widgetBuild(desc, this.browser_panel);
|
|
if (w){
|
|
this.browser_panel.add_widget(w);
|
|
}
|
|
}
|
|
|
|
/* deep copy a widget descriptor so we never mutate the caller's object */
|
|
clone_descriptor(desc){
|
|
return JSON.parse(JSON.stringify(desc));
|
|
}
|
|
};
|
|
|
|
bricks.Factory.register('ResourceBrowser', bricks.ResourceBrowser);
|