forked from extern/egroupware
Home: WIP home now shows stuff again
This commit is contained in:
parent
46ac680c98
commit
db5be59ed0
452
api/js/etemplate/Et2Portlet/Et2Portlet.ts
Normal file
452
api/js/etemplate/Et2Portlet/Et2Portlet.ts
Normal file
@ -0,0 +1,452 @@
|
|||||||
|
/**
|
||||||
|
* EGroupware eTemplate2 - Portlet base
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* @copyright 2022 Nathan Gray
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import {Et2Widget} from "../Et2Widget/Et2Widget";
|
||||||
|
import {SlCard} from "@shoelace-style/shoelace";
|
||||||
|
import interact from "@interactjs/interactjs";
|
||||||
|
import {egw} from "../../jsapi/egw_global";
|
||||||
|
import {classMap, css, html} from "@lion/core";
|
||||||
|
import {HasSlotController} from "@shoelace-style/shoelace/dist/internal/slot";
|
||||||
|
import shoelace from "../Styles/shoelace";
|
||||||
|
import {Et2Dialog} from "../Et2Dialog/Et2Dialog";
|
||||||
|
import {et2_IResizeable} from "../et2_core_interfaces";
|
||||||
|
import {HomeApp} from "../../../../home/js/app";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Participate in Home
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class Et2Portlet extends (Et2Widget(SlCard))
|
||||||
|
{
|
||||||
|
static get properties()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
...super.properties,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Give a title
|
||||||
|
* Goes in the header at the top with the icons
|
||||||
|
*/
|
||||||
|
title: {type: String},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom etemplate used to customize / set up the portlet
|
||||||
|
*/
|
||||||
|
editTemplate: {type: String},
|
||||||
|
/**
|
||||||
|
* Set the portlet color
|
||||||
|
*/
|
||||||
|
color: {type: String},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of customization settings, similar in structure to preference settings
|
||||||
|
*/
|
||||||
|
settings: {type: Object},
|
||||||
|
actions: {type: Object},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
...shoelace,
|
||||||
|
...(super.styles || []),
|
||||||
|
css`
|
||||||
|
.portlet__header {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
display: flex;
|
||||||
|
font-style: inherit;
|
||||||
|
font-variant: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
font-stretch: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: var(--sl-font-size-medium);
|
||||||
|
line-height: var(--sl-line-height-dense);
|
||||||
|
padding: var(--header-spacing);
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portlet__title {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
font-size: var(--sl-font-size-medium);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portlet__header et2-button-icon {
|
||||||
|
display: none;
|
||||||
|
order: 99;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portlet__header:hover et2-button-icon {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.card__body {
|
||||||
|
/* display block to prevent overflow from our size */
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::slotted(div) {
|
||||||
|
}
|
||||||
|
`
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly hasSlotController = new HasSlotController(this, 'footer', 'header', 'image');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are the "normal" actions that every portlet is expected to have.
|
||||||
|
* The widget provides default actions for all of these, but they can
|
||||||
|
* be added to or overridden if needed by setting the action attribute.
|
||||||
|
*/
|
||||||
|
protected static default_actions : any = {
|
||||||
|
edit_settings: {
|
||||||
|
icon: "edit",
|
||||||
|
caption: "Configure",
|
||||||
|
"default": true,
|
||||||
|
hideOnDisabled: true,
|
||||||
|
group: "portlet"
|
||||||
|
},
|
||||||
|
remove_portlet: {
|
||||||
|
icon: "delete",
|
||||||
|
caption: "Remove",
|
||||||
|
group: "portlet"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.editTemplate = egw.webserverUrl + "/home/templates/default/edit.xet"
|
||||||
|
this.actions = {};
|
||||||
|
|
||||||
|
this._onMoveResize = this._onMoveResize.bind(this);
|
||||||
|
this._onMoveResizeEnd = this._onMoveResizeEnd.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback()
|
||||||
|
{
|
||||||
|
super.connectedCallback();
|
||||||
|
|
||||||
|
Promise.all([/* any others here...*/ this.updateComplete])
|
||||||
|
.then(() => this._setupMoveResize());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overriden from parent to add in default actions
|
||||||
|
*/
|
||||||
|
set_actions(actions)
|
||||||
|
{
|
||||||
|
// Set targets for actions
|
||||||
|
let defaults : any = {};
|
||||||
|
for(let action_name in Et2Portlet.default_actions)
|
||||||
|
{
|
||||||
|
defaults[action_name] = Et2Portlet.default_actions[action_name];
|
||||||
|
// Translate caption here, as translations aren't available earlier
|
||||||
|
defaults[action_name].caption = this.egw().lang(Et2Portlet.default_actions[action_name].caption);
|
||||||
|
if(typeof this[action_name] == "function")
|
||||||
|
{
|
||||||
|
defaults[action_name].onExecute = this[action_name].bind(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add in defaults, but let provided actions override them
|
||||||
|
this.actions = jQuery.extend(true, {}, defaults, actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up moving & resizing
|
||||||
|
*/
|
||||||
|
_setupMoveResize()
|
||||||
|
{
|
||||||
|
// Quick calculation of min size - dialog is made up of header, content & buttons
|
||||||
|
let minHeight = 0;
|
||||||
|
for(let e of this.children)
|
||||||
|
{
|
||||||
|
minHeight += e.getBoundingClientRect().height + parseFloat(getComputedStyle(e).marginTop) + parseFloat(getComputedStyle(e).marginBottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get parent's dimensions
|
||||||
|
let style = getComputedStyle(this.parentElement);
|
||||||
|
let parentDimensions = {
|
||||||
|
width: parseInt(style.gridAutoColumns) + parseInt(style.gap) || HomeApp.GRID,
|
||||||
|
height: parseInt(style.gridAutoRows) + parseInt(style.gap) || HomeApp.GRID
|
||||||
|
};
|
||||||
|
|
||||||
|
let gridTarget = interact.snappers.grid({
|
||||||
|
x: parentDimensions.width,
|
||||||
|
y: parentDimensions.height
|
||||||
|
});
|
||||||
|
|
||||||
|
interact(this)
|
||||||
|
.resizable({
|
||||||
|
edges: {bottom: true, right: true},
|
||||||
|
listeners: {
|
||||||
|
move: this._onMoveResize,
|
||||||
|
end: this._onMoveResizeEnd
|
||||||
|
},
|
||||||
|
modifiers: [
|
||||||
|
// Snap to grid
|
||||||
|
interact.modifiers.snap({
|
||||||
|
targets: [gridTarget],
|
||||||
|
offset: "startCoords",
|
||||||
|
limits: {top: 0, left: 0}
|
||||||
|
}),
|
||||||
|
|
||||||
|
// keep the edges inside the parent
|
||||||
|
interact.modifiers.restrictEdges({
|
||||||
|
outer: 'parent'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.draggable({
|
||||||
|
allowFrom: ".portlet__header",
|
||||||
|
autoScroll: true,
|
||||||
|
listeners: {
|
||||||
|
move: this._onMoveResize,
|
||||||
|
end: this._onMoveResizeEnd
|
||||||
|
},
|
||||||
|
modifiers: [
|
||||||
|
// Restrict interferes with grid making it act strangely
|
||||||
|
//interact.modifiers.restrict({
|
||||||
|
// restriction: 'parent'
|
||||||
|
//}),
|
||||||
|
// Snap to grid
|
||||||
|
interact.modifiers.snap({
|
||||||
|
targets: [gridTarget],
|
||||||
|
offset: "startCoords",
|
||||||
|
limits: {top: 0, left: 0}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle moving and resizing
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
_onMoveResize(event : InteractEvent)
|
||||||
|
{
|
||||||
|
let target = event.target
|
||||||
|
let x = (parseFloat(target.getAttribute('data-x')) || 0) + (event.deltaRect ? 0 : event.dx);
|
||||||
|
let y = (parseFloat(target.getAttribute('data-y')) || 0) + (event.deltaRect ? 0 : event.dy);
|
||||||
|
|
||||||
|
// update the element's style
|
||||||
|
// Size
|
||||||
|
target.style.width = event.rect.width + 'px'
|
||||||
|
target.style.height = event.rect.height + 'px'
|
||||||
|
|
||||||
|
// Position
|
||||||
|
target.style.transform = 'translate(' + x + 'px,' + y + 'px)';
|
||||||
|
|
||||||
|
target.setAttribute('data-x', x);
|
||||||
|
target.setAttribute('data-y', y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move or resize has completed. Now into parent grid and update settings.
|
||||||
|
*
|
||||||
|
* @param {InteractEvent} event
|
||||||
|
*/
|
||||||
|
_onMoveResizeEnd(event : InteractEvent)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Get parent's dimensions
|
||||||
|
let style = getComputedStyle(this.parentElement);
|
||||||
|
let parentDimensions = {
|
||||||
|
x: parseInt(style.gridAutoColumns) || 1,
|
||||||
|
y: parseInt(style.gridAutoRows) || 1
|
||||||
|
}
|
||||||
|
let target = event.target
|
||||||
|
let dx = Math.round((parseInt(target.getAttribute('data-x')) || 0) / parentDimensions.x);
|
||||||
|
let dy = Math.round((parseInt(target.getAttribute('data-y')) || 0) / parentDimensions.y);
|
||||||
|
let dwidth = Math.round((event.deltaRect?.width || 1) / parentDimensions.x);
|
||||||
|
let dheight = Math.round((event.deltaRect?.height || 1) / parentDimensions.y);
|
||||||
|
let [o_x, o_width] = this.style.gridColumn.split(" / span");
|
||||||
|
let [o_y, o_height] = this.style.gridRow.split(" / span");
|
||||||
|
|
||||||
|
// Clear temp stuff from moving
|
||||||
|
target.style.transform = "";
|
||||||
|
target.style.width = "";
|
||||||
|
target.style.height = "";
|
||||||
|
target.removeAttribute('data-x');
|
||||||
|
target.removeAttribute('data-y');
|
||||||
|
|
||||||
|
let col = Math.max(1, (dx + (parseInt(o_x) || 0)));
|
||||||
|
let row = Math.max(1, (dy + (parseInt(o_y) || 0)));
|
||||||
|
let width = (dwidth + parseInt(o_width)) || 1;
|
||||||
|
let height = (dheight + parseInt(o_height)) || 1;
|
||||||
|
|
||||||
|
// Set grid position
|
||||||
|
target.style.gridArea = row + " / " +
|
||||||
|
col + "/ span " +
|
||||||
|
height + " / span " +
|
||||||
|
width;
|
||||||
|
|
||||||
|
// Update position settings
|
||||||
|
this.update_settings({row: row, col: col, width: width, height: height});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
imageTemplate()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
headerTemplate()
|
||||||
|
{
|
||||||
|
return html`
|
||||||
|
<header class="portlet__header">
|
||||||
|
<h2 class="portlet__title">${this.title}</h2>
|
||||||
|
<et2-button-icon name="gear" label="Settings" noSubmit=true
|
||||||
|
@click="${() => this.edit_settings()}"></et2-button-icon>
|
||||||
|
</header>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
footerTemplate()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create & show a dialog for customizing this portlet
|
||||||
|
*
|
||||||
|
* Properties for customization are sent in the 'settings' attribute
|
||||||
|
*/
|
||||||
|
edit_settings()
|
||||||
|
{
|
||||||
|
let dialog = new Et2Dialog(this.egw());
|
||||||
|
dialog.transformAttributes({
|
||||||
|
callback: this._process_edit.bind(this),
|
||||||
|
template: this.editTemplate,
|
||||||
|
value: {
|
||||||
|
content: this.settings
|
||||||
|
},
|
||||||
|
buttons: Et2Dialog.BUTTONS_OK_CANCEL
|
||||||
|
});
|
||||||
|
// Set separately to avoid translation
|
||||||
|
dialog.title = this.egw().lang("Edit") + " " + (this.title || '');
|
||||||
|
this.appendChild(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
_process_edit(button_id, value)
|
||||||
|
{
|
||||||
|
if(button_id != Et2Dialog.OK_BUTTON)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass updated settings, unless we're removing
|
||||||
|
this.update_settings((typeof value == 'string') ? {} : this.settings || {});
|
||||||
|
|
||||||
|
// Extend, not replace, because settings has types while value has just value
|
||||||
|
if(typeof value == 'object')
|
||||||
|
{
|
||||||
|
this.settings = {...this.settings, value};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected update_settings(settings)
|
||||||
|
{
|
||||||
|
// Save settings - server might reply with new content if the portlet needs an update,
|
||||||
|
// but ideally it doesn't
|
||||||
|
this.classList.add("loading");
|
||||||
|
|
||||||
|
this.egw().jsonq("home.home_ui.ajax_set_properties", [this.id, [], settings, this.settings ? this.settings.group : false],
|
||||||
|
function(data)
|
||||||
|
{
|
||||||
|
// This section not for us
|
||||||
|
if(!data || typeof data.attributes == 'undefined')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.classList.remove("loading");
|
||||||
|
|
||||||
|
this.transformAttributes(data.attributes);
|
||||||
|
|
||||||
|
// Flagged as needing to edit settings? Open dialog
|
||||||
|
if(typeof data.edit_settings != 'undefined' && data.edit_settings)
|
||||||
|
{
|
||||||
|
this.edit_settings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only resize once, and only if needed
|
||||||
|
if(data.attributes.width || data.attributes.height)
|
||||||
|
{
|
||||||
|
this.style.columnSpan = data.attributes.width;
|
||||||
|
this.style.rowSpan = data.attributes.height;
|
||||||
|
|
||||||
|
// Tell children
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.iterateOver(function(widget)
|
||||||
|
{
|
||||||
|
if(typeof widget.resize === 'function')
|
||||||
|
{
|
||||||
|
widget.resize();
|
||||||
|
}
|
||||||
|
}, null, et2_IResizeable);
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
// Something went wrong, but do not stop
|
||||||
|
this.egw().debug('warn', e, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render()
|
||||||
|
{
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
${this.color ? ".card {--border-color: " + this.color + "}" : ""}
|
||||||
|
</style>
|
||||||
|
<div
|
||||||
|
part="base"
|
||||||
|
class=${classMap({
|
||||||
|
card: true,
|
||||||
|
'card--has-footer': this.hasSlotController.test('footer'),
|
||||||
|
'card--has-image': this.hasSlotController.test('image'),
|
||||||
|
'card--has-header': true,
|
||||||
|
'et2-portlet': true
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<slot name="image" part="image" class="card__image">${this.imageTemplate()}</slot>
|
||||||
|
<slot name="header" part="header" class="card__header">${this.headerTemplate()}</slot>
|
||||||
|
<slot part="body" class="card__body"></slot>
|
||||||
|
<slot name="footer" part="footer" class="card__footer">${this.footerTemplate()}</slot>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!customElements.get("et2-portlet"))
|
||||||
|
{
|
||||||
|
customElements.define("et2-portlet", Et2Portlet);
|
||||||
|
}
|
@ -17,7 +17,7 @@
|
|||||||
* views, we need some custom handling to detect and handle refreshes.
|
* views, we need some custom handling to detect and handle refreshes.
|
||||||
*
|
*
|
||||||
* Note we put the class in home.
|
* Note we put the class in home.
|
||||||
*/
|
*
|
||||||
app.classes.home.calendar_favorite_portlet = app.classes.home.home_favorite_portlet.extend({
|
app.classes.home.calendar_favorite_portlet = app.classes.home.home_favorite_portlet.extend({
|
||||||
|
|
||||||
observer: function(_msg, _app, _id, _type, _msg_type, _targetapp)
|
observer: function(_msg, _app, _id, _type, _msg_type, _targetapp)
|
||||||
@ -70,4 +70,4 @@ observer: function(_msg, _app, _id, _type, _msg_type, _targetapp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});*/
|
@ -30,6 +30,7 @@ import {EGW_AI_DRAG_ENTER, EGW_AI_DRAG_OUT} from "../../api/js/egw_action/egw_ac
|
|||||||
import {formatDate, formatTime, parseTime} from "../../api/js/etemplate/Et2Date/Et2Date";
|
import {formatDate, formatTime, parseTime} from "../../api/js/etemplate/Et2Date/Et2Date";
|
||||||
import interact from "@interactjs/interactjs/index";
|
import interact from "@interactjs/interactjs/index";
|
||||||
import type {InteractEvent} from "@interactjs/core/InteractEvent";
|
import type {InteractEvent} from "@interactjs/core/InteractEvent";
|
||||||
|
import {CalendarApp} from "./app";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class which implements the "calendar-timegrid" XET-Tag for displaying a span of days
|
* Class which implements the "calendar-timegrid" XET-Tag for displaying a span of days
|
||||||
|
@ -290,7 +290,7 @@ class home_ui
|
|||||||
$appname = $app;
|
$appname = $app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Framework::includeJS('', $classname, $appname ? $appname : 'home');
|
//Framework::includeJS('', $classname, $appname ? $appname : 'home');
|
||||||
|
|
||||||
if($full_exec)
|
if($full_exec)
|
||||||
{
|
{
|
||||||
|
10
home/js/Et2PortletFavorite.ts
Normal file
10
home/js/Et2PortletFavorite.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
|
||||||
|
|
||||||
|
export class Et2PortletFavorite extends Et2Portlet
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!customElements.get("et2-portlet-favorite"))
|
||||||
|
{
|
||||||
|
customElements.define("et2-portlet-favorite", Et2PortletFavorite);
|
||||||
|
}
|
@ -8,17 +8,12 @@
|
|||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*egw:uses
|
|
||||||
/vendor/bower-asset/jquery/dist/jquery.js;
|
|
||||||
/vendor/bower-asset/jquery-ui/jquery-ui.js;
|
|
||||||
/vendor/npm-asset/gridster/dist/jquery.gridster.js;
|
|
||||||
*/
|
|
||||||
import {AppJS} from "../../api/js/jsapi/app_base.js";
|
import {AppJS} from "../../api/js/jsapi/app_base.js";
|
||||||
import {et2_createWidget} from "../../api/js/etemplate/et2_core_widget";
|
import {et2_createWidget} from "../../api/js/etemplate/et2_core_widget";
|
||||||
import {et2_dialog} from "../../api/js/etemplate/et2_widget_dialog";
|
import {EgwApp} from "../../api/js/jsapi/egw_app";
|
||||||
import {et2_button} from "../../api/js/etemplate/et2_widget_button";
|
import {etemplate2} from "../../api/js/etemplate/etemplate2";
|
||||||
// need legacy loading (uses this instead of window): import "../../vendor/npm-asset/gridster/dist/jquery.gridster.js";
|
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
|
||||||
import "../../api/js/jsapi/egw_inheritance.js"; // Class
|
import {Et2PortletFavorite} from "./Et2PortletFavorite";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JS for home application
|
* JS for home application
|
||||||
@ -29,45 +24,40 @@ import "../../api/js/jsapi/egw_inheritance.js"; // Class
|
|||||||
* @see http://gridster.net
|
* @see http://gridster.net
|
||||||
* @augments AppJS
|
* @augments AppJS
|
||||||
*/
|
*/
|
||||||
app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
export class HomeApp extends EgwApp
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* AppJS requires overwriting this with the actual application name
|
|
||||||
*/
|
|
||||||
appname: "home",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grid resolution. Must match et2_portlet GRID
|
* Grid resolution. Must match et2_portlet GRID
|
||||||
*/
|
*/
|
||||||
GRID: 50,
|
public static GRID = 50;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default size for new portlets
|
* Default size for new portlets
|
||||||
*/
|
*/
|
||||||
DEFAULT: {
|
public static DEFAULT = {
|
||||||
WIDTH: 4,
|
WIDTH: 4,
|
||||||
HEIGHT: 1
|
HEIGHT: 1
|
||||||
},
|
};
|
||||||
|
|
||||||
// List of portlets
|
// List of portlets
|
||||||
portlets: {},
|
private portlets = {};
|
||||||
|
portlet_container : any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @memberOf app.home
|
|
||||||
*/
|
*/
|
||||||
init: function()
|
constructor()
|
||||||
{
|
{
|
||||||
// call parent
|
// call parent
|
||||||
this._super.apply(this, arguments);
|
super("home");
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor
|
* Destructor
|
||||||
* @memberOf app.home
|
|
||||||
*/
|
*/
|
||||||
destroy: function()
|
destroy()
|
||||||
{
|
{
|
||||||
delete this.et2;
|
delete this.et2;
|
||||||
delete this.portlet_container;
|
delete this.portlet_container;
|
||||||
@ -75,15 +65,15 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
this.portlets = {};
|
this.portlets = {};
|
||||||
|
|
||||||
// call parent
|
// call parent
|
||||||
this._super.apply(this, arguments);
|
super.destroy(this.appname);
|
||||||
|
|
||||||
// Make sure all other sub-etemplates in portlets are done
|
// Make sure all other sub-etemplates in portlets are done
|
||||||
var others = etemplate2.getByApplication(this.appname);
|
let others = etemplate2.getByApplication(this.appname);
|
||||||
for(var i = 0; i < others.length; i++)
|
for(let i = 0; i < others.length; i++)
|
||||||
{
|
{
|
||||||
others[i].clear();
|
others[i].clear();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is called when the etemplate2 object is loaded
|
* This function is called when the etemplate2 object is loaded
|
||||||
@ -93,13 +83,13 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
* @param {etemplate2} et2 Newly ready object
|
* @param {etemplate2} et2 Newly ready object
|
||||||
* @param {string} Template name
|
* @param {string} Template name
|
||||||
*/
|
*/
|
||||||
et2_ready: function(et2, name)
|
et2_ready(et2, name)
|
||||||
{
|
{
|
||||||
// Top level
|
// Top level
|
||||||
if(name == 'home.index')
|
if(name == 'home.index')
|
||||||
{
|
{
|
||||||
// call parent
|
// call parent
|
||||||
this._super.apply(this, arguments);
|
super.et2_ready(et2, name);
|
||||||
|
|
||||||
this.et2.set_id('home.index');
|
this.et2.set_id('home.index');
|
||||||
this.et2.set_actions(this.et2.getArrayMgr('modifications').getEntry('home.index')['actions']);
|
this.et2.set_actions(this.et2.getArrayMgr('modifications').getEntry('home.index')['actions']);
|
||||||
@ -107,22 +97,24 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
this.portlet_container = this.et2.getWidgetById("portlets");
|
this.portlet_container = this.et2.getWidgetById("portlets");
|
||||||
|
|
||||||
// Set up sorting of portlets
|
// Set up sorting of portlets
|
||||||
this._do_ordering();
|
//this._do_ordering();
|
||||||
|
|
||||||
// Accept drops of favorites, which aren't part of action system
|
// Accept drops of favorites, which aren't part of action system
|
||||||
jQuery(this.et2.getDOMNode().parentNode).droppable({
|
jQuery(this.et2.getDOMNode().parentNode).droppable({
|
||||||
hoverClass: 'drop-hover',
|
hoverClass: 'drop-hover',
|
||||||
accept: function(draggable) {
|
accept: function(draggable)
|
||||||
|
{
|
||||||
// Check for direct support for that application
|
// Check for direct support for that application
|
||||||
if(draggable[0].dataset && draggable[0].dataset.appname)
|
if(draggable[0].dataset && draggable[0].dataset.appname)
|
||||||
{
|
{
|
||||||
return egw_getActionManager('home',false,1).getActionById('drop_'+draggable[0].dataset.appname +'_favorite_portlet') != null;
|
return egw_getActionManager('home', false, 1).getActionById('drop_' + draggable[0].dataset.appname + '_favorite_portlet') != null;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
drop: function(event, ui) {
|
drop: function(event, ui)
|
||||||
|
{
|
||||||
// Favorite dropped on home - fake an action and divert to normal handler
|
// Favorite dropped on home - fake an action and divert to normal handler
|
||||||
var action = {
|
let action = {
|
||||||
data: {
|
data: {
|
||||||
class: 'add_home_favorite_portlet'
|
class: 'add_home_favorite_portlet'
|
||||||
}
|
}
|
||||||
@ -131,38 +123,38 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
// Check for direct support for that application
|
// Check for direct support for that application
|
||||||
if(ui.helper.context.dataset && ui.helper.context.dataset.appname)
|
if(ui.helper.context.dataset && ui.helper.context.dataset.appname)
|
||||||
{
|
{
|
||||||
var action = egw_getActionManager('home',false,1).getActionById('drop_'+ui.helper.context.dataset.appname +'_favorite_portlet') || {}
|
action = egw_getActionManager('home', false, 1).getActionById('drop_' + ui.helper.context.dataset.appname + '_favorite_portlet') || {}
|
||||||
}
|
}
|
||||||
action.ui = ui;
|
action.ui = ui;
|
||||||
app.home.add_from_drop(action, [{data: ui.helper.context.dataset}])
|
app.home.add_from_drop(action, [{data: ui.helper.context.dataset}])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Bind to unload to remove it from our list
|
// Bind to unload to remove it from our list
|
||||||
.on('clear','.et2_container[id]', jQuery.proxy(function(e) {
|
.on('clear', '.et2_container[id]', jQuery.proxy(function(e)
|
||||||
|
{
|
||||||
if(e.target && e.target.id && this.portlets[e.target.id])
|
if(e.target && e.target.id && this.portlets[e.target.id])
|
||||||
{
|
{
|
||||||
this.portlets[e.target.id].destroy();
|
this.portlets[e.target.id].destroy();
|
||||||
delete this.portlets[e.target.id];
|
delete this.portlets[e.target.id];
|
||||||
}
|
}
|
||||||
},this));
|
}, this));
|
||||||
}
|
}
|
||||||
else if (et2.uniqueId)
|
else if(et2.uniqueId)
|
||||||
{
|
{
|
||||||
let portlet_container = this.portlet_container || window.app.home?.portlet_container;
|
let portlet_container = this.portlet_container || window.app.home?.portlet_container;
|
||||||
// Handle bad timing - a sub-template was finished first
|
// Handle bad timing - a sub-template was finished first
|
||||||
if(!portlet_container)
|
if(!portlet_container)
|
||||||
{
|
{
|
||||||
window.setTimeout(jQuery.proxy(function() {this.et2_ready(et2, name);},this),200);
|
window.setTimeout(() => {this.et2_ready(et2, name);}, 200);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let portlet = portlet_container.getWidgetById(et2.uniqueId);
|
||||||
var portlet = portlet_container.getWidgetById(et2.uniqueId);
|
|
||||||
// Check for existing etemplate, this one loaded over it
|
// Check for existing etemplate, this one loaded over it
|
||||||
// NOTE: Moving them around like this can cause problems with event handlers
|
// NOTE: Moving them around like this can cause problems with event handlers
|
||||||
var existing = etemplate2.getById(et2.uniqueId);
|
let existing = etemplate2.getById(et2.uniqueId);
|
||||||
if(portlet && existing)
|
if(portlet && existing)
|
||||||
{
|
{
|
||||||
for(var i = 0; i < portlet._children.length; i++)
|
for(let i = 0; i < portlet._children.length; i++)
|
||||||
{
|
{
|
||||||
if(typeof portlet._children[i]._init == 'undefined')
|
if(typeof portlet._children[i]._init == 'undefined')
|
||||||
{
|
{
|
||||||
@ -170,11 +162,14 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Set size & position
|
||||||
|
let settings = portlet_container.getArrayMgr("content").data.find(e => e.id == et2.uniqueId) || {};
|
||||||
|
portlet.style.gridArea = settings.row + "/" + settings.col + "/ span " + (settings.height || 1) + "/ span " + (settings.width || 1);
|
||||||
|
|
||||||
// It's in the right place for original load, but move it into portlet
|
// It's in the right place for original load, but move it into portlet
|
||||||
var misplaced = jQuery(etemplate2.getById('home-index').DOMContainer).siblings('#'+et2.DOMContainer.id);
|
let misplaced = jQuery(etemplate2.getById('home-index').DOMContainer).siblings('#' + et2.DOMContainer.id);
|
||||||
if(portlet)
|
if(portlet)
|
||||||
{
|
{
|
||||||
portlet.content = jQuery(et2.DOMContainer).appendTo(portlet.content);
|
|
||||||
portlet.addChild(et2.widgetContainer);
|
portlet.addChild(et2.widgetContainer);
|
||||||
et2.resize();
|
et2.resize();
|
||||||
}
|
}
|
||||||
@ -186,17 +181,7 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
// Instanciate custom code for this portlet
|
// Instanciate custom code for this portlet
|
||||||
this._get_portlet_code(portlet);
|
this._get_portlet_code(portlet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special handling to deal with legacy (non-et2) calendar links
|
|
||||||
if(name == 'home.legacy')
|
|
||||||
{
|
|
||||||
jQuery('.calendar_calDayColHeader a, .calendar_plannerDayScale a, .calendar_plannerWeekScale a, .calendar_plannerMonthScale a, .calendar_calGridHeader a', et2.DOMContainer)
|
|
||||||
.on('click', function(e) {
|
|
||||||
egw.link_handler(this.href,'calendar');
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observer method receives update notifications from all applications
|
* Observer method receives update notifications from all applications
|
||||||
@ -217,9 +202,9 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
* @param {string} _targetapp which app's window should be refreshed, default current
|
* @param {string} _targetapp which app's window should be refreshed, default current
|
||||||
* @return {false|*} false to stop regular refresh, thought all observers are run
|
* @return {false|*} false to stop regular refresh, thought all observers are run
|
||||||
*/
|
*/
|
||||||
observer: function(_msg, _app, _id, _type, _msg_type, _targetapp)
|
observer(_msg, _app, _id, _type, _msg_type, _targetapp)
|
||||||
{
|
{
|
||||||
for(var id in this.portlets)
|
for(let id in this.portlets)
|
||||||
{
|
{
|
||||||
// App is home, refresh all portlets
|
// App is home, refresh all portlets
|
||||||
if(_app == 'home')
|
if(_app == 'home')
|
||||||
@ -231,68 +216,56 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
// Ask the portlets if they're interested
|
// Ask the portlets if they're interested
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var code = this.portlets[id];
|
let code = this.portlets[id];
|
||||||
if(code)
|
if(code)
|
||||||
{
|
{
|
||||||
code.observer(_msg,_app,_id,_type,_msg_type,_targetapp);
|
code.observer(_msg, _app, _id, _type, _msg_type, _targetapp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(e)
|
catch(e)
|
||||||
{
|
{
|
||||||
this.egw.debug("error", "Error trying to update portlet " + id,e);
|
this.egw.debug("error", "Error trying to update portlet " + id, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new portlet from the context menu
|
* Add a new portlet from the context menu
|
||||||
*/
|
*/
|
||||||
add: function(action, source) {
|
add(action, source)
|
||||||
|
{
|
||||||
// Basic portlet attributes
|
// Basic portlet attributes
|
||||||
var attrs = {
|
let attrs = {
|
||||||
|
...HomeApp.DEFAULT, ...{
|
||||||
id: this._create_id(),
|
id: this._create_id(),
|
||||||
class: action.data.class,
|
class: action.data.class
|
||||||
width: this.DEFAULT.WIDTH,
|
}
|
||||||
height: this.DEFAULT.HEIGHT
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to put it about where the menu was opened
|
// Try to put it about where the menu was opened
|
||||||
if(action.menu_context)
|
if(action.menu_context)
|
||||||
{
|
{
|
||||||
var $portlet_container = jQuery(this.portlet_container.getDOMNode());
|
let $portlet_container = jQuery(this.portlet_container.getDOMNode());
|
||||||
attrs.row = Math.max(1,Math.round((action.menu_context.posy - $portlet_container.offset().top )/ this.GRID)+1);
|
attrs.row = Math.max(1, Math.round((action.menu_context.posy - $portlet_container.offset().top) / HomeApp.GRID) + 1);
|
||||||
attrs.col = Math.max(1,Math.round((action.menu_context.posx - $portlet_container.offset().left) / this.GRID)+1);
|
attrs.col = Math.max(1, Math.round((action.menu_context.posx - $portlet_container.offset().left) / HomeApp.GRID) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't pass default width & height so class can set it
|
let portlet = <Et2Portlet>et2_createWidget('et2-portlet', attrs, this.portlet_container);
|
||||||
delete attrs.width;
|
|
||||||
delete attrs.height;
|
|
||||||
var portlet = et2_createWidget('portlet',jQuery.extend({},attrs), this.portlet_container);
|
|
||||||
portlet.loadingFinished();
|
portlet.loadingFinished();
|
||||||
|
|
||||||
// Immediately add content ID so etemplate loads into the right place
|
|
||||||
portlet.content.append('<div id="'+ attrs.id+'" class="et2_container"/>');
|
|
||||||
|
|
||||||
// Get actual attributes & settings, since they're not available client side yet
|
// Get actual attributes & settings, since they're not available client side yet
|
||||||
portlet._process_edit(et2_dialog.OK_BUTTON, attrs);
|
portlet.update_settings(attrs);
|
||||||
|
|
||||||
// Set up sorting/grid of new portlet
|
|
||||||
var $portlet_container = jQuery(this.portlet_container.getDOMNode());
|
|
||||||
$portlet_container.data("gridster").add_widget(
|
|
||||||
portlet.getDOMNode(),
|
|
||||||
this.DEFAULT.WIDTH, this.DEFAULT.HEIGHT,
|
|
||||||
attrs.col, attrs.row
|
|
||||||
);
|
|
||||||
|
|
||||||
// Instanciate custom code for this portlet
|
// Instanciate custom code for this portlet
|
||||||
this._get_portlet_code(portlet);
|
this._get_portlet_code(portlet);
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User dropped something on home. Add a new portlet
|
* User dropped something on home. Add a new portlet
|
||||||
*/
|
*/
|
||||||
add_from_drop: function(action,source) {
|
add_from_drop(action, source)
|
||||||
|
{
|
||||||
|
|
||||||
// Actions got confused drop vs popup
|
// Actions got confused drop vs popup
|
||||||
if(source[0].id == 'portlets')
|
if(source[0].id == 'portlets')
|
||||||
@ -300,10 +273,10 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
return this.add(action);
|
return this.add(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
var $portlet_container = jQuery(this.portlet_container.getDOMNode());
|
let $portlet_container = jQuery(this.portlet_container.getDOMNode());
|
||||||
|
|
||||||
// Basic portlet attributes
|
// Basic portlet attributes
|
||||||
var attrs = {
|
let attrs = {
|
||||||
id: this._create_id(),
|
id: this._create_id(),
|
||||||
class: action.data.class || action.id.substr(5),
|
class: action.data.class || action.id.substr(5),
|
||||||
width: this.DEFAULT.WIDTH,
|
width: this.DEFAULT.WIDTH,
|
||||||
@ -313,18 +286,18 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
// Try to find where the drop was
|
// Try to find where the drop was
|
||||||
if(action != null && action.ui && action.ui.position)
|
if(action != null && action.ui && action.ui.position)
|
||||||
{
|
{
|
||||||
attrs.row = Math.max(1,Math.round((action.ui.position.top - $portlet_container.offset().top )/ this.GRID));
|
attrs.row = Math.max(1, Math.round((action.ui.position.top - $portlet_container.offset().top) / this.GRID));
|
||||||
attrs.col = Math.max(1,Math.round((action.ui.position.left - $portlet_container.offset().left) / this.GRID));
|
attrs.col = Math.max(1, Math.round((action.ui.position.left - $portlet_container.offset().left) / this.GRID));
|
||||||
}
|
}
|
||||||
|
|
||||||
var portlet = et2_createWidget('portlet',jQuery.extend({},attrs), this.portlet_container);
|
let portlet = <Et2Portlet>et2_createWidget('portlet', jQuery.extend({}, attrs), this.portlet_container);
|
||||||
portlet.loadingFinished();
|
portlet.loadingFinished();
|
||||||
// Immediately add content ID so etemplate loads into the right place
|
// Immediately add content ID so etemplate loads into the right place
|
||||||
portlet.content.append('<div id="'+ attrs.id+'" class="et2_container"/>');
|
portlet.content.append('<div id="' + attrs.id + '" class="et2_container"/>');
|
||||||
|
|
||||||
// Get actual attributes & settings, since they're not available client side yet
|
// Get actual attributes & settings, since they're not available client side yet
|
||||||
var drop_data = [];
|
let drop_data = [];
|
||||||
for(var i = 0; i < source.length; i++)
|
for(let i = 0; i < source.length; i++)
|
||||||
{
|
{
|
||||||
if(source[i].id)
|
if(source[i].id)
|
||||||
{
|
{
|
||||||
@ -338,7 +311,7 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
// Don't pass default width & height so class can set it
|
// Don't pass default width & height so class can set it
|
||||||
delete attrs.width;
|
delete attrs.width;
|
||||||
delete attrs.height;
|
delete attrs.height;
|
||||||
portlet._process_edit(et2_dialog.OK_BUTTON, jQuery.extend({dropped_data: drop_data},attrs));
|
portlet._process_edit(et2_dialog.OK_BUTTON, jQuery.extend({dropped_data: drop_data}, attrs));
|
||||||
|
|
||||||
// Set up sorting/grid of new portlet
|
// Set up sorting/grid of new portlet
|
||||||
$portlet_container.data("gridster").add_widget(
|
$portlet_container.data("gridster").add_widget(
|
||||||
@ -349,7 +322,7 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
|
|
||||||
// Instanciate custom code for this portlet
|
// Instanciate custom code for this portlet
|
||||||
this._get_portlet_code(portlet);
|
this._get_portlet_code(portlet);
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current selection as default for other users
|
* Set the current selection as default for other users
|
||||||
@ -360,25 +333,27 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
* @param {egwAction} action
|
* @param {egwAction} action
|
||||||
* @param {egwActionObject[]} selected
|
* @param {egwActionObject[]} selected
|
||||||
*/
|
*/
|
||||||
set_default: function(action, selected) {
|
set_default(action, selected)
|
||||||
|
{
|
||||||
// Gather just IDs, server will handle the details
|
// Gather just IDs, server will handle the details
|
||||||
var portlet_ids = [];
|
let portlet_ids = [];
|
||||||
var group = action.data.portlet_group || false;
|
let group = action.data.portlet_group || false;
|
||||||
if(selected[0].id == 'home.index')
|
if(selected[0].id == 'home.index')
|
||||||
{
|
{
|
||||||
// Set all
|
// Set all
|
||||||
this.portlet_container.iterateOver(function(portlet) {
|
this.portlet_container.iterateOver(function(portlet)
|
||||||
|
{
|
||||||
portlet_ids.push(portlet.id);
|
portlet_ids.push(portlet.id);
|
||||||
},this,et2_portlet);
|
}, this, et2_portlet);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(var i = 0; i < selected.length; i++)
|
for(let i = 0; i < selected.length; i++)
|
||||||
{
|
{
|
||||||
portlet_ids.push(selected[i].id);
|
portlet_ids.push(selected[i].id);
|
||||||
|
|
||||||
// Read the associated group so we can properly remove it
|
// Read the associated group so we can properly remove it
|
||||||
var portlet = egw.preference(selected[i].id,'home');
|
let portlet = egw.preference(selected[i].id, 'home');
|
||||||
if(!group && portlet && portlet.group)
|
if(!group && portlet && portlet.group)
|
||||||
{
|
{
|
||||||
group = portlet.group;
|
group = portlet.group;
|
||||||
@ -395,33 +370,38 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
egw.json('home_ui::ajax_set_default', ['delete', portlet_ids, group]).sendRequest(true);
|
egw.json('home_ui::ajax_set_default', ['delete', portlet_ids, group]).sendRequest(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var dialog = et2_createWidget("dialog",{
|
let dialog = et2_createWidget("dialog", {
|
||||||
// If you use a template, the second parameter will be the value of the template, as if it were submitted.
|
// If you use a template, the second parameter will be the value of the template, as if it were submitted.
|
||||||
callback: function(button_id, value) {
|
callback: function(button_id, value)
|
||||||
if(button_id != et2_dialog.OK_BUTTON) return;
|
{
|
||||||
|
if(button_id != et2_dialog.OK_BUTTON)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Pass them to server
|
// Pass them to server
|
||||||
egw.json('home_ui::ajax_set_default', ['add', portlet_ids, value.group||false]).sendRequest(true);
|
egw.json('home_ui::ajax_set_default', ['add', portlet_ids, value.group || false]).sendRequest(true);
|
||||||
},
|
},
|
||||||
buttons: et2_dialog.BUTTONS_OK_CANCEL,
|
buttons: et2_dialog.BUTTONS_OK_CANCEL,
|
||||||
title: action.caption,
|
title: action.caption,
|
||||||
template:"home.set_default",
|
template: "home.set_default",
|
||||||
value: {content:{}, sel_options: {group:{default: egw.lang('All'), forced: egw.lang('Forced')}}}
|
value: {content: {}, sel_options: {group: {default: egw.lang('All'), forced: egw.lang('Forced')}}}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow a refresh from anywhere by triggering an update with no changes
|
* Allow a refresh from anywhere by triggering an update with no changes
|
||||||
*
|
*
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
*/
|
*/
|
||||||
refresh: function(id) {
|
refresh(id)
|
||||||
var p = this.portlet_container.getWidgetById(id);
|
{
|
||||||
|
let p = this.portlet_container.getWidgetById(id);
|
||||||
if(p)
|
if(p)
|
||||||
{
|
{
|
||||||
p._process_edit(et2_dialog.OK_BUTTON, '~reload~');
|
p._process_edit(et2_dialog.OK_BUTTON, '~reload~');
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the best fitting code to use for the given portlet, instanciate
|
* Determine the best fitting code to use for the given portlet, instanciate
|
||||||
@ -430,33 +410,36 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
* @param {et2_portlet} portlet
|
* @param {et2_portlet} portlet
|
||||||
* @returns {home_portlet}
|
* @returns {home_portlet}
|
||||||
*/
|
*/
|
||||||
_get_portlet_code: function(portlet) {
|
_get_portlet_code(portlet)
|
||||||
var classname = portlet.class;
|
{
|
||||||
|
let classname = portlet.class;
|
||||||
// Freshly added portlets can have 'add_' prefix
|
// Freshly added portlets can have 'add_' prefix
|
||||||
if(classname.indexOf('add_') == 0)
|
if(classname.indexOf('add_') == 0)
|
||||||
{
|
{
|
||||||
classname = classname.replace('add_','');
|
classname = classname.replace('add_', '');
|
||||||
}
|
}
|
||||||
// Prefer a specific match
|
// Prefer a specific match
|
||||||
var _class = app.classes.home[classname] ||
|
let _class = app.classes.home[classname] ||
|
||||||
|
(typeof customElements.get(classname) != "undefined" ? customElements.get(classname).class : false) ||
|
||||||
// If it has a nextmatch, use favorite base class
|
// If it has a nextmatch, use favorite base class
|
||||||
(portlet.getWidgetById('nm') ? app.classes.home.home_favorite_portlet : false) ||
|
(portlet.getWidgetById('nm') ? Et2PortletFavorite : false) ||
|
||||||
// Fall back to base class
|
// Fall back to base class
|
||||||
app.classes.home.home_portlet;
|
Et2Portlet;
|
||||||
|
|
||||||
this.portlets[portlet.id] = new _class(portlet);
|
this.portlets[portlet.id] = new _class(portlet);
|
||||||
|
|
||||||
return this.portlets[portlet.id];
|
return this.portlets[portlet.id];
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For link_portlet - opens the configured record when the user
|
* For link_portlet - opens the configured record when the user
|
||||||
* double-clicks or chooses view from the context menu
|
* double-clicks or chooses view from the context menu
|
||||||
*/
|
*/
|
||||||
open_link: function(action) {
|
open_link(action)
|
||||||
|
{
|
||||||
|
|
||||||
// Get widget
|
// Get widget
|
||||||
var widget = null;
|
let widget = null;
|
||||||
while(action.parent != null)
|
while(action.parent != null)
|
||||||
{
|
{
|
||||||
if(action.data && action.data.widget)
|
if(action.data && action.data.widget)
|
||||||
@ -468,26 +451,25 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
}
|
}
|
||||||
if(widget == null)
|
if(widget == null)
|
||||||
{
|
{
|
||||||
egw().log("warning", "Could not find widget");
|
this.egw.log("warning", "Could not find widget");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
egw().open(widget.options.settings.entry, "", 'view',null,widget.options.settings.entry.app);
|
this.egw.open(widget.options.settings.entry, "", 'view', null, widget.options.settings.entry.app);
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the drag / drop / re-order of portlets
|
* Set up the drag / drop / re-order of portlets
|
||||||
*/
|
*/
|
||||||
_do_ordering: function() {
|
_do_ordering()
|
||||||
var $portlet_container = jQuery(this.portlet_container.getDOMNode());
|
{
|
||||||
|
let $portlet_container = jQuery(this.portlet_container.getDOMNode());
|
||||||
$portlet_container
|
$portlet_container
|
||||||
.addClass("home ui-helper-clearfix")
|
|
||||||
.disableSelection()
|
|
||||||
/* Gridster */
|
/* Gridster */
|
||||||
.gridster({
|
.gridster({
|
||||||
widget_selector: 'div.et2_portlet',
|
widget_selector: 'div.et2_portlet',
|
||||||
// Dimensions + margins = grid spacing
|
// Dimensions + margins = grid spacing
|
||||||
widget_base_dimensions: [this.GRID-5, this.GRID-5],
|
widget_base_dimensions: [home.GRID - 5, home.GRID - 5],
|
||||||
widget_margins: [5,5],
|
widget_margins: [5, 5],
|
||||||
extra_rows: 1,
|
extra_rows: 1,
|
||||||
extra_cols: 1,
|
extra_cols: 1,
|
||||||
min_cols: 3,
|
min_cols: 3,
|
||||||
@ -498,9 +480,10 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
* @param grid Object Grid settings
|
* @param grid Object Grid settings
|
||||||
* @return Object - will be returned by gridster.serialize()
|
* @return Object - will be returned by gridster.serialize()
|
||||||
*/
|
*/
|
||||||
serialize_params: function($w, grid) {
|
serialize_params: function($w, grid)
|
||||||
|
{
|
||||||
return {
|
return {
|
||||||
id: $w.attr('id').replace(app.home.portlet_container.getInstanceManager().uniqueId+'_',''),
|
id: $w.attr('id').replace(app.home.portlet_container.getInstanceManager().uniqueId + '_', ''),
|
||||||
row: grid.row,
|
row: grid.row,
|
||||||
col: grid.col,
|
col: grid.col,
|
||||||
width: grid.size_x,
|
width: grid.size_x,
|
||||||
@ -512,24 +495,31 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
*/
|
*/
|
||||||
draggable: {
|
draggable: {
|
||||||
handle: '.ui-widget-header',
|
handle: '.ui-widget-header',
|
||||||
stop: function(event,ui) {
|
stop: function(event, ui)
|
||||||
|
{
|
||||||
// Update widget(s)
|
// Update widget(s)
|
||||||
var changed = this.serialize_changed();
|
let changed = this.serialize_changed();
|
||||||
|
|
||||||
// Reset changed, or they keep accumulating
|
// Reset changed, or they keep accumulating
|
||||||
this.$changed = jQuery([]);
|
this.$changed = jQuery([]);
|
||||||
|
|
||||||
for (var key in changed)
|
for(let key in changed)
|
||||||
{
|
{
|
||||||
if(!changed[key].id) continue;
|
if(!changed[key].id)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Changed ID is the ID
|
// Changed ID is the ID
|
||||||
var widget = window.app.home.portlet_container.getWidgetById(changed[key].id);
|
let widget = window.app.home.portlet_container.getWidgetById(changed[key].id);
|
||||||
if(!widget || widget == window.app.home.portlet_container) continue;
|
if(!widget || widget == window.app.home.portlet_container)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
egw().jsonq("home.home_ui.ajax_set_properties",[changed[key].id, {},{
|
egw().jsonq("home.home_ui.ajax_set_properties", [changed[key].id, {}, {
|
||||||
row: changed[key].row,
|
row: changed[key].row,
|
||||||
col: changed[key].col
|
col: changed[key].col
|
||||||
},widget.settings?widget.settings.group:false],
|
}, widget.settings ? widget.settings.group : false],
|
||||||
null,
|
null,
|
||||||
widget, true, widget
|
widget, true, widget
|
||||||
);
|
);
|
||||||
@ -540,40 +530,44 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Rescue selectboxes from Firefox
|
// Rescue selectboxes from Firefox
|
||||||
$portlet_container.on('mousedown touchstart', 'select', function(e) {
|
$portlet_container.on('mousedown touchstart', 'select', function(e)
|
||||||
|
{
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
// Bind window resize to re-layout gridster
|
// Bind window resize to re-layout gridster
|
||||||
jQuery(window).one("resize."+this.et2._inst.uniqueId, function() {
|
jQuery(window).one("resize." + this.et2._inst.uniqueId, function()
|
||||||
|
{
|
||||||
// Note this doesn't change the positions, just makes them invalid
|
// Note this doesn't change the positions, just makes them invalid
|
||||||
$portlet_container.data('gridster').recalculate_faux_grid();
|
$portlet_container.data('gridster').recalculate_faux_grid();
|
||||||
});
|
});
|
||||||
// Bind resize to update gridster - this may happen _before_ the widget gets a
|
// Bind resize to update gridster - this may happen _before_ the widget gets a
|
||||||
// chance to update itself, so we can't use the widget
|
// chance to update itself, so we can't use the widget
|
||||||
$portlet_container
|
$portlet_container
|
||||||
.on("resizestop", function(event, ui) {
|
.on("resizestop", function(event, ui)
|
||||||
|
{
|
||||||
$portlet_container.data("gridster").resize_widget(
|
$portlet_container.data("gridster").resize_widget(
|
||||||
ui.element,
|
ui.element,
|
||||||
Math.round(ui.size.width / app.home.GRID),
|
Math.round(ui.size.width / app.home.GRID),
|
||||||
Math.round(ui.size.height / app.home.GRID)
|
Math.round(ui.size.height / app.home.GRID)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an ID that should be unique, at least amoung a single user's portlets
|
* Create an ID that should be unique, at least amoung a single user's portlets
|
||||||
*/
|
*/
|
||||||
_create_id: function() {
|
_create_id()
|
||||||
var id = '';
|
{
|
||||||
|
let id = '';
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
id = Math.floor((1 + Math.random()) * 0x10000)
|
id = Math.floor((1 + Math.random()) * 0x10000)
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.substring(1);
|
.substring(1);
|
||||||
}
|
}
|
||||||
while(this.portlet_container.getWidgetById('portlet_'+id));
|
while(this.portlet_container.getWidgetById('portlet_' + id));
|
||||||
return 'portlet_'+id;
|
return 'portlet_' + id;
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions for the list portlet
|
* Functions for the list portlet
|
||||||
@ -585,7 +579,8 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
* @param {egwActionObject[]} Selected entries
|
* @param {egwActionObject[]} Selected entries
|
||||||
* @param {egwActionObject} target_action Drop target
|
* @param {egwActionObject} target_action Drop target
|
||||||
*/
|
*/
|
||||||
add_link: function(action, source, target_action) {
|
add_link(action, source, target_action)
|
||||||
|
{
|
||||||
// Actions got confused drop vs popup
|
// Actions got confused drop vs popup
|
||||||
if(source[0].id == 'portlets')
|
if(source[0].id == 'portlets')
|
||||||
{
|
{
|
||||||
@ -593,7 +588,7 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get widget
|
// Get widget
|
||||||
var widget = null;
|
let widget = null;
|
||||||
while(action.parent != null)
|
while(action.parent != null)
|
||||||
{
|
{
|
||||||
if(action.data && action.data.widget)
|
if(action.data && action.data.widget)
|
||||||
@ -606,14 +601,18 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
if(target_action == null)
|
if(target_action == null)
|
||||||
{
|
{
|
||||||
// use template base url from initial template, to continue using webdav, if that was loaded via webdav
|
// use template base url from initial template, to continue using webdav, if that was loaded via webdav
|
||||||
var splitted = 'home.edit'.split('.');
|
let splitted = 'home.edit'.split('.');
|
||||||
var path = app.home.portlet_container.getRoot()._inst.template_base_url + splitted.shift() + "/templates/default/" +
|
let path = app.home.portlet_container.getRoot()._inst.template_base_url + splitted.shift() + "/templates/default/" +
|
||||||
splitted.join('.')+ ".xet";
|
splitted.join('.') + ".xet";
|
||||||
var dialog = et2_createWidget("dialog",{
|
let dialog = et2_createWidget("dialog", {
|
||||||
callback: function(button_id, value) {
|
callback: function(button_id, value)
|
||||||
if(button_id == et2_dialog.CANCEL_BUTTON) return;
|
{
|
||||||
var new_list = widget.options.settings.list || [];
|
if(button_id == et2_dialog.CANCEL_BUTTON)
|
||||||
for(var i = 0; i < new_list.length; i++)
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let new_list = widget.options.settings.list || [];
|
||||||
|
for(let i = 0; i < new_list.length; i++)
|
||||||
{
|
{
|
||||||
if(new_list[i].app == value.add.app && new_list[i].id == value.add.id)
|
if(new_list[i].app == value.add.app && new_list[i].id == value.add.id)
|
||||||
{
|
{
|
||||||
@ -624,9 +623,9 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
value.add.link_id = value.add.app + ':' + value.add.id;
|
value.add.link_id = value.add.app + ':' + value.add.id;
|
||||||
// Update server side
|
// Update server side
|
||||||
new_list.push(value.add);
|
new_list.push(value.add);
|
||||||
widget._process_edit(button_id,{list: new_list});
|
widget._process_edit(button_id, {list: new_list});
|
||||||
// Update client side
|
// Update client side
|
||||||
var list = widget.getWidgetById('list');
|
let list = widget.getWidgetById('list');
|
||||||
if(list)
|
if(list)
|
||||||
{
|
{
|
||||||
list.set_value(new_list);
|
list.set_value(new_list);
|
||||||
@ -634,41 +633,41 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
},
|
},
|
||||||
buttons: et2_dialog.BUTTONS_OK_CANCEL,
|
buttons: et2_dialog.BUTTONS_OK_CANCEL,
|
||||||
title: app.home.egw.lang('add'),
|
title: app.home.egw.lang('add'),
|
||||||
template:path,
|
template: path,
|
||||||
value: { content: [{label: app.home.egw.lang('add'),type: 'link-entry',name: 'add',size:''}]}
|
value: {content: [{label: app.home.egw.lang('add'), type: 'link-entry', name: 'add', size: ''}]}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Drag'n'dropped something on the list - just send action IDs
|
// Drag'n'dropped something on the list - just send action IDs
|
||||||
var new_list = widget.options.settings.list || [];
|
let new_list = widget.options.settings.list || [];
|
||||||
var changed = false;
|
let changed = false;
|
||||||
for(var i = 0; i < new_list.length; i++)
|
for(let i = 0; i < new_list.length; i++)
|
||||||
{
|
{
|
||||||
// Avoid duplicates
|
// Avoid duplicates
|
||||||
for(var j = 0; j < source.length; j++)
|
for(let j = 0; j < source.length; j++)
|
||||||
{
|
{
|
||||||
if(!source[j].id || new_list[i].app+"::"+new_list[i].id == source[j].id)
|
if(!source[j].id || new_list[i].app + "::" + new_list[i].id == source[j].id)
|
||||||
{
|
{
|
||||||
// Duplicate - skip it
|
// Duplicate - skip it
|
||||||
source.splice(j,1);
|
source.splice(j, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(var i = 0; i < source.length; i++)
|
for(let i = 0; i < source.length; i++)
|
||||||
{
|
{
|
||||||
var explode = source[i].id.split('::');
|
let explode = source[i].id.split('::');
|
||||||
new_list.push({app: explode[0],id: explode[1], link_id: explode.join(':')});
|
new_list.push({app: explode[0], id: explode[1], link_id: explode.join(':')});
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
if(changed)
|
if(changed)
|
||||||
{
|
{
|
||||||
widget._process_edit(et2_dialog.OK_BUTTON,{
|
widget._process_edit(et2_dialog.OK_BUTTON, {
|
||||||
list: new_list || {}
|
list: new_list || {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Filemanager support - links need app = 'file' and type set
|
// Filemanager support - links need app = 'file' and type set
|
||||||
for(var i = 0; i < new_list.length; i++)
|
for(let i = 0; i < new_list.length; i++)
|
||||||
{
|
{
|
||||||
if(new_list[i]['app'] == 'filemanager')
|
if(new_list[i]['app'] == 'filemanager')
|
||||||
{
|
{
|
||||||
@ -679,20 +678,21 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
|
|
||||||
widget.getWidgetById('list').set_value(new_list);
|
widget.getWidgetById('list').set_value(new_list);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a link from the list
|
* Remove a link from the list
|
||||||
*/
|
*/
|
||||||
link_change: function(list, link_id, row) {
|
link_change(list, link_id, row)
|
||||||
|
{
|
||||||
// Quick response client side
|
// Quick response client side
|
||||||
row.slideUp(row.remove);
|
row.slideUp(row.remove);
|
||||||
|
|
||||||
// Actual removal
|
// Actual removal
|
||||||
var portlet = list._parent._parent;
|
let portlet = list._parent._parent;
|
||||||
portlet.options.settings.list.splice(row.index(), 1);
|
portlet.options.settings.list.splice(row.index(), 1);
|
||||||
portlet._process_edit(et2_dialog.OK_BUTTON,{list: portlet.options.settings.list || {}});
|
portlet._process_edit(et2_dialog.OK_BUTTON, {list: portlet.options.settings.list || {}});
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions for the note portlet
|
* Functions for the note portlet
|
||||||
@ -704,33 +704,34 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
* @param {egwAction} action
|
* @param {egwAction} action
|
||||||
* @param {egwActionObject[]} Selected
|
* @param {egwActionObject[]} Selected
|
||||||
*/
|
*/
|
||||||
note_edit: function(action, selected) {
|
note_edit(action, selected)
|
||||||
|
{
|
||||||
if(!selected && typeof action == 'string')
|
if(!selected && typeof action == 'string')
|
||||||
{
|
{
|
||||||
var id = action;
|
let id = action;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var id = selected[0].id;
|
let id = selected[0].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aim to match the size
|
// Aim to match the size
|
||||||
var portlet_dom = jQuery('[id$='+id+'][data-sizex]',this.portlet_container.getDOMNode());
|
let portlet_dom = jQuery('[id$=' + id + '][data-sizex]', this.portlet_container.getDOMNode());
|
||||||
var width = portlet_dom.attr('data-sizex') * this.GRID;
|
let width = portlet_dom.attr('data-sizex') * this.GRID;
|
||||||
var height = portlet_dom.attr('data-sizey') * this.GRID;
|
let height = portlet_dom.attr('data-sizey') * this.GRID;
|
||||||
|
|
||||||
// CKEditor is impossible to use below a certain size
|
// CKEditor is impossible to use below a certain size
|
||||||
// Add 35px for the toolbar, 35px for the buttons
|
// Add 35px for the toolbar, 35px for the buttons
|
||||||
var window_width = Math.max(580, width+20);
|
let window_width = Math.max(580, width + 20);
|
||||||
var window_height = Math.max(350, height+70);
|
let window_height = Math.max(350, height + 70);
|
||||||
|
|
||||||
// Open popup, but add 70 to the height for the toolbar
|
// Open popup, but add 70 to the height for the toolbar
|
||||||
egw.open_link(egw.link('/index.php',{
|
this.egw.open_link(this.egw.link('/index.php', {
|
||||||
menuaction: 'home.home_note_portlet.edit',
|
menuaction: 'home.home_note_portlet.edit',
|
||||||
id: id,
|
id: id,
|
||||||
height: window_height - 70
|
height: window_height - 70
|
||||||
}),'home_'+id, window_width+'x'+window_height,'home');
|
}), 'home_' + id, window_width + 'x' + window_height, 'home');
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Favorites / nextmatch
|
* Favorites / nextmatch
|
||||||
@ -741,18 +742,24 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
* @param {et2_button} widget
|
* @param {et2_button} widget
|
||||||
*/
|
*/
|
||||||
nextmatch_toggle_header: function(event, widget) {
|
nextmatch_toggle_header(event, widget)
|
||||||
|
{
|
||||||
widget.set_class(widget.class == 'opened' ? 'closed' : 'opened');
|
widget.set_class(widget.class == 'opened' ? 'closed' : 'opened');
|
||||||
// We operate on the DOM here, nm should be unaware of our fiddling
|
// We operate on the DOM here, nm should be unaware of our fiddling
|
||||||
var nm = widget.getParent().getWidgetById('nm');
|
let nm = widget.getParent().getWidgetById('nm');
|
||||||
if(!nm) return;
|
if(!nm)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Hide header
|
// Hide header
|
||||||
nm.div.toggleClass('header_hidden');
|
nm.div.toggleClass('header_hidden');
|
||||||
nm.set_hide_header(nm.div.hasClass('header_hidden'));
|
nm.set_hide_header(nm.div.hasClass('header_hidden'));
|
||||||
nm.resize();
|
nm.resize();
|
||||||
}
|
}
|
||||||
})}).call(window);
|
}
|
||||||
|
|
||||||
|
app.classes.home = HomeApp;
|
||||||
|
|
||||||
/// Base class code
|
/// Base class code
|
||||||
|
|
||||||
@ -763,15 +770,19 @@ app.classes.home = (function(){ "use strict"; return AppJS.extend(
|
|||||||
*
|
*
|
||||||
* @type @exp;Class@call;extend
|
* @type @exp;Class@call;extend
|
||||||
*/
|
*/
|
||||||
app.classes.home.home_portlet = Class.extend({
|
export class HomePortlet
|
||||||
portlet: null,
|
{
|
||||||
|
protected portlet = null;
|
||||||
|
|
||||||
init: function(portlet) {
|
init(portlet)
|
||||||
|
{
|
||||||
this.portlet = portlet;
|
this.portlet = portlet;
|
||||||
},
|
}
|
||||||
destroy: function() {
|
|
||||||
|
destroy()
|
||||||
|
{
|
||||||
this.portlet = null;
|
this.portlet = null;
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle framework refresh messages to determine if the portlet needs to
|
* Handle framework refresh messages to determine if the portlet needs to
|
||||||
@ -780,12 +791,13 @@ app.classes.home.home_portlet = Class.extend({
|
|||||||
* App is responsible for only reacting to "messages" it is interested in!
|
* App is responsible for only reacting to "messages" it is interested in!
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
observer: function(_msg, _app, _id, _type, _msg_type, _targetapp)
|
observer(_msg, _app, _id, _type, _msg_type, _targetapp)
|
||||||
{
|
{
|
||||||
// Not interested
|
// Not interested
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
app.classes.home.home_link_portlet = app.classes.home.home_portlet.extend({
|
app.classes.home.home_link_portlet = app.classes.home.home_portlet.extend({
|
||||||
init: function(portlet) {
|
init: function(portlet) {
|
||||||
// call parent
|
// call parent
|
||||||
@ -794,7 +806,7 @@ app.classes.home.home_link_portlet = app.classes.home.home_portlet.extend({
|
|||||||
// Check for tooltip
|
// Check for tooltip
|
||||||
if(this.portlet)
|
if(this.portlet)
|
||||||
{
|
{
|
||||||
var content = jQuery('.tooltip',this.portlet.content);
|
let content = jQuery('.tooltip', this.portlet.content);
|
||||||
if(content.length && content.children().length)
|
if(content.length && content.children().length)
|
||||||
{
|
{
|
||||||
//Check if the tooltip is already initialized
|
//Check if the tooltip is already initialized
|
||||||
@ -831,7 +843,7 @@ app.classes.home.home_link_portlet = app.classes.home.home_portlet.extend({
|
|||||||
{
|
{
|
||||||
if(this.portlet && this.portlet.settings)
|
if(this.portlet && this.portlet.settings)
|
||||||
{
|
{
|
||||||
var value = this.portlet.settings.entry || {};
|
let value = this.portlet.settings.entry || {};
|
||||||
if(value.app && value.app == _app && value.id && value.id == _id)
|
if(value.app && value.app == _app && value.id && value.id == _id)
|
||||||
{
|
{
|
||||||
// We don't just get the updated title, in case there's a custom
|
// We don't just get the updated title, in case there's a custom
|
||||||
@ -846,8 +858,8 @@ app.classes.home.home_list_portlet = app.classes.home.home_portlet.extend({
|
|||||||
{
|
{
|
||||||
if(this.portlet && this.portlet.getWidgetById('list'))
|
if(this.portlet && this.portlet.getWidgetById('list'))
|
||||||
{
|
{
|
||||||
var list = this.portlet.getWidgetById('list').options.value;
|
let list = this.portlet.getWidgetById('list').options.value;
|
||||||
for(var i = 0; i < list.length; i++)
|
for(let i = 0; i < list.length; i++)
|
||||||
{
|
{
|
||||||
if(list[i].app == _app && list[i].id == _id)
|
if(list[i].app == _app && list[i].id == _id)
|
||||||
{
|
{
|
@ -10,6 +10,16 @@
|
|||||||
}
|
}
|
||||||
#home-index_portlets {
|
#home-index_portlets {
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
|
display: grid;
|
||||||
|
grid-auto-columns: 50ex;
|
||||||
|
grid-auto-rows: 50ex;
|
||||||
|
|
||||||
|
gap: 2ex;
|
||||||
|
|
||||||
|
justify-content: stretch;
|
||||||
|
align-content: stretch;
|
||||||
|
justify-items: stretch;
|
||||||
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
#portlets {
|
#portlets {
|
||||||
border: 1px solid silver;
|
border: 1px solid silver;
|
||||||
@ -26,14 +36,8 @@
|
|||||||
.et2_portlet.ui-widget-content > div {
|
.et2_portlet.ui-widget-content > div {
|
||||||
|
|
||||||
}
|
}
|
||||||
.et2_portlet.ui-widget-content > div:last-of-type {
|
|
||||||
/* Allow space for header, as the whole portlet is sized by auto-generated css */
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0px;
|
|
||||||
top: 20px;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.et2_portlet .et2_container {
|
.et2_portlet .et2_container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,15 @@
|
|||||||
<html id="mainscreen_message"/>
|
<html id="mainscreen_message"/>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<et2-box id="portlets">
|
<old-box id="portlets">
|
||||||
<!-- Box wrapper needed to get box to auto-repeat -->
|
<!-- Box wrapper needed to get box to auto-repeat -->
|
||||||
<et2-box id="${row}"><portlet id="${_cont[id]}" title="$_cont[title]" color="@color" parent_node="home-index_portlets" settings="@settings" width="@width" height="@height" row="@row" col="@col" value="@content" class="@class"/></et2-box>
|
<et2-box id="${row}">
|
||||||
|
<et2-portlet id="${_cont[id]}" title="$_cont[title]" color="@color"
|
||||||
|
parent_node="home-index_portlets" settings="@settings" width="@width"
|
||||||
|
height="@height" row="@row" col="@col" value="@content" class="@class"
|
||||||
|
actions="@actions"/>
|
||||||
</et2-box>
|
</et2-box>
|
||||||
|
</old-box>
|
||||||
</row>
|
</row>
|
||||||
</rows>
|
</rows>
|
||||||
</grid>
|
</grid>
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
/**
|
|
||||||
* EGroupware: CSS with less preprocessor
|
|
||||||
*
|
|
||||||
* Please do NOT change app.css directly, instead change app.less and compile it!
|
|
||||||
*
|
|
||||||
* @link http://www.egroupware.org
|
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
||||||
* @author Stefan Reinhardt <stefan.reinhardt@pixelegg.de>
|
|
||||||
* @package home
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
@ -1,18 +0,0 @@
|
|||||||
/**
|
|
||||||
* EGroupware: CSS with less preprocessor
|
|
||||||
*
|
|
||||||
* Please do NOT change app.css directly, instead change app.less and compile it!
|
|
||||||
*
|
|
||||||
* @link http://www.egroupware.org
|
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
||||||
* @author Stefan Reinhardt <stefan.reinhardt@pixelegg.de>
|
|
||||||
* @package home
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
@import (reference) "../../../pixelegg/less/def_buttons.less";
|
|
||||||
@import (reference) "../../../pixelegg/less/def_design_pattern_color_font_shadow.less";
|
|
||||||
|
|
||||||
@import (reference) "../default/app.css";
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user