mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 14:41:29 +01:00
Change tabs to use Shoelace
Includes changes to historylog, since it did some deferred loading & sizing magic based on tab
This commit is contained in:
parent
358a6a8ac8
commit
db143f047a
23
api/js/etemplate/Layout/Et2Tabs/Et2Tab.ts
Normal file
23
api/js/etemplate/Layout/Et2Tabs/Et2Tab.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {Et2Widget} from "../../Et2Widget/Et2Widget";
|
||||||
|
import {SlTab} from "@shoelace-style/shoelace";
|
||||||
|
|
||||||
|
export class Et2Tab extends Et2Widget(SlTab)
|
||||||
|
{
|
||||||
|
|
||||||
|
static get properties()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
...super.properties,
|
||||||
|
|
||||||
|
hidden: {type: Boolean, reflect: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.hidden = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("et2-tab", Et2Tab);
|
52
api/js/etemplate/Layout/Et2Tabs/Et2TabPanel.ts
Normal file
52
api/js/etemplate/Layout/Et2Tabs/Et2TabPanel.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import {Et2Widget} from "../../Et2Widget/Et2Widget";
|
||||||
|
import {SlTabPanel} from "@shoelace-style/shoelace";
|
||||||
|
import shoelace from "../../Styles/shoelace";
|
||||||
|
import {css} from "@lion/core";
|
||||||
|
|
||||||
|
export class Et2TabPanel extends Et2Widget(SlTabPanel)
|
||||||
|
{
|
||||||
|
static get styles()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
// @ts-ignore
|
||||||
|
...super.styles,
|
||||||
|
...shoelace,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
/*
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
min-height: fit-content;
|
||||||
|
min-width: fit-content;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
.tab-panel {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
::slotted(*) {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static get properties()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
...super.properties,
|
||||||
|
|
||||||
|
hidden: {type: Boolean, reflect: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.hidden = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("et2-tab-panel", Et2TabPanel);
|
388
api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts
Normal file
388
api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
/**
|
||||||
|
* EGroupware eTemplate2 - Box widget
|
||||||
|
*
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @package etemplate
|
||||||
|
* @subpackage api
|
||||||
|
* @link https://www.egroupware.org
|
||||||
|
* @author Nathan Gray
|
||||||
|
*/
|
||||||
|
import {SlTab, SlTabGroup, SlTabPanel} from "@shoelace-style/shoelace";
|
||||||
|
import {Et2Widget, loadWebComponent} from "../../Et2Widget/Et2Widget";
|
||||||
|
import {et2_directChildrenByTagName, et2_filteredNodeIterator, et2_readAttrWithDefault} from "../../et2_core_xml";
|
||||||
|
import {css, PropertyValues} from "@lion/core";
|
||||||
|
import shoelace from "../../Styles/shoelace";
|
||||||
|
|
||||||
|
|
||||||
|
export class Et2Tabs extends Et2Widget(SlTabGroup)
|
||||||
|
{
|
||||||
|
static get styles()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
...super.styles,
|
||||||
|
...shoelace,
|
||||||
|
css`
|
||||||
|
.tab-group--top {
|
||||||
|
height: 100%;
|
||||||
|
min-height: fit-content;
|
||||||
|
}
|
||||||
|
.tab-group__body {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: hidden auto;
|
||||||
|
}
|
||||||
|
.tab-group__body-fixed-height {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
::slotted([hidden]) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
::slotted(et2-tab-panel) {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
...super.properties,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of [extra] tabs.
|
||||||
|
* Each tab needs {label:..., template:...}.
|
||||||
|
* Additional optional keys are prepend, hidden and id, for access into content array
|
||||||
|
*/
|
||||||
|
extraTabs: {type: Object},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add tabs to template
|
||||||
|
* Set to true if tabs specified in tabs property should be added to tabs read from template,
|
||||||
|
* default false if not which replaces what's in template
|
||||||
|
*/
|
||||||
|
addTabs: {type: Boolean},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the height for tabs
|
||||||
|
* Leave unset to size automatically
|
||||||
|
*/
|
||||||
|
tabHeight: {type: String},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use "placement" instead
|
||||||
|
* @see https://shoelace.style/components/tab-group
|
||||||
|
*/
|
||||||
|
alignTabs: {type: String}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of currently selected tab
|
||||||
|
* @type {number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
protected _selectedIndex = -1;
|
||||||
|
protected tabData = [];
|
||||||
|
protected lazyLoaded = false;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.extraTabs = [];
|
||||||
|
this.addTabs = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadFromXML(_node)
|
||||||
|
{
|
||||||
|
// Get the tabs and tabpanels tags
|
||||||
|
const tabsElems = et2_directChildrenByTagName(_node, "tabs");
|
||||||
|
const tabpanelsElems = et2_directChildrenByTagName(_node, "tabpanels");
|
||||||
|
const tabData = [];
|
||||||
|
|
||||||
|
// Check for a parent height, we'll apply it to tab panels
|
||||||
|
var height = et2_readAttrWithDefault(_node.parentNode, "height", null);
|
||||||
|
if(height)
|
||||||
|
{
|
||||||
|
this.tabContainer.css("height", height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no tabs set or they should be added to tabs from xml
|
||||||
|
if(!this.extraTabs || this.extraTabs.length == 0 || this.addTabs)
|
||||||
|
{
|
||||||
|
if(tabsElems.length == 1 && tabpanelsElems.length == 1)
|
||||||
|
{
|
||||||
|
var tabs = tabsElems[0];
|
||||||
|
var tabpanels = tabpanelsElems[0];
|
||||||
|
|
||||||
|
// Parse the "tabs" tag
|
||||||
|
this._readTabs(tabData, tabs);
|
||||||
|
|
||||||
|
// Read and create the widgets defined in the "tabpanels"
|
||||||
|
this._readTabPanels(tabData, tabpanels);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.egw().debug("error", "Error while parsing tabbox, none or multiple tabs or tabpanels tags!", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add in additional tabs
|
||||||
|
if(this.extraTabs)
|
||||||
|
{
|
||||||
|
let readonly = this.getArrayMgr("readonlys").getEntry(this.id) || {};
|
||||||
|
for(let i = 0; i < this.extraTabs.length; i++)
|
||||||
|
{
|
||||||
|
let tab = this.extraTabs[i];
|
||||||
|
let tab_id = tab.id || tab.template;
|
||||||
|
let tab_options = {id: tab_id, template: tab.template, url: tab.url, content: undefined};
|
||||||
|
if(tab.id)
|
||||||
|
{
|
||||||
|
tab_options.content = tab.id;
|
||||||
|
}
|
||||||
|
tabData[tab.prepend ? 'unshift' : 'push'].call(tabData, {
|
||||||
|
"id": tab_id,
|
||||||
|
"label": this.egw().lang(tab.label),
|
||||||
|
"widget": null,
|
||||||
|
"widget_options": tab_options,
|
||||||
|
"contentDiv": null,
|
||||||
|
"flagDiv": null,
|
||||||
|
"hidden": typeof tab.hidden != "undefined" ? tab.hidden : readonly[tab_id] || false,
|
||||||
|
"XMLNode": null,
|
||||||
|
"promise": null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the tab DOM-Nodes
|
||||||
|
this.createTabs(tabData);
|
||||||
|
}
|
||||||
|
|
||||||
|
_readTabs(tabData, tabs)
|
||||||
|
{
|
||||||
|
let selected = "";
|
||||||
|
this._selectedIndex = -1;
|
||||||
|
let hidden = {};
|
||||||
|
if(this.id)
|
||||||
|
{
|
||||||
|
// Set the value for this element
|
||||||
|
let contentMgr = this.getArrayMgr("content");
|
||||||
|
if(contentMgr != null)
|
||||||
|
{
|
||||||
|
let val = contentMgr.getEntry(this.id);
|
||||||
|
if(val !== null)
|
||||||
|
{
|
||||||
|
selected = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contentMgr = this.getArrayMgr("readonlys");
|
||||||
|
if(contentMgr != null)
|
||||||
|
{
|
||||||
|
let val = contentMgr.getEntry(this.id);
|
||||||
|
if(val !== null && typeof val !== 'undefined')
|
||||||
|
{
|
||||||
|
hidden = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let i = 0;
|
||||||
|
et2_filteredNodeIterator(tabs, function(node, nodeName)
|
||||||
|
{
|
||||||
|
if(nodeName == "tab")
|
||||||
|
{
|
||||||
|
const index_name = et2_readAttrWithDefault(node, "id", '');
|
||||||
|
var hide = false;
|
||||||
|
var widget_options = {};
|
||||||
|
if(index_name)
|
||||||
|
{
|
||||||
|
if(selected == index_name)
|
||||||
|
{
|
||||||
|
this.selected_index = i;
|
||||||
|
}
|
||||||
|
if(hidden[index_name])
|
||||||
|
{
|
||||||
|
hide = true;
|
||||||
|
}
|
||||||
|
// Get the class attribute and add it as widget_options
|
||||||
|
const classAttr = et2_readAttrWithDefault(node, "class", '');
|
||||||
|
if(classAttr)
|
||||||
|
{
|
||||||
|
widget_options = {'class': classAttr};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabData.push({
|
||||||
|
"id": index_name,
|
||||||
|
"label": this.egw().lang(et2_readAttrWithDefault(node, "label", "Tab")),
|
||||||
|
"widget": null,
|
||||||
|
"widget_options": widget_options,
|
||||||
|
"contentDiv": null,
|
||||||
|
"flagDiv": null,
|
||||||
|
"hidden": hide,
|
||||||
|
"XMLNode": null,
|
||||||
|
"promise": null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw("Error while parsing: Invalid tag '" + nodeName +
|
||||||
|
"' in tabs tag");
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// Make sure we don't try to display a hidden tab
|
||||||
|
for(let i = 0; i < tabData.length && this._selectedIndex < 0; i++)
|
||||||
|
{
|
||||||
|
if(!tabData[i].hidden)
|
||||||
|
{
|
||||||
|
this._selectedIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_readTabPanels(tabData, tabpanels)
|
||||||
|
{
|
||||||
|
var i = 0;
|
||||||
|
et2_filteredNodeIterator(tabpanels, function(node, nodeName)
|
||||||
|
{
|
||||||
|
if(i < tabData.length)
|
||||||
|
{
|
||||||
|
// Store node for later evaluation
|
||||||
|
tabData[i].XMLNode = node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw("Error while reading tabpanels tag, too many widgets!");
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected update(changedProperties : PropertyValues)
|
||||||
|
{
|
||||||
|
super.update(changedProperties);
|
||||||
|
if(changedProperties.has("tabHeight"))
|
||||||
|
{
|
||||||
|
const body = this.shadowRoot.querySelector(".tab-group__body");
|
||||||
|
body.style.setProperty("height", this.tabHeight == parseInt(this.tabHeight) + "" ? this.tabHeight + "px" : this.tabHeight);
|
||||||
|
body.classList.toggle("tab-group__body-fixed-height", this.tabHeight !== '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the nodes for tabs
|
||||||
|
*
|
||||||
|
* @param tabData
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected createTabs(tabData)
|
||||||
|
{
|
||||||
|
this.tabData = tabData;
|
||||||
|
tabData.forEach((tab, index) =>
|
||||||
|
{
|
||||||
|
// Tab - SlTabGroup looks for sl-tab, so we can't use our own without overriding a lot
|
||||||
|
tab.flagDiv = loadWebComponent("et2-tab", {
|
||||||
|
slot: "nav",
|
||||||
|
panel: tab.id,
|
||||||
|
active: index == this._selectedIndex,
|
||||||
|
hidden: tab.hidden
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// Set tab label
|
||||||
|
tab.flagDiv.appendChild(document.createTextNode(tab.label));
|
||||||
|
});
|
||||||
|
tabData.forEach((tab, index) =>
|
||||||
|
{
|
||||||
|
this.createPanel(tab);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createPanel(tab, active = false)
|
||||||
|
{
|
||||||
|
// Tab panel
|
||||||
|
tab.contentDiv = loadWebComponent('et2-tab-panel', {
|
||||||
|
name: tab.id,
|
||||||
|
active: active,
|
||||||
|
hidden: tab.hidden
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// Tab content
|
||||||
|
let tabContent = tab.contentDiv.createElementFromNode(tab.XMLNode);
|
||||||
|
tab.contentDiv.appendChild(
|
||||||
|
typeof window.customElements.get(tab.XMLNode.nodeName) == "undefined" ?
|
||||||
|
tabContent.getDOMNode() : tabContent
|
||||||
|
);
|
||||||
|
|
||||||
|
return tab.contentDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllTabs(includeDisabled = false)
|
||||||
|
{
|
||||||
|
const slot = <HTMLSlotElement>this.shadowRoot.querySelector('slot[name="nav"]');
|
||||||
|
const tabNames = ["sl-tab", "et2-tab"];
|
||||||
|
return <SlTab[]>[...slot.assignedElements()].filter((el) =>
|
||||||
|
{
|
||||||
|
return includeDisabled ? tabNames.indexOf(el.tagName.toLowerCase()) != -1 : tabNames.indexOf(el.tagName.toLowerCase()) !== -1 && !el.disabled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllPanels()
|
||||||
|
{
|
||||||
|
const slot = this.body.querySelector('slot')!;
|
||||||
|
return [...slot.assignedElements()].filter(el => ['et2-tab-panel', 'sl-tab-panel'].indexOf(el.tagName.toLowerCase()) != -1) as [SlTabPanel];
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick(event : MouseEvent)
|
||||||
|
{
|
||||||
|
const target = event.target as HTMLElement;
|
||||||
|
const tab = target.closest('et2-tab');
|
||||||
|
const tabGroup = tab?.closest('sl-tab-group') || tab?.closest('et2-tabbox');
|
||||||
|
|
||||||
|
// Ensure the target tab is in this tab group
|
||||||
|
if(tabGroup !== this)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tab !== null)
|
||||||
|
{
|
||||||
|
this.setActiveTab(tab, {scrollBehavior: 'smooth'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up for printing
|
||||||
|
*
|
||||||
|
* @return {undefined|Deferred} Return a jQuery Deferred object if not done setting up
|
||||||
|
* (waiting for data)
|
||||||
|
*/
|
||||||
|
beforePrint()
|
||||||
|
{
|
||||||
|
// Remove the "active" flag from all tabs-flags
|
||||||
|
this.querySelector("[active]").removeAttribute("active");
|
||||||
|
|
||||||
|
// Remove height limit
|
||||||
|
this.style.height = '';
|
||||||
|
|
||||||
|
// Show all enabled tabs
|
||||||
|
for(let i = 0; i < this.tabData.length; i++)
|
||||||
|
{
|
||||||
|
let entry = this.tabData[i];
|
||||||
|
if(entry.hidden)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entry.flagDiv.insertBefore(entry.contentDiv);
|
||||||
|
entry.contentDiv.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset after printing
|
||||||
|
*/
|
||||||
|
afterPrint()
|
||||||
|
{
|
||||||
|
this.setActiveTab(this._selectedIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("et2-tabbox", Et2Tabs);
|
@ -18,11 +18,18 @@ import {ClassWithAttributes} from './et2_core_inheritance';
|
|||||||
import {et2_IDOMNode} from "./et2_core_interfaces";
|
import {et2_IDOMNode} from "./et2_core_interfaces";
|
||||||
import {et2_hasChild, et2_no_init} from "./et2_core_common";
|
import {et2_hasChild, et2_no_init} from "./et2_core_common";
|
||||||
import {et2_widget, WidgetConfig} from "./et2_core_widget";
|
import {et2_widget, WidgetConfig} from "./et2_core_widget";
|
||||||
import {egw_getActionManager, egwActionObject, egwActionObjectInterface, egw_getAppObjectManager,egw_getObjectManager} from '../egw_action/egw_action.js';
|
import {
|
||||||
import {EGW_AI_DRAG_OVER, EGW_AI_DRAG_OUT} from '../egw_action/egw_action_constants.js';
|
egw_getActionManager,
|
||||||
|
egw_getAppObjectManager,
|
||||||
|
egw_getObjectManager,
|
||||||
|
egwActionObject,
|
||||||
|
egwActionObjectInterface
|
||||||
|
} from '../egw_action/egw_action.js';
|
||||||
|
import {EGW_AI_DRAG_OUT, EGW_AI_DRAG_OVER} from '../egw_action/egw_action_constants.js';
|
||||||
import {egw} from "../jsapi/egw_global";
|
import {egw} from "../jsapi/egw_global";
|
||||||
// fixing circular dependencies by only importing type
|
import {Et2Tab} from "./Layout/Et2Tabs/Et2Tab";
|
||||||
import type {et2_tabbox} from "./et2_widget_tabs";
|
import {Et2TabPanel} from "./Layout/Et2Tabs/Et2TabPanel";
|
||||||
|
import {Et2Tabs} from "./Layout/Et2Tabs/Et2Tabs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract widget class which can be inserted into the DOM. All widget classes
|
* Abstract widget class which can be inserted into the DOM. All widget classes
|
||||||
@ -320,12 +327,14 @@ export abstract class et2_DOMWidget extends et2_widget implements et2_IDOMNode
|
|||||||
*
|
*
|
||||||
* @returns {Object|null} Data for tab the widget is on
|
* @returns {Object|null} Data for tab the widget is on
|
||||||
*/
|
*/
|
||||||
get_tab_info() : {id: string, label: string, widget: et2_widget, contentDiv: JQuery, flagDiv: JQuery} | null
|
get_tab_info() : { id : string, label : string, widget : et2_widget, contentDiv : Et2TabPanel, flagDiv : Et2Tab } | null
|
||||||
{
|
{
|
||||||
var parent : et2_widget = this;
|
var parent : et2_widget = this;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
parent = parent.getParent();
|
parent = parent.getParent();
|
||||||
} while (parent !== this.getRoot() && parent.getType() !== 'tabbox');
|
}
|
||||||
|
while(parent !== this.getRoot() && ['tabbox', 'ET2-TABBOX'].indexOf(parent.getType()) == -1);
|
||||||
|
|
||||||
// No tab
|
// No tab
|
||||||
if(parent === this.getRoot())
|
if(parent === this.getRoot())
|
||||||
@ -333,14 +342,14 @@ export abstract class et2_DOMWidget extends et2_widget implements et2_IDOMNode
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tabbox : et2_tabbox = <et2_tabbox><unknown>parent;
|
let tabbox : Et2Tabs = <Et2Tabs><unknown>parent;
|
||||||
|
|
||||||
// Find the tab index
|
// Find the tab index
|
||||||
for(var i = 0; i < tabbox.tabData.length; i++)
|
for(var i = 0; i < tabbox.tabData.length; i++)
|
||||||
{
|
{
|
||||||
// Find the tab by DOM heritage
|
// Find the tab by DOM heritage
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if(tabbox.tabData[i].contentDiv.has(this.div).length)
|
if(tabbox.tabData[i].contentDiv.contains(this.div[0] || this))
|
||||||
{
|
{
|
||||||
return tabbox.tabData[i];
|
return tabbox.tabData[i];
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import {et2_dataview_column} from "./et2_dataview_model_columns";
|
|||||||
import {et2_dataview_controller} from "./et2_dataview_controller";
|
import {et2_dataview_controller} from "./et2_dataview_controller";
|
||||||
import {et2_diff} from "./et2_widget_diff";
|
import {et2_diff} from "./et2_widget_diff";
|
||||||
import {et2_IDetachedDOM, et2_IResizeable} from "./et2_core_interfaces";
|
import {et2_IDetachedDOM, et2_IResizeable} from "./et2_core_interfaces";
|
||||||
import {et2_dynheight} from "./et2_widget_dynheight";
|
|
||||||
import {et2_customfields_list} from "./et2_extension_customfields";
|
import {et2_customfields_list} from "./et2_extension_customfields";
|
||||||
import {et2_selectbox} from "./et2_widget_selectbox";
|
import {et2_selectbox} from "./et2_widget_selectbox";
|
||||||
import {loadWebComponent} from "./Et2Widget/Et2Widget";
|
import {loadWebComponent} from "./Et2Widget/Et2Widget";
|
||||||
@ -96,7 +95,6 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
|||||||
private div: JQuery;
|
private div: JQuery;
|
||||||
private innerDiv: JQuery;
|
private innerDiv: JQuery;
|
||||||
private _filters: { appname: string; record_id: string; get_rows: string; };
|
private _filters: { appname: string; record_id: string; get_rows: string; };
|
||||||
private dynheight: et2_dynheight;
|
|
||||||
private dataview: et2_dataview;
|
private dataview: et2_dataview;
|
||||||
private controller: et2_dataview_controller;
|
private controller: et2_dataview_controller;
|
||||||
private fields: any;
|
private fields: any;
|
||||||
@ -114,6 +112,8 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
|||||||
|
|
||||||
this.innerDiv = jQuery(document.createElement("div"))
|
this.innerDiv = jQuery(document.createElement("div"))
|
||||||
.appendTo(this.div);
|
.appendTo(this.div);
|
||||||
|
|
||||||
|
this._resize = this._resize.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_status_id( _new_id)
|
set_status_id( _new_id)
|
||||||
@ -130,36 +130,16 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
|||||||
if(tab)
|
if(tab)
|
||||||
{
|
{
|
||||||
// Bind the action to when the tab is selected
|
// Bind the action to when the tab is selected
|
||||||
const handler = function(e)
|
const handler = (e) =>
|
||||||
{
|
{
|
||||||
e.data.div.unbind("click.history");
|
if(typeof this.dataview == "undefined")
|
||||||
// Bind on click tap, because we need to update history size
|
{
|
||||||
// after a rezise happend and history log was not the active tab
|
this.finishInit();
|
||||||
e.data.div.bind("click.history", {"history": e.data.history, div: tab.flagDiv}, function (e) {
|
|
||||||
if (e.data.history && e.data.history.dynheight) {
|
|
||||||
e.data.history.dynheight.update(function (_w, _h) {
|
|
||||||
e.data.history.dataview.resize(_w, _h);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof e.data.history.dataview == "undefined") {
|
|
||||||
e.data.history.finishInit();
|
|
||||||
if (e.data.history.dynheight) {
|
|
||||||
e.data.history.dynheight.update(function (_w, _h) {
|
|
||||||
e.data.history.dataview.resize(_w, _h);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// TODO: Find a better way to get this to wait
|
||||||
|
window.setTimeout(this._resize, 10);
|
||||||
};
|
};
|
||||||
tab.flagDiv.bind("click.history",{"history": this, div: tab.flagDiv}, handler);
|
tab.flagDiv.addEventListener("click", handler);
|
||||||
|
|
||||||
// Display if history tab is selected
|
|
||||||
if(tab.contentDiv.is(':visible') && typeof this.dataview == 'undefined')
|
|
||||||
{
|
|
||||||
tab.flagDiv.trigger("click.history");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -194,13 +174,7 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
|||||||
this.egw().debug("warn", "status_id attribute should not be the same as historylog ID");
|
this.egw().debug("warn", "status_id attribute should not be the same as historylog ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the dynheight component which dynamically scales the inner
|
|
||||||
// container.
|
|
||||||
this.div.parentsUntil('.et2_tabs').height('100%');
|
|
||||||
const parent = this.get_tab_info();
|
const parent = this.get_tab_info();
|
||||||
this.dynheight = new et2_dynheight(parent ? parent.contentDiv : this.div.parent(),
|
|
||||||
this.innerDiv, 250
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create the outer grid container
|
// Create the outer grid container
|
||||||
this.dataview = new et2_dataview(this.innerDiv, this.egw());
|
this.dataview = new et2_dataview(this.innerDiv, this.egw());
|
||||||
@ -267,9 +241,7 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
|||||||
// Register a resize callback
|
// Register a resize callback
|
||||||
jQuery(window).on('resize.' +this.options.value.app + this.options.value.id, function()
|
jQuery(window).on('resize.' +this.options.value.app + this.options.value.id, function()
|
||||||
{
|
{
|
||||||
if (this && typeof this.dynheight != 'undefined') this.dynheight.update(function(_w, _h) {
|
this.dataview.resize();
|
||||||
this.dataview.resize(_w, _h);
|
|
||||||
}.bind(this));
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +269,6 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
|||||||
// Free the grid components
|
// Free the grid components
|
||||||
if(this.dataview) this.dataview.destroy();
|
if(this.dataview) this.dataview.destroy();
|
||||||
if(this.controller) this.controller.destroy();
|
if(this.controller) this.controller.destroy();
|
||||||
if(this.dynheight) this.dynheight.destroy();
|
|
||||||
|
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
@ -750,37 +721,33 @@ export class et2_historylog extends et2_valueWidget implements et2_IDataProvider
|
|||||||
row.parents("td").attr("colspan", 2)
|
row.parents("td").attr("colspan", 2)
|
||||||
.css("border-right", "none");
|
.css("border-right", "none");
|
||||||
row.css("width", (
|
row.css("width", (
|
||||||
this.dataview.getColumnMgr().getColumnWidth(et2_historylog.NEW_VALUE) +
|
this.dataview.getColumnMgr().getColumnWidth(et2_historylog.NEW_VALUE) +
|
||||||
this.dataview.getColumnMgr().getColumnWidth(et2_historylog.OLD_VALUE)-10)+'px');
|
this.dataview.getColumnMgr().getColumnWidth(et2_historylog.OLD_VALUE) - 10) + 'px');
|
||||||
|
|
||||||
// Skip column 5
|
// Skip column 5
|
||||||
row.parents("td").next().remove();
|
row.parents("td").next().remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_resize()
|
||||||
|
{
|
||||||
|
let tab = this.get_tab_info();
|
||||||
|
if(this.dataview)
|
||||||
|
{
|
||||||
|
// -# to avoid scrollbars
|
||||||
|
this.dataview.resize(
|
||||||
|
Math.min(
|
||||||
|
window.innerWidth - 15,
|
||||||
|
parseInt(getComputedStyle(tab.contentDiv).width)
|
||||||
|
) - 5,
|
||||||
|
parseInt(getComputedStyle(tab.contentDiv).height) - 5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resize(_height)
|
resize(_height)
|
||||||
{
|
{
|
||||||
if (typeof this.options != 'undefined' && _height
|
|
||||||
&& typeof this.options.resize_ratio != 'undefined')
|
this._resize();
|
||||||
{
|
|
||||||
// apply the ratio
|
|
||||||
_height = (this.options.resize_ratio != '')? _height * this.options.resize_ratio: _height;
|
|
||||||
if (_height != 0)
|
|
||||||
{
|
|
||||||
// 250px is the default value for history widget
|
|
||||||
// if it's not loaded yet and window is resized
|
|
||||||
// then add the default height with excess_height
|
|
||||||
if (this.div.height() == 0) _height += 250;
|
|
||||||
this.div.height(this.div.height() + _height);
|
|
||||||
|
|
||||||
// trigger the history registered resize
|
|
||||||
// in order to update the height with new value
|
|
||||||
this.div.trigger('resize.' +this.options.value.app + this.options.value.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(this.dynheight)
|
|
||||||
{
|
|
||||||
this.dynheight.update();
|
|
||||||
}
|
|
||||||
// Resize diff widgets to match new space
|
// Resize diff widgets to match new space
|
||||||
if(this.dataview)
|
if(this.dataview)
|
||||||
{
|
{
|
||||||
|
@ -25,6 +25,9 @@ import '../jsapi/egw_json.js';
|
|||||||
import {egwIsMobile} from "../egw_action/egw_action_common.js";
|
import {egwIsMobile} from "../egw_action/egw_action_common.js";
|
||||||
import './Layout/Et2Box/Et2Box';
|
import './Layout/Et2Box/Et2Box';
|
||||||
import './Layout/Et2Details/Et2Details';
|
import './Layout/Et2Details/Et2Details';
|
||||||
|
import './Layout/Et2Tabs/Et2Tab';
|
||||||
|
import './Layout/Et2Tabs/Et2Tabs';
|
||||||
|
import './Layout/Et2Tabs/Et2TabPanel';
|
||||||
import './Et2Avatar/Et2Avatar';
|
import './Et2Avatar/Et2Avatar';
|
||||||
import './Et2Button/Et2Button';
|
import './Et2Button/Et2Button';
|
||||||
import './Et2Checkbox/Et2Checkbox';
|
import './Et2Checkbox/Et2Checkbox';
|
||||||
@ -666,6 +669,8 @@ export class etemplate2
|
|||||||
if(egw.debug_level() >= 4 && console.timeStamp)
|
if(egw.debug_level() >= 4 && console.timeStamp)
|
||||||
{
|
{
|
||||||
console.timeStamp("Begin rendering template");
|
console.timeStamp("Begin rendering template");
|
||||||
|
console.time("Template load");
|
||||||
|
console.time("loadFromXML");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add into indexed list - do this before, so anything looking can find it,
|
// Add into indexed list - do this before, so anything looking can find it,
|
||||||
@ -678,6 +683,8 @@ export class etemplate2
|
|||||||
|
|
||||||
// Read the XML structure of the requested template
|
// Read the XML structure of the requested template
|
||||||
this._widgetContainer.loadFromXML(etemplate2.templates[this.name]);
|
this._widgetContainer.loadFromXML(etemplate2.templates[this.name]);
|
||||||
|
console.timeEnd("loadFromXML");
|
||||||
|
console.time("deferred");
|
||||||
|
|
||||||
// List of Promises from widgets that are not quite fully loaded
|
// List of Promises from widgets that are not quite fully loaded
|
||||||
const deferred = [];
|
const deferred = [];
|
||||||
@ -693,6 +700,10 @@ export class etemplate2
|
|||||||
|
|
||||||
if(egw.debug_level() >= 3 && console.groupEnd)
|
if(egw.debug_level() >= 3 && console.groupEnd)
|
||||||
{
|
{
|
||||||
|
if(console.timeStamp)
|
||||||
|
{
|
||||||
|
console.timeStamp("loading finished, waiting for deferred");
|
||||||
|
}
|
||||||
egw.window.console.groupEnd();
|
egw.window.console.groupEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -702,6 +713,9 @@ export class etemplate2
|
|||||||
{
|
{
|
||||||
Promise.all(deferred).then(() =>
|
Promise.all(deferred).then(() =>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
console.timeEnd("deferred");
|
||||||
|
console.timeStamp("Deferred done");
|
||||||
// Clear dirty now that it's all loaded
|
// Clear dirty now that it's all loaded
|
||||||
this.widgetContainer.iterateOver((_widget) =>
|
this.widgetContainer.iterateOver((_widget) =>
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user