2020-01-24 14:08:09 +01:00
|
|
|
/**
|
|
|
|
* EGroupware eTemplate2 - JS toolbar object
|
|
|
|
*
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
* @package etemplate
|
|
|
|
* @subpackage api
|
2021-06-07 17:33:53 +02:00
|
|
|
* @link https://www.egroupware.org
|
2020-01-24 14:08:09 +01:00
|
|
|
* @author Nathan Gray
|
|
|
|
* @copyright Nathan Gray 2013
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*egw:uses
|
|
|
|
/vendor/bower-asset/jquery/dist/jquery.js;
|
|
|
|
et2_DOMWidget;
|
|
|
|
*/
|
|
|
|
|
|
|
|
import {et2_DOMWidget} from "./et2_core_DOMWidget";
|
2022-08-07 10:10:33 +02:00
|
|
|
import {et2_register_widget, WidgetConfig} from "./et2_core_widget";
|
2020-01-24 14:08:09 +01:00
|
|
|
import {ClassWithAttributes} from "./et2_core_inheritance";
|
2022-03-30 21:24:52 +02:00
|
|
|
import {egw_getObjectManager, egwActionObject, egwActionObjectManager} from '../egw_action/egw_action.js';
|
2021-06-07 17:33:53 +02:00
|
|
|
import {et2_IInput} from "./et2_core_interfaces";
|
|
|
|
import {egw} from "../jsapi/egw_global";
|
2021-06-09 14:28:29 +02:00
|
|
|
import {egwIsMobile} from "../egw_action/egw_action_common.js";
|
2022-03-30 21:24:52 +02:00
|
|
|
import {Et2Dialog} from "./Et2Dialog/Et2Dialog";
|
2022-05-13 22:19:21 +02:00
|
|
|
import {Et2DropdownButton} from "./Et2DropdownButton/Et2DropdownButton";
|
|
|
|
import {loadWebComponent} from "./Et2Widget/Et2Widget";
|
2022-06-01 16:46:44 +02:00
|
|
|
import interact from "@interactjs/interactjs";
|
2022-08-01 17:59:40 +02:00
|
|
|
import {Et2Button} from "./Et2Button/Et2Button";
|
2022-08-03 13:41:58 +02:00
|
|
|
import {Et2Checkbox} from "./Et2Checkbox/Et2Checkbox";
|
2022-03-30 21:24:52 +02:00
|
|
|
|
2020-01-24 14:08:09 +01:00
|
|
|
/**
|
|
|
|
* This toolbar gets its contents from its actions
|
|
|
|
*
|
|
|
|
* @augments et2_valueWidget
|
|
|
|
*/
|
2021-06-07 17:33:53 +02:00
|
|
|
export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
2022-03-30 21:24:52 +02:00
|
|
|
static readonly _attributes : any = {
|
2020-01-24 14:08:09 +01:00
|
|
|
"view_range": {
|
|
|
|
"name": "View range",
|
|
|
|
"type": "string",
|
|
|
|
"default": "5",
|
|
|
|
"description": "Define minimum action view range to show actions by both icons and caption"
|
|
|
|
},
|
|
|
|
"flat_list": {
|
|
|
|
"name": "Flat list",
|
|
|
|
"type": "boolean",
|
|
|
|
"default": true,
|
|
|
|
"description": "Define whether the actions with children should be shown as dropdown or flat list"
|
2021-09-07 16:30:53 +02:00
|
|
|
},
|
|
|
|
"list_header": {
|
|
|
|
"name": "list header style",
|
|
|
|
"type": "string",
|
2022-07-19 14:36:01 +02:00
|
|
|
"default": "short",
|
2021-09-07 16:30:53 +02:00
|
|
|
"description": "Define a style for list header (more ...), which can get short 3dots with no caption or bigger button with caption more ..."
|
2021-10-11 10:34:19 +02:00
|
|
|
},
|
|
|
|
"preference_id": {
|
|
|
|
"name": "Preference id",
|
|
|
|
"type": "string",
|
|
|
|
"default": false,
|
|
|
|
"description": "Define a custom preference id for saving the toolbar preferences." +
|
|
|
|
"This is useful when you have the same toolbar and you use it in a pop up but also in a tab, which have different dom ids" +
|
|
|
|
"When not set it defaults to the dom id of the form."
|
|
|
|
},
|
|
|
|
"preference_app": {
|
|
|
|
"name": "Preference application",
|
|
|
|
"type": "string",
|
|
|
|
"default": false,
|
|
|
|
"description": "Define a custom preference application for saving the toolbar preferences." +
|
|
|
|
"This is useful when you have the same toolbar and you use it in a pop up but also in a tab, wich have different application names" +
|
|
|
|
"When not set it defaults to the result of this.egw().app_name();"
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default buttons, so there is something for the widget browser / editor to show
|
|
|
|
*/
|
|
|
|
static default_toolbar : any = {
|
|
|
|
view: {caption:'View', icons: {primary: 'ui-icon-check'}, group:1, toolbarDefault:true},
|
|
|
|
edit: {caption:'Edit', group:1, toolbarDefault:true},
|
|
|
|
save: {caption:'Save', group:2, toolbarDefault:true}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* id of last action executed / value of toolbar if submitted
|
|
|
|
*/
|
|
|
|
value : string = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* actionbox is a div for stored actions
|
|
|
|
*/
|
|
|
|
private readonly actionbox : JQuery = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* actionlist is a div for active actions
|
|
|
|
*/
|
|
|
|
private readonly actionlist : JQuery = null;
|
|
|
|
div : JQuery = null;
|
|
|
|
private countActions : number = 0;
|
|
|
|
private dropdowns : object = {};
|
|
|
|
private preference : object = {};
|
|
|
|
menu : any = null;
|
2020-05-29 19:21:17 +02:00
|
|
|
private _objectManager : egwActionObject = null;
|
2020-01-24 14:08:09 +01:00
|
|
|
|
|
|
|
constructor(_parent, _attrs? : WidgetConfig, _child? : object)
|
|
|
|
{
|
|
|
|
// Call the inherited constructor
|
|
|
|
super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_toolbar._attributes, _child || {}));
|
|
|
|
|
|
|
|
this.div = jQuery(document.createElement('div'))
|
|
|
|
.addClass('et2_toolbar ui-widget-header ui-corner-all');
|
|
|
|
|
|
|
|
// Set proper id and dom_id for the widget
|
|
|
|
this.set_id(this.id);
|
|
|
|
|
2021-10-11 10:34:19 +02:00
|
|
|
if(!this.options.preference_id){
|
|
|
|
this.options.preference_id = this.dom_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!this.options.preference_app){
|
|
|
|
this.options.preference_app = this.egw().app_name();
|
|
|
|
}
|
2020-01-24 14:08:09 +01:00
|
|
|
|
2022-04-25 17:24:29 +02:00
|
|
|
this.actionbox = jQuery(document.createElement('details'))
|
2020-01-24 14:08:09 +01:00
|
|
|
.addClass("et2_toolbar_more")
|
|
|
|
.attr('id',this.id +'-'+ 'actionbox');
|
|
|
|
|
|
|
|
this.actionlist = jQuery(document.createElement('div'))
|
|
|
|
.addClass("et2_toolbar_actionlist")
|
|
|
|
.attr('id',this.id +'-'+ 'actionlist');
|
|
|
|
|
|
|
|
this.countActions = 0;
|
|
|
|
this.dropdowns = {};
|
|
|
|
this.preference = {};
|
|
|
|
|
|
|
|
this._build_menu(et2_toolbar.default_toolbar, true);
|
2020-03-05 13:25:52 +01:00
|
|
|
}
|
2020-01-24 14:08:09 +01:00
|
|
|
|
2020-03-05 13:25:52 +01:00
|
|
|
destroy()
|
|
|
|
{
|
2020-01-24 14:08:09 +01:00
|
|
|
// Destroy widget
|
|
|
|
if(this.div && this.div.data('ui-menu')) this.menu.menu("destroy");
|
|
|
|
|
|
|
|
// Null children
|
|
|
|
|
|
|
|
// Remove
|
|
|
|
this.div.empty().remove();
|
|
|
|
this.actionbox.empty().remove();
|
|
|
|
this.actionlist.empty().remove();
|
2020-03-05 13:25:52 +01:00
|
|
|
}
|
2020-01-24 14:08:09 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fix function in order to fix toolbar preferences with the new preference structure
|
|
|
|
* @param {action object} _action
|
|
|
|
* @todo ** SEE IMPORTANT TODO **
|
|
|
|
*/
|
|
|
|
private _fix_preference(_action)
|
|
|
|
{
|
|
|
|
|
|
|
|
// ** IMPORTANT TODO: This switch case should be removed for new release **
|
|
|
|
// This is an ugly hack but we need to add this switch becuase to update and fix
|
|
|
|
// current users toolbar preferences with the new structure which is:
|
|
|
|
// - All actions should be stored in preference
|
|
|
|
// - Actions inside menu set as true
|
|
|
|
// - Actions outside menu set as false
|
|
|
|
// - if an action gets added to toolbar it would be undefined in
|
|
|
|
// the preference which we need to consider to add it to the preference
|
|
|
|
// according to its toolbarDefault option.
|
|
|
|
if (this.dom_id === 'mail-display_displayToolbar' || this.dom_id === 'mail-index_toolbar')
|
|
|
|
{
|
|
|
|
switch (_action.id)
|
|
|
|
{
|
|
|
|
// Actions newly added to mail index and display toolbar
|
|
|
|
case 'read':
|
|
|
|
case 'label1':
|
|
|
|
case 'label2':
|
|
|
|
case 'label3':
|
|
|
|
case 'label4':
|
|
|
|
case 'label5':
|
|
|
|
this.set_prefered(_action.id, !_action.toolbarDefault);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Fix structure and add the actions not the preference
|
|
|
|
// into the preference with value false, as they're already
|
|
|
|
// outside of the menu.
|
|
|
|
this.set_prefered(_action.id, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ** IMPORTANT TODO: This line needs to stay and be fixed with !toolbarDefault after the if condition
|
|
|
|
// has been removed.
|
|
|
|
this.set_prefered(_action.id, false/*!toolbarDefault*/);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Count number of actions including their children
|
|
|
|
* @param {object} actions
|
|
|
|
* @return {number} return total number of actions
|
|
|
|
*/
|
|
|
|
private _countActions(actions)
|
|
|
|
{
|
|
|
|
let totalCount = 0;
|
|
|
|
let childCounter = function (action, count)
|
|
|
|
{
|
|
|
|
let children = action.children || 0,
|
|
|
|
returnCounter = count || 0;
|
|
|
|
if (children)
|
|
|
|
{
|
|
|
|
returnCounter -= 1;
|
|
|
|
for (let nChild in children)
|
|
|
|
{
|
|
|
|
returnCounter += 1;
|
|
|
|
returnCounter = childCounter (children[nChild], returnCounter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
returnCounter = count;
|
|
|
|
}
|
|
|
|
return returnCounter;
|
|
|
|
};
|
|
|
|
for (let nAction in actions)
|
|
|
|
{
|
|
|
|
if (this.options.flat_list)
|
|
|
|
{
|
|
|
|
totalCount += childCounter(actions[nAction] ,1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
totalCount ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return totalCount;
|
2020-03-05 13:25:52 +01:00
|
|
|
}
|
2020-01-24 14:08:09 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Go through actions and build buttons for the toolbar
|
|
|
|
*
|
|
|
|
* @param {Object} actions egw-actions to build menu from
|
|
|
|
* @param {boolean} isDefault setting isDefault with true will
|
|
|
|
* avoid actions get into the preferences, for instandce, first
|
|
|
|
* time toolbar_default actions initialization.
|
|
|
|
*/
|
|
|
|
private _build_menu(actions : object, isDefault? : boolean)
|
|
|
|
{
|
|
|
|
// Clear existing
|
|
|
|
this.div.empty();
|
2022-06-07 17:18:56 +02:00
|
|
|
this.actionbox
|
2022-06-21 16:21:23 +02:00
|
|
|
.removeClass('et2_dropZone')
|
2022-06-07 17:18:56 +02:00
|
|
|
.empty();
|
|
|
|
this.actionlist
|
2022-06-21 16:21:23 +02:00
|
|
|
.removeClass('et2_dropZone')
|
2022-06-07 17:18:56 +02:00
|
|
|
.empty();
|
2020-01-24 14:08:09 +01:00
|
|
|
let admin_setting = this.options.is_admin ? '<span class="toolbar-admin-pref" title="'+egw.lang('Admin settings')+' ..."></span>': '';
|
2022-04-26 11:18:43 +02:00
|
|
|
const list_header = this.options.list_header == 'more'?true:false;
|
|
|
|
this.actionbox.append('<summary class="ui-toolbar-menulistHeader'+(!list_header?' list_header-short':' ')+'">'+(list_header?egw.lang('more')+' ...':'')+admin_setting+'</summary>');
|
2020-01-24 14:08:09 +01:00
|
|
|
this.actionbox.append('<div id="' + this.id + '-menulist' +'" class="ui-toolbar-menulist" ></div>');
|
|
|
|
let that = this;
|
|
|
|
if (this.options.is_admin)
|
|
|
|
{
|
|
|
|
this.actionbox.find('.toolbar-admin-pref').click(function(e){
|
2021-10-11 10:34:19 +02:00
|
|
|
egw.json('EGroupware\\Api\\Etemplate\\Widget\\Toolbar::ajax_get_default_prefs', [that.options.preference_app, that.options.preference_id], function(_prefs){
|
2020-01-24 14:08:09 +01:00
|
|
|
let prefs = [];
|
|
|
|
for (let p in _prefs)
|
|
|
|
{
|
|
|
|
if (_prefs[p] === false) prefs.push(p);
|
|
|
|
}
|
|
|
|
that._admin_settings_dialog.call(that, actions, prefs);
|
|
|
|
}).sendRequest(true);
|
2022-04-26 11:18:43 +02:00
|
|
|
return false;
|
2020-01-24 14:08:09 +01:00
|
|
|
});
|
2022-04-26 11:18:43 +02:00
|
|
|
this.actionbox.addClass('admin');
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
2021-10-11 10:34:19 +02:00
|
|
|
|
|
|
|
let pref = (!egwIsMobile())? egw.preference(this.options.preference_id, this.options.preference_app): undefined;
|
2020-01-24 14:08:09 +01:00
|
|
|
if (pref && !jQuery.isArray(pref)) this.preference = pref;
|
|
|
|
|
|
|
|
//Set the default actions for the first time
|
|
|
|
if (typeof pref === 'undefined' && !isDefault)
|
|
|
|
{
|
|
|
|
for (var name in actions)
|
|
|
|
{
|
|
|
|
if ((typeof actions[name].children === 'undefined' || !this.options.flat_list) && actions[name].id)
|
|
|
|
{
|
|
|
|
this.set_prefered(actions[name].id,!actions[name].toolbarDefault);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(!isDefault)
|
|
|
|
{
|
|
|
|
for (var name in actions)
|
|
|
|
{
|
|
|
|
// Check if the action is not in the preference, means it's an new added action
|
|
|
|
// therefore it needs to be added to the preference with taking its toolbarDefault
|
|
|
|
// option into account.
|
|
|
|
if ((typeof actions[name].children === 'undefined' || !this.options.flat_list)
|
|
|
|
&& typeof pref[name] === 'undefined')
|
|
|
|
{
|
|
|
|
this._fix_preference(actions[name]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let menuLen = 0;
|
|
|
|
for (let key in this.preference)
|
|
|
|
{
|
|
|
|
if (this.preference[key]) menuLen++;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.countActions = this._countActions(actions) - menuLen;
|
|
|
|
|
|
|
|
let last_group = null;
|
|
|
|
let last_group_id = null;
|
|
|
|
for(let name in actions)
|
|
|
|
{
|
|
|
|
let action = actions[name];
|
|
|
|
if (typeof action == 'string') action = {id: name, caption: action};
|
2020-03-30 22:24:54 +02:00
|
|
|
if(typeof action.group == 'undefined')
|
|
|
|
{
|
|
|
|
action.group = 'default';
|
|
|
|
}
|
2020-01-24 14:08:09 +01:00
|
|
|
|
|
|
|
// Add in divider
|
|
|
|
if(last_group_id != action.group)
|
|
|
|
{
|
|
|
|
last_group = jQuery('[data-group="' + action.group + '"]',this.actionlist);
|
|
|
|
if(last_group.length == 0)
|
|
|
|
{
|
|
|
|
jQuery('<span data-group="'+action.group+'">').appendTo(this.actionlist);
|
|
|
|
}
|
|
|
|
last_group_id = action.group;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure there's something to display
|
|
|
|
if(!action.caption && !action.icon && !action.iconUrl) continue;
|
|
|
|
|
|
|
|
if(action.children)
|
|
|
|
{
|
|
|
|
let children = {};
|
|
|
|
let add_children = function(root, children) {
|
|
|
|
for(let id in root.children)
|
|
|
|
{
|
|
|
|
let info = {
|
|
|
|
id: id || root.children[id].id,
|
2022-05-13 22:19:21 +02:00
|
|
|
value: id || root.children[id].id,
|
2020-01-24 14:08:09 +01:00
|
|
|
label: root.children[id].caption
|
|
|
|
};
|
|
|
|
let childaction = {};
|
|
|
|
if(root.children[id].iconUrl)
|
|
|
|
{
|
|
|
|
info['icon'] = root.children[id].iconUrl;
|
|
|
|
}
|
|
|
|
if(root.children[id].children)
|
|
|
|
{
|
|
|
|
add_children(root.children[id], info);
|
|
|
|
}
|
|
|
|
children[id] = info;
|
|
|
|
|
|
|
|
if (that.options.flat_list)
|
|
|
|
{
|
|
|
|
childaction = root.children[id];
|
|
|
|
if (typeof pref === 'undefined' && !isDefault)
|
|
|
|
{
|
|
|
|
if (!childaction['toolbarDefault'])
|
|
|
|
{
|
|
|
|
that.set_prefered(childaction['id'],true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
that.set_prefered(childaction['id'],false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(!isDefault)
|
|
|
|
{
|
|
|
|
if (typeof pref[childaction['id']] === 'undefined')
|
|
|
|
{
|
|
|
|
that._fix_preference(childaction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (typeof root.children[id].group !== 'undefined' &&
|
|
|
|
typeof root.group !== 'undefined')
|
|
|
|
{
|
|
|
|
childaction['group'] = root.group;
|
|
|
|
}
|
2022-05-13 22:19:21 +02:00
|
|
|
that._make_button(childaction);
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
add_children(action, children);
|
|
|
|
if (this.options.flat_list && children)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-05-13 22:19:21 +02:00
|
|
|
let dropdown = <Et2DropdownButton><unknown>loadWebComponent("et2-dropdown-button", {
|
|
|
|
id: this.id + "-" + action.id,
|
|
|
|
label: action.caption,
|
2022-06-07 17:18:56 +02:00
|
|
|
class: this.preference[action.id] ? `et2_toolbar-dropdown et2_toolbar_draggable${this.id} et2_toolbar-dropdown-menulist` : `et2_toolbar-dropdown et2_toolbar_draggable${this.id}`,
|
2022-05-18 22:39:25 +02:00
|
|
|
onchange: function(ev)
|
2022-05-13 22:19:21 +02:00
|
|
|
{
|
2022-05-18 22:39:25 +02:00
|
|
|
let action = that._actionManager.getActionById(dropdown.value);
|
2022-05-13 22:19:21 +02:00
|
|
|
dropdown.set_label(action.caption);
|
|
|
|
if(action)
|
|
|
|
{
|
|
|
|
this.value = action.id;
|
|
|
|
action.execute([]);
|
|
|
|
}
|
|
|
|
//console.debug(selected, this, action);
|
|
|
|
}.bind(action),
|
|
|
|
image: action.iconUrl || ''
|
|
|
|
}, this);
|
|
|
|
|
|
|
|
dropdown.select_options = Object.values(children);
|
2020-01-24 14:08:09 +01:00
|
|
|
|
|
|
|
//Set default selected action
|
|
|
|
if (typeof action.children !='undefined')
|
|
|
|
{
|
|
|
|
for (let child in action.children)
|
|
|
|
{
|
|
|
|
if(action.children[child].default)
|
|
|
|
{
|
2022-05-13 22:19:21 +02:00
|
|
|
dropdown.label = action.children[child].caption;
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-13 22:19:21 +02:00
|
|
|
|
|
|
|
dropdown.onclick = function(selected, dropdown)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
|
|
|
let action = that._actionManager.getActionById(this.getValue());
|
|
|
|
if(action)
|
|
|
|
{
|
|
|
|
this.value = action.id;
|
|
|
|
action.execute([]);
|
|
|
|
}
|
|
|
|
//console.debug(selected, this, action);
|
2022-05-13 22:19:21 +02:00
|
|
|
}.bind(dropdown);
|
|
|
|
jQuery(dropdown.getDOMNode()).appendTo(this.preference[action.id] ? this.actionbox.children()[1] : jQuery('[data-group=' + action.group + ']', this.actionlist));
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this._make_button(action);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ************** Drag and Drop feature for toolbar *****
|
|
|
|
this.actionlist.find('span[data-group]').sort( function (lg,g){
|
|
|
|
return +lg.getAttribute('data-group') - +g.getAttribute('data-group');
|
|
|
|
}).appendTo(this.actionlist);
|
|
|
|
|
|
|
|
this.actionlist.appendTo(this.div);
|
|
|
|
this.actionbox.appendTo(this.div);
|
|
|
|
|
2022-06-01 16:46:44 +02:00
|
|
|
let toolbar = this.actionlist.find('span[data-group]'),
|
2022-06-13 11:22:52 +02:00
|
|
|
toolbox = this.actionbox;
|
2022-06-07 17:18:56 +02:00
|
|
|
this.actionlist[0].classList.add(`et2_toolbar_dropzone_list${this.id}`);
|
|
|
|
this.actionbox[0].classList.add(`et2_toolbar_dropzone_more${this.id}`);
|
|
|
|
|
2022-06-01 16:46:44 +02:00
|
|
|
this.actions = actions;
|
2022-06-07 17:18:56 +02:00
|
|
|
let dragPosition = {x:0,y:0};
|
|
|
|
let dragTranslate = {x:0, y:0};
|
|
|
|
let draggables = this.getDOMNode().querySelectorAll(`.et2_toolbar_draggable${this.id}`);
|
|
|
|
draggables.forEach(_item => {
|
|
|
|
interact(_item).draggable({
|
|
|
|
startAxis: 'xy',
|
|
|
|
listeners: {
|
|
|
|
start: function(e)
|
|
|
|
{
|
|
|
|
dragPosition = {x:e.page.x, y:e.page.y};
|
|
|
|
e.target.setAttribute('style', `width:${e.target.clientWidth}px !important`);
|
|
|
|
e.target.style.position = 'fixed';
|
|
|
|
e.target.style.transform =
|
|
|
|
`translate(${dragPosition.x}px, ${dragPosition.y}px)`;
|
|
|
|
},
|
|
|
|
move : function(e)
|
|
|
|
{
|
|
|
|
dragTranslate.x += e.delta.x;
|
|
|
|
dragTranslate.y += e.delta.y;
|
|
|
|
e.target.style.transform =
|
|
|
|
`translate(${dragTranslate.x}px, ${dragTranslate.y}px)`;
|
|
|
|
},
|
|
|
|
end : function (e)
|
|
|
|
{
|
|
|
|
that._build_menu(that.actions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
interact(`.et2_toolbar_dropzone_list${this.id}`).unset();
|
|
|
|
interact(`.et2_toolbar_dropzone_list${this.id}`).dropzone({
|
|
|
|
checker: function (
|
|
|
|
dragEvent, // related dragmove or dragend
|
|
|
|
event, // Touch, Pointer or Mouse Event
|
|
|
|
dropped, // bool default checker result
|
|
|
|
dropzone, // dropzone Interactable
|
|
|
|
dropzoneElement, // dropzone element
|
|
|
|
draggable, // draggable Interactable
|
|
|
|
draggableElement // draggable element
|
|
|
|
) {
|
|
|
|
return dropped && !dropzoneElement.contains(draggableElement);
|
2020-01-24 14:08:09 +01:00
|
|
|
},
|
2022-06-07 17:18:56 +02:00
|
|
|
accept: `.et2_toolbar_draggable${this.id}`,
|
|
|
|
ondrop: function(e)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
2022-06-07 17:18:56 +02:00
|
|
|
that.set_prefered(e.draggable.target.id.replace(that.id + '-', ''), false);
|
2022-06-01 16:46:44 +02:00
|
|
|
that._build_menu(that.actions);
|
2022-06-07 17:18:56 +02:00
|
|
|
},
|
|
|
|
ondragenter: function(e)
|
|
|
|
{
|
2022-06-21 16:21:23 +02:00
|
|
|
e.target.classList.add('et2_dropZone');
|
2022-06-07 17:18:56 +02:00
|
|
|
},
|
|
|
|
ondragleave: function(e)
|
|
|
|
{
|
2022-06-21 16:21:23 +02:00
|
|
|
e.target.classList.remove('et2_dropZone');
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
});
|
2022-06-13 11:22:52 +02:00
|
|
|
const menulist = [`.et2_toolbar_dropzone_more${this.id}`, `#${this.id}-menulist`];
|
|
|
|
menulist.forEach(_item => {
|
|
|
|
interact(_item).unset();
|
|
|
|
interact(_item).dropzone({
|
|
|
|
checker: function (
|
|
|
|
dragEvent, // related dragmove or dragend
|
|
|
|
event, // Touch, Pointer or Mouse Event
|
|
|
|
dropped, // bool default checker result
|
|
|
|
dropzone, // dropzone Interactable
|
|
|
|
dropzoneElement, // dropzone element
|
|
|
|
draggable, // draggable Interactable
|
|
|
|
draggableElement // draggable element
|
|
|
|
) {
|
|
|
|
console.log(dragEvent);
|
|
|
|
|
|
|
|
return dropped && !dropzoneElement.contains(draggableElement);
|
|
|
|
},
|
|
|
|
accept: `.et2_toolbar_draggable${this.id}`,
|
|
|
|
ondrop: function(e)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
2022-06-13 11:22:52 +02:00
|
|
|
that.set_prefered(e.draggable.target.id.replace(that.id + '-', ''), true);
|
|
|
|
if (that.actionlist.find(`.et2_toolbar_draggable${that.id}`).length == 0)
|
|
|
|
{
|
|
|
|
that.preference = {};
|
|
|
|
egw.set_preference(that.options.preference_app,that.options.preference_id,that.preference);
|
|
|
|
}
|
|
|
|
that._build_menu(that.actions);
|
|
|
|
},
|
|
|
|
ondragenter: function(e)
|
|
|
|
{
|
2022-06-21 16:21:23 +02:00
|
|
|
e.target.classList.add('et2_dropZone');
|
2022-06-13 11:22:52 +02:00
|
|
|
},
|
|
|
|
ondragleave: function(e)
|
|
|
|
{
|
2022-06-21 16:21:23 +02:00
|
|
|
e.target.classList.remove('et2_dropZone');
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
2022-06-13 11:22:52 +02:00
|
|
|
});
|
2020-01-24 14:08:09 +01:00
|
|
|
});
|
|
|
|
|
2022-04-26 14:52:48 +02:00
|
|
|
toolbox.on('toggle', (e)=>{
|
|
|
|
const details = <HTMLDetailsElement>e.target;
|
|
|
|
if (details.open)
|
|
|
|
{
|
2022-05-18 22:39:25 +02:00
|
|
|
jQuery('html').on('click.outsideOfMenu', function(e)
|
|
|
|
{
|
|
|
|
// Clicking on dropdown button should not close the details, we'd like to see the dropdown
|
|
|
|
if(e.target instanceof Et2DropdownButton)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(e.target != details && e.target != details.firstChild)
|
|
|
|
{
|
|
|
|
details.open = false;
|
|
|
|
}
|
|
|
|
|
2022-04-26 14:52:48 +02:00
|
|
|
jQuery('html').unbind('click.outsideOfMenu');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add/Or remove an action from prefence
|
|
|
|
*
|
|
|
|
* @param {string} _action name of the action which needs to be stored in pereference
|
|
|
|
* @param {boolean} _state if set to true action will be set to actionbox, false will set it to actionlist
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
set_prefered(_action,_state)
|
|
|
|
{
|
|
|
|
this.preference[_action] = _state;
|
|
|
|
if (egwIsMobile()) return;
|
2021-10-11 10:34:19 +02:00
|
|
|
egw.set_preference(this.options.preference_app,this.options.preference_id,this.preference);
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make a button based on the given action
|
|
|
|
*
|
|
|
|
* @param {Object} action action object with attributes icon, caption, ...
|
|
|
|
*/
|
|
|
|
_make_button(action)
|
|
|
|
{
|
2022-08-03 13:41:58 +02:00
|
|
|
let self = this;
|
2020-01-24 14:08:09 +01:00
|
|
|
|
2022-08-03 13:41:58 +02:00
|
|
|
const isCheckbox = action && action.checkbox;
|
|
|
|
const isToggleSwitch = action.data?.toggle_on || action.data?.toggle_off;
|
2021-03-03 16:53:19 +01:00
|
|
|
|
2022-08-03 13:41:58 +02:00
|
|
|
const actionHandler = function(action, e)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
2022-08-01 17:59:40 +02:00
|
|
|
let actionObj = this._actionManager.getActionById(action.id);
|
|
|
|
if(actionObj)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
2022-08-01 17:59:40 +02:00
|
|
|
if (actionObj.checkbox)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
2022-08-01 17:59:40 +02:00
|
|
|
self.checkbox(actionObj.id, !actionObj.checked);
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
2022-08-01 17:59:40 +02:00
|
|
|
this.value = actionObj.id;
|
|
|
|
actionObj.data.event = e;
|
|
|
|
actionObj.execute([]);
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
2022-08-01 17:59:40 +02:00
|
|
|
}.bind(this, action);
|
2020-01-24 14:08:09 +01:00
|
|
|
|
2022-08-03 13:41:58 +02:00
|
|
|
let widget = null;
|
|
|
|
|
|
|
|
if (isToggleSwitch)
|
|
|
|
{
|
|
|
|
widget = <Et2Checkbox>loadWebComponent('et2-switch', {
|
|
|
|
id: `${this.id}-${action.id}`,
|
|
|
|
toggleOn: action.data.toggle_on,
|
2022-08-03 17:25:17 +02:00
|
|
|
toggleOff: action.data.toggle_off,
|
|
|
|
class: `et2_toolbar_draggable${this.id}`,
|
2022-08-03 13:41:58 +02:00
|
|
|
}, this);
|
2022-08-05 13:03:59 +02:00
|
|
|
widget.style.backgroundImage = `url(${action.iconUrl})`;
|
2022-08-03 13:41:58 +02:00
|
|
|
widget.value = action.checked;
|
|
|
|
action.data.widget = widget;
|
|
|
|
widget.onchange = actionHandler;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
widget = <Et2Button>loadWebComponent("et2-button", {
|
|
|
|
id: `${this.id}-${action.id}`,
|
|
|
|
image: action.iconUrl || '',
|
|
|
|
slot: "buttons",
|
|
|
|
class: `et2_toolbar_draggable${this.id}`,
|
|
|
|
}, this);
|
|
|
|
if (isCheckbox)
|
|
|
|
{
|
|
|
|
if (this.checkbox(action.id)) widget.classList.add('toolbar_toggled'+ (typeof action.toggledClass != 'undefined'?" "+action.toggledClass:''));
|
|
|
|
}
|
|
|
|
widget.onclick = actionHandler;
|
|
|
|
}
|
|
|
|
jQuery(widget.getDOMNode()).appendTo(this.preference[action.id]?this.actionbox.children()[1]:jQuery('[data-group='+action.group+']',this.actionlist));
|
|
|
|
|
|
|
|
if (action.caption)
|
|
|
|
{
|
2022-08-18 11:10:39 +02:00
|
|
|
widget.statustext = action.caption;
|
2022-08-03 13:41:58 +02:00
|
|
|
if ((this.countActions <= parseInt(this.view_range) ||
|
|
|
|
this.preference[action.id] || !action.iconUrl) &&
|
|
|
|
!(isCheckbox && isToggleSwitch)) // no caption for slideswitch checkboxes
|
|
|
|
{
|
|
|
|
widget.classList.add(action.iconUrl?'et2_toolbar_hasCaption':'et2_toolbar_onlyCaption');
|
2022-08-05 16:25:39 +02:00
|
|
|
widget.label = action.caption;
|
2022-08-03 13:41:58 +02:00
|
|
|
}
|
|
|
|
}
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Link the actions to the DOM nodes / widget bits.
|
|
|
|
*
|
|
|
|
* @param {Object} actions egw-actions to build menu from
|
|
|
|
*/
|
|
|
|
_link_actions(actions)
|
|
|
|
{
|
|
|
|
this._build_menu(actions);
|
|
|
|
|
|
|
|
let self = this;
|
2020-05-29 19:21:17 +02:00
|
|
|
let gom = egw_getObjectManager(this.egw().app_name(),true,1);
|
2020-01-24 14:08:09 +01:00
|
|
|
if(this._objectManager == null)
|
|
|
|
{
|
|
|
|
this._objectManager = gom.addObject(
|
|
|
|
new egwActionObjectManager(this.id, this._actionManager));
|
|
|
|
|
|
|
|
this._objectManager.handleKeyPress = function(_keyCode, _shift, _ctrl, _alt) {
|
|
|
|
for(let i = 0; i < self._actionManager.children.length; i++)
|
|
|
|
{
|
|
|
|
let action = self._actionManager.children[i];
|
|
|
|
if(typeof action.shortcut === 'object' &&
|
|
|
|
action.shortcut &&
|
|
|
|
_keyCode == action.shortcut.keyCode &&
|
|
|
|
_ctrl == action.shortcut.ctrl &&
|
|
|
|
_alt == action.shortcut.alt &&
|
|
|
|
_shift == action.shortcut.shift
|
|
|
|
)
|
|
|
|
{
|
|
|
|
self.value = action.id;
|
|
|
|
action.execute([]);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return egwActionObject.prototype.handleKeyPress.call(this, _keyCode,_shift,_ctrl,_alt);
|
2020-02-27 19:54:55 +01:00
|
|
|
};
|
2020-01-24 14:08:09 +01:00
|
|
|
this._objectManager.parent.updateFocusedChild(this._objectManager, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set/Get the checkbox toolbar action
|
|
|
|
*
|
|
|
|
* @param {string} _action action name of the selected toolbar
|
|
|
|
* @param {boolean} _value value that needs to be set for the action true|false
|
|
|
|
* - if no value means checkbox value returns the current value
|
|
|
|
*
|
|
|
|
* @returns {boolean} returns boolean result of get checkbox value
|
|
|
|
* or returns undefined as Set result or failure
|
|
|
|
*/
|
|
|
|
checkbox(_action, _value?)
|
|
|
|
{
|
|
|
|
if (!_action || typeof this._actionManager == 'undefined') return undefined;
|
|
|
|
let action_event = this._actionManager.getActionById(_action);
|
|
|
|
|
|
|
|
if (action_event && typeof _value !='undefined')
|
|
|
|
{
|
|
|
|
action_event.set_checked(_value);
|
2022-08-01 17:59:40 +02:00
|
|
|
var btn = jQuery('#'+this.dom_id+'-'+_action);
|
2020-01-24 14:08:09 +01:00
|
|
|
if(action_event.data && action_event.data.widget)
|
|
|
|
{
|
|
|
|
action_event.data.widget.set_value(_value);
|
|
|
|
}
|
|
|
|
else if (btn.length > 0)
|
|
|
|
{
|
|
|
|
btn.toggleClass('toolbar_toggled'+ (typeof action_event.data.toggledClass != 'undefined'?" "+action_event.data.toggledClass:''), _value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (action_event)
|
|
|
|
{
|
|
|
|
return action_event.checked;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getDOMNode()
|
|
|
|
{
|
|
|
|
return this.div[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* getValue has to return the value of the input widget
|
|
|
|
*/
|
|
|
|
getValue()
|
|
|
|
{
|
|
|
|
return this.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is dirty returns true if the value of the widget has changed since it
|
2020-06-29 21:23:17 +02:00
|
|
|
* was loaded. We don't consider toolbars as dirtyable
|
2020-01-24 14:08:09 +01:00
|
|
|
*/
|
|
|
|
isDirty()
|
|
|
|
{
|
2020-06-29 21:23:17 +02:00
|
|
|
return false;
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
|
2020-07-02 19:19:11 +02:00
|
|
|
/**
|
|
|
|
* Causes the dirty flag to be reseted.
|
|
|
|
*/
|
|
|
|
resetDirty()
|
|
|
|
{
|
|
|
|
this.value = null;
|
|
|
|
}
|
2020-01-24 14:08:09 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks the data to see if it is valid, as far as the client side can tell.
|
|
|
|
* Return true if it's not possible to tell on the client side, because the server
|
|
|
|
* will have the chance to validate also.
|
|
|
|
*
|
|
|
|
* The messages array is to be populated with everything wrong with the data,
|
|
|
|
* so don't stop checking after the first problem unless it really makes sense
|
|
|
|
* to ignore other problems.
|
|
|
|
*
|
|
|
|
* @param {String[]} messages List of messages explaining the failure(s).
|
|
|
|
* messages should be fairly short, and already translated.
|
|
|
|
*
|
|
|
|
* @return {boolean} True if the value is valid (enough), false to fail
|
|
|
|
*/
|
|
|
|
isValid(messages)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attach the container node of the widget to DOM-Tree
|
|
|
|
* @returns {Boolean}
|
|
|
|
*/
|
|
|
|
doLoadingFinished()
|
|
|
|
{
|
|
|
|
super.doLoadingFinished();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds dialog for possible admin settings (e.g. default actions pref)
|
|
|
|
*
|
|
|
|
* @param {type} _actions
|
|
|
|
* @param {object} _default_prefs
|
|
|
|
*/
|
|
|
|
private _admin_settings_dialog(_actions, _default_prefs)
|
|
|
|
{
|
|
|
|
let buttons = [
|
2022-03-30 21:24:52 +02:00
|
|
|
{label: egw.lang("Save"), id: "save"},
|
|
|
|
{label: egw.lang("Close"), id: "close"}
|
2020-01-24 14:08:09 +01:00
|
|
|
];
|
|
|
|
let self = this;
|
|
|
|
let sel_options = {actions:[]};
|
|
|
|
let content = {actions:[], reset:false};
|
|
|
|
for (let key in _actions)
|
|
|
|
{
|
|
|
|
if (_actions[key]['children'] && this.options.flat_list)
|
|
|
|
{
|
|
|
|
for (let child in _actions[key]['children'])
|
|
|
|
{
|
|
|
|
sel_options.actions.push({
|
|
|
|
id:child,
|
|
|
|
value: child,
|
|
|
|
label: _actions[key]['children'][child]['caption'],
|
2021-10-11 10:34:19 +02:00
|
|
|
app: self.options.preference_app,
|
2020-01-24 14:08:09 +01:00
|
|
|
icon: _actions[key]['children'][child]['iconUrl']
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sel_options.actions.push({
|
2022-03-30 21:24:52 +02:00
|
|
|
id: key,
|
2020-01-24 14:08:09 +01:00
|
|
|
value: key,
|
|
|
|
label: _actions[key]['caption'],
|
2021-10-11 10:34:19 +02:00
|
|
|
app: self.options.preference_app,
|
2020-01-24 14:08:09 +01:00
|
|
|
icon: _actions[key]['iconUrl']
|
|
|
|
});
|
|
|
|
}
|
2022-03-30 21:24:52 +02:00
|
|
|
if((!_default_prefs || _default_prefs.length == 0) && _actions[key]['toolbarDefault'])
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
2022-03-30 21:24:52 +02:00
|
|
|
content.actions.push(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(_default_prefs && _default_prefs.length > 0)
|
|
|
|
{
|
|
|
|
content.actions = _default_prefs;
|
|
|
|
}
|
|
|
|
let dialog = new Et2Dialog(this.egw());
|
|
|
|
dialog.transformAttributes({
|
2020-01-24 14:08:09 +01:00
|
|
|
callback: function(_button_id, _value)
|
|
|
|
{
|
2022-03-30 21:24:52 +02:00
|
|
|
if(_button_id == 'save' && _value)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
2022-03-30 21:24:52 +02:00
|
|
|
if(_value.actions)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
|
|
|
let pref = jQuery.extend({}, self.preference);
|
2022-03-30 21:24:52 +02:00
|
|
|
for(let i in pref)
|
2020-01-24 14:08:09 +01:00
|
|
|
{
|
|
|
|
pref[i] = true;
|
2022-03-30 21:24:52 +02:00
|
|
|
if(_value.actions.includes(i))
|
|
|
|
{
|
|
|
|
pref[i] = false;
|
|
|
|
}
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
_value.actions = pref;
|
|
|
|
}
|
|
|
|
egw.json('EGroupware\\Api\\Etemplate\\Widget\\Toolbar::ajax_setAdminSettings',
|
2022-03-30 21:24:52 +02:00
|
|
|
[_value, self.options.preference_id, self.options.preference_app], function(_result)
|
|
|
|
{
|
2020-01-24 14:08:09 +01:00
|
|
|
egw.message(_result);
|
|
|
|
}).sendRequest(true);
|
|
|
|
}
|
|
|
|
},
|
2021-10-11 10:34:19 +02:00
|
|
|
title: egw.lang('admin settings for %1', this.options.preference_id),
|
2020-01-24 14:08:09 +01:00
|
|
|
buttons: buttons,
|
|
|
|
minWidth: 600,
|
|
|
|
minHeight: 300,
|
2022-03-30 21:24:52 +02:00
|
|
|
value: {content: content, sel_options: sel_options},
|
|
|
|
template: egw.webserverUrl + '/api/templates/default/toolbarAdminSettings.xet?1',
|
2020-01-24 14:08:09 +01:00
|
|
|
resizable: false
|
2022-03-30 21:24:52 +02:00
|
|
|
}
|
|
|
|
);
|
|
|
|
document.body.appendChild(dialog);
|
2020-01-24 14:08:09 +01:00
|
|
|
}
|
|
|
|
}
|
2022-05-26 17:28:58 +02:00
|
|
|
et2_register_widget(et2_toolbar, ["toolbar"]);
|