forked from extern/egroupware
Compare commits
11 Commits
master
...
jquery-les
Author | SHA1 | Date | |
---|---|---|---|
|
5ce0ce73de | ||
|
19cf0faf60 | ||
|
8ca0d0c197 | ||
|
19135ab904 | ||
|
41ccb921be | ||
|
76d1d570f6 | ||
|
c56812a42f | ||
|
8c8d8c2de9 | ||
|
24d5f01719 | ||
|
90b737bc18 | ||
|
063dff4c8f |
@ -19,7 +19,7 @@
|
|||||||
import {egwAction,egwActionImplementation} from "./egw_action.js";
|
import {egwAction,egwActionImplementation} from "./egw_action.js";
|
||||||
import {getPopupImplementation} from "./egw_action_popup.js";
|
import {getPopupImplementation} from "./egw_action_popup.js";
|
||||||
import {EGW_AI_DRAG_OUT, EGW_AI_DRAG_OVER, EGW_AO_EXEC_THIS} from "./egw_action_constants.js";
|
import {EGW_AI_DRAG_OUT, EGW_AI_DRAG_OVER, EGW_AO_EXEC_THIS} from "./egw_action_constants.js";
|
||||||
|
import 'egw-touch-dnd/touch-dnd.js';
|
||||||
/**
|
/**
|
||||||
* Register the drag and drop handlers
|
* Register the drag and drop handlers
|
||||||
*/
|
*/
|
||||||
@ -317,12 +317,9 @@ export function egwDragActionImplementation()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
jQuery(node).draggable(
|
let $draggable = jQuery(node).draggable({
|
||||||
{
|
delay: 250,
|
||||||
"distance": 20,
|
clone: function(e) {
|
||||||
"cursor": "move",
|
|
||||||
"cursorAt": { top: -12, left: -12 },
|
|
||||||
"helper": function(e) {
|
|
||||||
// The helper function is called before the start function
|
// The helper function is called before the start function
|
||||||
// is evoked. Call the given callback function. The callback
|
// is evoked. Call the given callback function. The callback
|
||||||
// function will gather the selected elements and action links
|
// function will gather the selected elements and action links
|
||||||
@ -351,9 +348,6 @@ export function egwDragActionImplementation()
|
|||||||
// Return an empty div if the helper dom node is not set
|
// Return an empty div if the helper dom node is not set
|
||||||
return ai.defaultDDHelper(ai.selected);//jQuery(document.createElement("div")).addClass('et2_egw_action_ddHelper');
|
return ai.defaultDDHelper(ai.selected);//jQuery(document.createElement("div")).addClass('et2_egw_action_ddHelper');
|
||||||
},
|
},
|
||||||
"start": function(e) {
|
|
||||||
return ai.helper != null;
|
|
||||||
},
|
|
||||||
revert: function(valid)
|
revert: function(valid)
|
||||||
{
|
{
|
||||||
var dTarget = this;
|
var dTarget = this;
|
||||||
@ -388,14 +382,11 @@ export function egwDragActionImplementation()
|
|||||||
},
|
},
|
||||||
// Solves problem with scroll position changing in the grid
|
// Solves problem with scroll position changing in the grid
|
||||||
// component
|
// component
|
||||||
"refreshPositions": true,
|
// "refreshPositions": true,
|
||||||
"scroll": false,
|
});
|
||||||
//"containment": "document",
|
$draggable.on('draggable:start', function(e) {
|
||||||
"iframeFix": true,
|
return ai.helper != null;
|
||||||
"delay": 300
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -550,19 +541,18 @@ export function egwDropActionImplementation()
|
|||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
{
|
{
|
||||||
jQuery(node).droppable(
|
let $droppable = jQuery(node).droppable({
|
||||||
{
|
accept: function(_draggable) {
|
||||||
"accept": function(_draggable) {
|
|
||||||
if (typeof _draggable.data("ddTypes") != "undefined")
|
if (typeof _draggable.data("ddTypes") != "undefined")
|
||||||
{
|
{
|
||||||
var accepted = self._fetchAccepted(
|
let accepted = self._fetchAccepted(
|
||||||
_callback.call(_context, "links", self, EGW_AO_EXEC_THIS));
|
_callback.call(_context, "links", self, EGW_AO_EXEC_THIS));
|
||||||
|
|
||||||
// Check whether all drag types of the selected objects
|
// Check whether all drag types of the selected objects
|
||||||
// are accepted
|
// are accepted
|
||||||
var ddTypes = _draggable.data("ddTypes");
|
let ddTypes = _draggable.data("ddTypes");
|
||||||
|
|
||||||
for (var i = 0; i < ddTypes.length; i++)
|
for (let i = 0; i < ddTypes.length; i++)
|
||||||
{
|
{
|
||||||
if (accepted.indexOf(ddTypes[i]) != -1)
|
if (accepted.indexOf(ddTypes[i]) != -1)
|
||||||
{
|
{
|
||||||
@ -573,21 +563,23 @@ export function egwDropActionImplementation()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"drop": function(event, ui) {
|
hoverClass: "drop-hover",
|
||||||
var draggable = ui.draggable;
|
});
|
||||||
var ddTypes = draggable.data("ddTypes");
|
$droppable.on('droppable:drop', function(event, ui) {
|
||||||
var selected = draggable.data("selected");
|
let draggable = ui.item;
|
||||||
|
let ddTypes = draggable.data("ddTypes");
|
||||||
|
let selected = draggable.data("selected");
|
||||||
|
|
||||||
var links = _callback.call(_context, "links", self, EGW_AO_EXEC_THIS);
|
let links = _callback.call(_context, "links", self, EGW_AO_EXEC_THIS);
|
||||||
|
|
||||||
// Disable all links which only accept types which are not
|
// Disable all links which only accept types which are not
|
||||||
// inside ddTypes
|
// inside ddTypes
|
||||||
for (var k in links)
|
for (let k in links)
|
||||||
{
|
{
|
||||||
var accepted = links[k].actionObj.acceptedTypes;
|
let accepted = links[k].actionObj.acceptedTypes;
|
||||||
|
|
||||||
var enabled = false;
|
let enabled = false;
|
||||||
for (var i = 0; i < ddTypes.length; i++)
|
for (let i = 0; i < ddTypes.length; i++)
|
||||||
{
|
{
|
||||||
if (accepted.indexOf(ddTypes[i]) != -1)
|
if (accepted.indexOf(ddTypes[i]) != -1)
|
||||||
{
|
{
|
||||||
@ -608,9 +600,9 @@ export function egwDropActionImplementation()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check whether there is only one link
|
// Check whether there is only one link
|
||||||
var cnt = 0;
|
let cnt = 0;
|
||||||
var lnk = null;
|
let lnk = null;
|
||||||
for (var k in links)
|
for (let k in links)
|
||||||
{
|
{
|
||||||
if (links[k].enabled && links[k].visible)
|
if (links[k].enabled && links[k].visible)
|
||||||
{
|
{
|
||||||
@ -638,8 +630,8 @@ export function egwDropActionImplementation()
|
|||||||
// This is possible as the popup and the popup action
|
// This is possible as the popup and the popup action
|
||||||
// object and the drop action object share same
|
// object and the drop action object share same
|
||||||
// set of properties.
|
// set of properties.
|
||||||
var popup = getPopupImplementation();
|
let popup = getPopupImplementation();
|
||||||
var pos = popup._getPageXY(event.originalEvent);
|
let pos = popup._getPageXY(event);
|
||||||
|
|
||||||
// Don't add paste actions, this is a drop
|
// Don't add paste actions, this is a drop
|
||||||
popup.auto_paste = false;
|
popup.auto_paste = false;
|
||||||
@ -653,21 +645,14 @@ export function egwDropActionImplementation()
|
|||||||
}
|
}
|
||||||
// Set cursor back to auto. Seems FF can't handle cursor reversion
|
// Set cursor back to auto. Seems FF can't handle cursor reversion
|
||||||
jQuery('body').css({cursor:'auto'});
|
jQuery('body').css({cursor:'auto'});
|
||||||
|
|
||||||
_aoi.triggerEvent(EGW_AI_DRAG_OUT,{event: event,ui:ui});
|
_aoi.triggerEvent(EGW_AI_DRAG_OUT,{event: event,ui:ui});
|
||||||
},
|
});
|
||||||
"over": function(event, ui) {
|
$droppable.on('droppable:out', function(event,ui) {
|
||||||
|
_aoi.triggerEvent(EGW_AI_DRAG_OUT,{event: event,ui:ui});
|
||||||
|
});
|
||||||
|
$droppable.on('droppable:over', function(event, ui) {
|
||||||
_aoi.triggerEvent(EGW_AI_DRAG_OVER,{event: event,ui:ui});
|
_aoi.triggerEvent(EGW_AI_DRAG_OVER,{event: event,ui:ui});
|
||||||
},
|
});
|
||||||
"out": function(event,ui) {
|
|
||||||
_aoi.triggerEvent(EGW_AI_DRAG_OUT,{event: event,ui:ui});
|
|
||||||
},
|
|
||||||
"tolerance": "pointer",
|
|
||||||
hoverClass: "drop-hover",
|
|
||||||
// Greedy is for nested droppables - children consume the action
|
|
||||||
greedy: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,12 @@
|
|||||||
/*egw:uses
|
/*egw:uses
|
||||||
vendor.bower-asset.jquery.dist.jquery;
|
vendor.bower-asset.jquery.dist.jquery;
|
||||||
egw_menu;
|
egw_menu;
|
||||||
/api/js/jquery/jquery-tap-and-hold/jquery.tapandhold.js;
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {egwAction, egwActionImplementation, egwActionObject} from './egw_action.js';
|
import {egwAction, egwActionImplementation, egwActionObject} from './egw_action.js';
|
||||||
import {egwFnct} from './egw_action_common.js';
|
import {egwFnct} from './egw_action_common.js';
|
||||||
import {egwMenu, _egw_active_menu} from "./egw_menu.js";
|
import {egwMenu, _egw_active_menu} from "./egw_menu.js";
|
||||||
import {EGW_KEY_ENTER, EGW_KEY_MENU} from "./egw_action_constants.js";
|
import {EGW_KEY_ENTER, EGW_KEY_MENU} from "./egw_action_constants.js";
|
||||||
import "../jquery/jquery-tap-and-hold/jquery.tapandhold.js";
|
|
||||||
|
|
||||||
if (typeof window._egwActionClasses == "undefined")
|
if (typeof window._egwActionClasses == "undefined")
|
||||||
window._egwActionClasses = {};
|
window._egwActionClasses = {};
|
||||||
@ -280,7 +278,39 @@ export function egwPopupActionImplementation()
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
ai._handleTapHold = function (_node, _callback)
|
||||||
|
{
|
||||||
|
let holdTimer = 600;
|
||||||
|
let maxDistanceAllowed = 40;
|
||||||
|
let tapTimeout = null;
|
||||||
|
let startx = 0;
|
||||||
|
let starty = 0;
|
||||||
|
|
||||||
|
//TODO (todo-jquery): ATM we need to convert the possible given jquery dom node object into DOM Element, this
|
||||||
|
// should be no longer neccessary after removing jQuery nodes.
|
||||||
|
if (_node instanceof jQuery)
|
||||||
|
{
|
||||||
|
_node = _node[0];
|
||||||
|
}
|
||||||
|
_node.addEventListener('touchstart', function(e){
|
||||||
|
|
||||||
|
tapTimeout = setTimeout(function(event){
|
||||||
|
_callback(e);
|
||||||
|
}, holdTimer);
|
||||||
|
startx = (e.changedTouches) ? e.changedTouches[0].pageX: e.pageX;
|
||||||
|
starty = (e.changedTouches) ? e.changedTouches[0].pageY: e.pageY;
|
||||||
|
});
|
||||||
|
_node.addEventListener('touchend', function(){
|
||||||
|
clearTimeout(tapTimeout);
|
||||||
|
});
|
||||||
|
_node.addEventListener('touchmove', function(_event){
|
||||||
|
if (tapTimeout == null) return;
|
||||||
|
let e = _event.originalEvent;
|
||||||
|
let x = (e.changedTouches) ? e.changedTouches[0].pageX: e.pageX;
|
||||||
|
let y = (e.changedTouches) ? e.changedTouches[0].pageY: e.pageY;
|
||||||
|
if (Math.sqrt((x-startx)*(x-startx) + (y-starty)+(y-starty)) > maxDistanceAllowed) clearTimeout(tapTimeout);
|
||||||
|
});
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Registers the handler for the context menu
|
* Registers the handler for the context menu
|
||||||
*
|
*
|
||||||
@ -292,14 +322,6 @@ export function egwPopupActionImplementation()
|
|||||||
ai._registerContext = function(_node, _callback, _context)
|
ai._registerContext = function(_node, _callback, _context)
|
||||||
{
|
{
|
||||||
var contextHandler = function(e) {
|
var contextHandler = function(e) {
|
||||||
if(egwIsMobile())
|
|
||||||
{
|
|
||||||
if (e.originalEvent.which == 3)
|
|
||||||
{
|
|
||||||
// Enable onhold trigger till we define a better handler for tree contextmenu
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Obtain the event object
|
//Obtain the event object
|
||||||
if (!e)
|
if (!e)
|
||||||
@ -327,7 +349,7 @@ export function egwPopupActionImplementation()
|
|||||||
};
|
};
|
||||||
// Safari still needs the taphold to trigger contextmenu
|
// Safari still needs the taphold to trigger contextmenu
|
||||||
// Chrome has default event on touch and hold which acts like right click
|
// Chrome has default event on touch and hold which acts like right click
|
||||||
jQuery(_node).bind('taphold', contextHandler);
|
this._handleTapHold(_node, contextHandler);
|
||||||
jQuery(_node).on('contextmenu', contextHandler);
|
jQuery(_node).on('contextmenu', contextHandler);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2078,30 +2078,19 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
|
|||||||
self.selectPopup = null;
|
self.selectPopup = null;
|
||||||
};
|
};
|
||||||
const $select = jQuery(select.getDOMNode());
|
const $select = jQuery(select.getDOMNode());
|
||||||
$select.find('.ui-multiselect-checkboxes').sortable({
|
|
||||||
placeholder:'ui-fav-sortable-placeholder',
|
//todo (todo-jquery-ui): fix the sortable import statement
|
||||||
items:'li[class^="selcolumn_sortable_col"]',
|
import('../../../node_modules/sortablejs/Sortable.min.js').then(function(){
|
||||||
cancel: 'li[class^="selcolumn_sortable_#"]',
|
let sortablejs = Sortable.create(select.getDOMNode().getElementsByClassName('ui-multiselect-checkboxes')[0], {
|
||||||
cursor: "move",
|
ghostClass: 'ui-fav-sortable-placeholder',
|
||||||
tolerance: "pointer",
|
draggable: 'li[class^="selcolumn_sortable_col"]',
|
||||||
axis: 'y',
|
filter: 'li[class^="selcolumn_sortable_#"]',
|
||||||
containment: "parent",
|
direction: 'vertical',
|
||||||
delay: 250, //(millisecond) delay before the sorting should start
|
delay: 25,
|
||||||
beforeStop: function(event, ui) {
|
|
||||||
jQuery('li[class^="selcolumn_sortable_#"]', this).css({
|
|
||||||
opacity: 1
|
|
||||||
});
|
|
||||||
},
|
|
||||||
start: function(event, ui){
|
|
||||||
jQuery('li[class^="selcolumn_sortable_#"]', this).css({
|
|
||||||
opacity: 0.5
|
|
||||||
});
|
|
||||||
},
|
|
||||||
sort: function (event, ui)
|
|
||||||
{
|
|
||||||
jQuery( this ).sortable("refreshPositions" );
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
$select.disableSelection();
|
$select.disableSelection();
|
||||||
$select.find('li[class^="selcolumn_sortable_"]').each(function(i,v){
|
$select.find('li[class^="selcolumn_sortable_"]').each(function(i,v){
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -177,21 +177,25 @@ export class et2_favorites extends et2_dropdown_button implements et2_INextmatch
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Add Sortable handler to nm fav. menu
|
//todo (@todo-jquery-ui): replace the import statement
|
||||||
jQuery(this.menu).sortable({
|
/**
|
||||||
|
* todo (@todo-jquery-ui): the sorting does not work at the moment becuase of jquery-ui menu being used in order to create dropdown
|
||||||
items:'li:not([data-id$="add"])',
|
* buttons menu. Once we replace the et2_widget_dropdown_button with web component this should be adapted
|
||||||
placeholder:'ui-fav-sortable-placeholder',
|
* and working again.
|
||||||
delay: 250, //(millisecond) delay before the sorting should start
|
**/
|
||||||
update: function ()
|
import('../../../node_modules/sortablejs/Sortable.min.js').then(function(){
|
||||||
{
|
let sortablejs = Sortable.create(this.menu[0], {
|
||||||
self.favSortedList = jQuery(this).sortable('toArray', {attribute:'data-id'});
|
ghostClass: 'ui-fav-sortable-placeholder',
|
||||||
|
draggable: 'li:not([data-id$="add"])',
|
||||||
self.egw().set_preference(self.options.app,'fav_sort_pref',self.favSortedList);
|
delay: 25,
|
||||||
|
dataIdAttr:'data-id',
|
||||||
|
onSort: function(event){
|
||||||
|
self.favSortedList = sortablejs.toArray();
|
||||||
|
self.egw.set_preference(self.options.app,'fav_sort_pref', self.favSortedList );
|
||||||
sideBoxDOMNodeSort(self.favSortedList);
|
sideBoxDOMNodeSort(self.favSortedList);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
// Add a listener on the delete to remove
|
// Add a listener on the delete to remove
|
||||||
this.menu.on("click","div.ui-icon-trash", app[self.options.app], function() {
|
this.menu.on("click","div.ui-icon-trash", app[self.options.app], function() {
|
||||||
|
@ -117,6 +117,7 @@ export class et2_grid extends et2_DOMWidget implements et2_IDetachedDOM, et2_IAl
|
|||||||
private wrapper = null;
|
private wrapper = null;
|
||||||
private lastRowNode: null;
|
private lastRowNode: null;
|
||||||
|
|
||||||
|
private sortablejs : Sortable = null;
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
@ -943,56 +944,54 @@ export class et2_grid extends et2_DOMWidget implements et2_IDetachedDOM, et2_IAl
|
|||||||
*/
|
*/
|
||||||
set_sortable(sortable: boolean | Function)
|
set_sortable(sortable: boolean | Function)
|
||||||
{
|
{
|
||||||
const $node = jQuery(this.getDOMNode());
|
const self = this;
|
||||||
if(!sortable)
|
let tbody = this.getDOMNode().getElementsByTagName('tbody')[0];
|
||||||
|
|
||||||
|
if(!sortable && this.sortablejs)
|
||||||
{
|
{
|
||||||
$node.sortable("destroy");
|
this.sortablejs.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure rows have IDs, so sortable has something to return
|
for (let i =0; i < tbody.children.length; i++)
|
||||||
jQuery('tr', this.tbody).each(function(index) {
|
{
|
||||||
const $this = jQuery(this);
|
if (!tbody.children[i].classList.contains('th') && !tbody.children[i].id)
|
||||||
|
{
|
||||||
|
tbody.children[i].setAttribute('id', i.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Header does not participate in sorting
|
|
||||||
if($this.hasClass('th')) return;
|
|
||||||
|
|
||||||
// If row doesn't have an ID, assign the index as ID
|
//todo (todo-jquery-ui): fix the sortable import statement
|
||||||
if(!$this.attr("id")) $this.attr("id", index);
|
import('../../../node_modules/sortablejs/Sortable.min.js').then(function(){
|
||||||
});
|
this.sortablejs = new Sortable(tbody,{
|
||||||
|
group: this.options.sortable_connectWith,
|
||||||
const self = this;
|
draggable: "tr:not(.th)",
|
||||||
|
filter: this.options.sortable_cancel,
|
||||||
// Set up sortable
|
ghostClass: this.options.sortable_placeholder,
|
||||||
$node.sortable({
|
dataIdAttr: 'id',
|
||||||
// Header does not participate in sorting
|
onAdd:function (event) {
|
||||||
items: "> tbody > tr:not(.th)",
|
if (typeof self.options.sortable_recieveCallback == 'function') {
|
||||||
distance: 15,
|
self.options.sortable_recieveCallback.call(self, event, this, self.id);
|
||||||
cancel: this.options.sortable_cancel,
|
}
|
||||||
placeholder: this.options.sortable_placeholder,
|
},
|
||||||
containment: this.options.sortable_containment,
|
onStart: function (event, ui) {
|
||||||
connectWith: this.options.sortable_connectWith,
|
if (typeof self.options.sortable_startCallback == 'function') {
|
||||||
update: function(event, ui) {
|
self.options.sortable_startCallback.call(self, event, this, self.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSort: function (event) {
|
||||||
self.egw().json(sortable,[
|
self.egw().json(sortable,[
|
||||||
self.getInstanceManager().etemplate_exec_id,
|
self.getInstanceManager().etemplate_exec_id,
|
||||||
$node.sortable("toArray"),
|
self.sortablejs.toArray(),
|
||||||
self.id],
|
self.id],
|
||||||
null,
|
null,
|
||||||
self,
|
self,
|
||||||
true
|
true
|
||||||
).sendRequest();
|
).sendRequest();
|
||||||
},
|
},
|
||||||
receive: function (event, ui) {
|
|
||||||
if (typeof self.sortable_recieveCallback == 'function') {
|
|
||||||
self.sortable_recieveCallback.call(self, event, ui, self.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
start: function (event, ui) {
|
|
||||||
if (typeof self.options.sortable_startCallback == 'function') {
|
|
||||||
self.options.sortable_startCallback.call(self, event, ui, self.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,7 +25,7 @@ import './fw_browser.js';
|
|||||||
import './fw_ui.js';
|
import './fw_ui.js';
|
||||||
import './fw_classes.js';
|
import './fw_classes.js';
|
||||||
import '../jsapi/egw_inheritance.js';
|
import '../jsapi/egw_inheritance.js';
|
||||||
|
import "sortablejs/Sortable.min.js";
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {DOMWindow} window
|
* @param {DOMWindow} window
|
||||||
@ -48,31 +48,16 @@ import '../jsapi/egw_inheritance.js';
|
|||||||
init: function()
|
init: function()
|
||||||
{
|
{
|
||||||
this._super.apply(this,arguments);
|
this._super.apply(this,arguments);
|
||||||
|
let self = this;
|
||||||
this.setBottomLine(this.parent.entries);
|
this.setBottomLine(this.parent.entries);
|
||||||
//Make the base Div sortable. Set all elements with the style "egw_fw_ui_sidemenu_entry_header"
|
|
||||||
//as handle
|
this.elemDiv.classList.add('ui-sortable')
|
||||||
if(jQuery(this.elemDiv).data('uiSortable'))
|
Sortable.create(this.elemDiv,{
|
||||||
{
|
onSort: function (evt) {
|
||||||
jQuery(this.elemDiv).sortable("destroy");
|
self.parent.isDraged = true;
|
||||||
}
|
self.parent.refreshSort();
|
||||||
jQuery(this.elemDiv).sortable({
|
|
||||||
handle: ".egw_fw_ui_sidemenu_entry_header",
|
|
||||||
distance: 15,
|
|
||||||
start: function(event, ui)
|
|
||||||
{
|
|
||||||
var parent = ui.item.context._parent;
|
|
||||||
parent.isDraged = true;
|
|
||||||
parent.parent.startDrag.call(parent.parent);
|
|
||||||
},
|
},
|
||||||
stop: function(event, ui)
|
direction: 'vertical'
|
||||||
{
|
|
||||||
var parent = ui.item.context._parent;
|
|
||||||
parent.parent.stopDrag.call(parent.parent);
|
|
||||||
parent.parent.refreshSort.call(parent.parent);
|
|
||||||
},
|
|
||||||
opacity: 0.7,
|
|
||||||
axis: 'y'
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -107,31 +92,6 @@ import '../jsapi/egw_inheritance.js';
|
|||||||
this._super.apply(this,arguments);
|
this._super.apply(this,arguments);
|
||||||
this.sortCallback = _sortCallback;
|
this.sortCallback = _sortCallback;
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @returns {undefined}
|
|
||||||
*/
|
|
||||||
startDrag: function()
|
|
||||||
{
|
|
||||||
if (this.activeEntry)
|
|
||||||
{
|
|
||||||
jQuery(this.activeEntry.marker).show();
|
|
||||||
jQuery(this.elemDiv).sortable("refresh");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @returns {undefined}
|
|
||||||
*/
|
|
||||||
stopDrag: function()
|
|
||||||
{
|
|
||||||
if (this.activeEntry)
|
|
||||||
{
|
|
||||||
jQuery(this.activeEntry.marker).hide();
|
|
||||||
jQuery(this.elemDiv).sortable("refresh");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the sidemenu elements whenever they were sorted. An array containing
|
* Called by the sidemenu elements whenever they were sorted. An array containing
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
jQuery - Tap and Hold
|
|
||||||
=====================
|
|
||||||
|
|
||||||
This jQuery plugin lets you detect a tap and hold event on touch interfaces.
|
|
||||||
|
|
||||||
How to use it?
|
|
||||||
|
|
||||||
1) Add the jQuery Tap and Hold plugin into your HTML
|
|
||||||
|
|
||||||
<script src="jquery.tapandhold.js" type="text/javascript"></script>
|
|
||||||
|
|
||||||
2) Bind a tap and hold handler function to the tap and hold event of an element.
|
|
||||||
|
|
||||||
$("#myDiv").bind("taphold", function(event){
|
|
||||||
alert("This is a tap and hold!");
|
|
||||||
});
|
|
||||||
|
|
||||||
You can check a working example in examples/example1.html
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>jQuery - Tap and Hold</title>
|
|
||||||
<script src="http://code.jquery.com/jquery-1.7.min.js" type="text/javascript"></script>
|
|
||||||
<script src="https://raw.github.com/zaubersoftware/jquery-tap-and-hold/master/jquery.tapandhold.js" type="text/javascript"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(function(){
|
|
||||||
$(".tap").bind("taphold", function(){
|
|
||||||
alert("Hello Tap and Hold World!");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="tap" style="width:200px; height:200px; background-color: blue; margin: 100px 300px;"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,136 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2011 Zauber S.A. <http://www.zaubersoftware.com/>
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* @author Guido Marucci Blas - guido@zaubersoftware.com
|
|
||||||
* @description Adds a handler for a custom event 'taphold' that handles a
|
|
||||||
* tap and hold on touch interfaces.
|
|
||||||
*/
|
|
||||||
(function($) {
|
|
||||||
var TAP_AND_HOLD_TRIGGER_TIMER = 600;
|
|
||||||
var MAX_DISTANCE_ALLOWED_IN_TAP_AND_HOLD_EVENT = 40;
|
|
||||||
var TOUCHSTART = "touchstart";
|
|
||||||
var TOUCHEND = "touchend";
|
|
||||||
var TOUCHMOVE = "touchmove";
|
|
||||||
|
|
||||||
// For debugging only
|
|
||||||
// var TOUCHSTART = "mousedown";
|
|
||||||
// var TOUCHEND = "mouseup";
|
|
||||||
// var TOUCHMOVE = "mousemove";
|
|
||||||
|
|
||||||
var tapAndHoldTimer = null;
|
|
||||||
|
|
||||||
function calculateEuclideanDistance(x1, y1, x2, y2) {
|
|
||||||
var diffX = (x2 - x1);
|
|
||||||
var diffY = (y2 - y1);
|
|
||||||
return Math.sqrt((diffX * diffX) + (diffY * diffY));
|
|
||||||
};
|
|
||||||
|
|
||||||
function onTouchStart(event) {
|
|
||||||
var e = event.originalEvent;
|
|
||||||
|
|
||||||
// Only start detector if and only if one finger is over the widget
|
|
||||||
if (!e.touches || (e.targetTouches.length === 1 && e.touches.length === 1)) {
|
|
||||||
startTapAndHoldDetector.call(this, event)
|
|
||||||
var element = $(this);
|
|
||||||
element.bind(TOUCHMOVE, onTouchMove);
|
|
||||||
element.bind(TOUCHEND, onTouchEnd);
|
|
||||||
} else {
|
|
||||||
stopTapAndHoldDetector.call(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function onTouchMove(event) {
|
|
||||||
if (tapAndHoldTimer == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var e = event.originalEvent;
|
|
||||||
var x = (e.changedTouches) ? e.changedTouches[0].pageX: e.pageX;
|
|
||||||
var y = (e.changedTouches) ? e.changedTouches[0].pageY: e.pageY;
|
|
||||||
|
|
||||||
var tapAndHoldPoint = $(this).data("taphold.point");
|
|
||||||
var euclideanDistance = calculateEuclideanDistance(tapAndHoldPoint.x, tapAndHoldPoint.y, x, y);
|
|
||||||
|
|
||||||
if (euclideanDistance > MAX_DISTANCE_ALLOWED_IN_TAP_AND_HOLD_EVENT) {
|
|
||||||
stopTapAndHoldDetector.call(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function onTouchEnd(event) {
|
|
||||||
stopTapAndHoldDetector.call(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
function onTapAndHold(event) {
|
|
||||||
clear.call(this);
|
|
||||||
$(this).data("taphold.handler").call(this, event);
|
|
||||||
};
|
|
||||||
|
|
||||||
function clear() {
|
|
||||||
tapAndHoldTimer = null;
|
|
||||||
$(this).unbind(TOUCHMOVE, onTouchMove);
|
|
||||||
$(this).unbind(TOUCHEND, onTouchEnd);
|
|
||||||
};
|
|
||||||
|
|
||||||
function startTapAndHoldDetector(event) {
|
|
||||||
if (tapAndHoldTimer != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var self = this;
|
|
||||||
tapAndHoldTimer = setTimeout(function(){
|
|
||||||
onTapAndHold.call(self, event)
|
|
||||||
}, TAP_AND_HOLD_TRIGGER_TIMER);
|
|
||||||
|
|
||||||
// Stores tap x & y
|
|
||||||
var e = event.originalEvent;
|
|
||||||
var tapAndHoldPoint = {};
|
|
||||||
tapAndHoldPoint.x = (e.changedTouches) ? e.changedTouches[0].pageX: e.pageX;
|
|
||||||
tapAndHoldPoint.y = (e.changedTouches) ? e.changedTouches[0].pageY: e.pageY;
|
|
||||||
$(this).data("taphold.point", tapAndHoldPoint);
|
|
||||||
};
|
|
||||||
|
|
||||||
function stopTapAndHoldDetector() {
|
|
||||||
clearTimeout(tapAndHoldTimer);
|
|
||||||
clear.call(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
$.event.special["taphold"] = {
|
|
||||||
setup: function() {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
add: function(handleObj) {
|
|
||||||
$(this).data("taphold.handler", handleObj.handler);
|
|
||||||
if (handleObj.data) {
|
|
||||||
$(this).bind(TOUCHSTART, handleObj.data, onTouchStart);
|
|
||||||
} else {
|
|
||||||
$(this).bind(TOUCHSTART, onTouchStart);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
remove: function(handleObj) {
|
|
||||||
stopTapAndHoldDetector.call(this);
|
|
||||||
if (handleObj.data) {
|
|
||||||
$(this).unbind(TOUCHSTART, handleObj.data, onTouchStart);
|
|
||||||
} else {
|
|
||||||
$(this).unbind(TOUCHSTART, onTouchStart);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
teardown: function() {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
})(jQuery);
|
|
@ -781,32 +781,21 @@ export abstract class EgwApp
|
|||||||
})
|
})
|
||||||
.addClass("ui-helper-clearfix");
|
.addClass("ui-helper-clearfix");
|
||||||
|
|
||||||
//Add Sortable handler to sideBox fav. menu
|
//todo (@todo-jquery-ui): replace the import statement
|
||||||
jQuery('ul','#favorite_sidebox_'+this.appname).sortable({
|
import('../../../node_modules/sortablejs/Sortable.min.js').then(function(){
|
||||||
items:'li:not([data-id$="add"])',
|
let el = document.getElementById('favorite_sidebox_'+this.appname).getElementsByTagName('ul')[0];
|
||||||
placeholder:'ui-fav-sortable-placeholder',
|
let sortablejs = Sortable.create(el, {
|
||||||
delay:250, //(millisecond) delay before the sorting should start
|
ghostClass: 'ui-fav-sortable-placeholder',
|
||||||
helper: function(event, item : any) {
|
draggable: 'li:not([data-id$="add"])',
|
||||||
// We'll need to know which app this is for
|
delay: 25,
|
||||||
item.attr('data-appname',self.appname);
|
dataIdAttr:'data-id',
|
||||||
// Create custom helper so it can be dragged to Home
|
onSort: function(event){
|
||||||
var h_parent = item.parent().parent().clone();
|
let favSortedList = sortablejs.toArray();
|
||||||
h_parent.find('li').not('[data-id="'+item.attr('data-id')+'"]').remove();
|
|
||||||
h_parent.appendTo('body');
|
|
||||||
return h_parent;
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
refreshPositions: true,
|
|
||||||
update: function (event, ui)
|
|
||||||
{
|
|
||||||
// @ts-ignore
|
|
||||||
var favSortedList = jQuery(this).sortable('toArray', {attribute:'data-id'});
|
|
||||||
|
|
||||||
self.egw.set_preference(self.appname,'fav_sort_pref',favSortedList);
|
self.egw.set_preference(self.appname,'fav_sort_pref',favSortedList);
|
||||||
|
|
||||||
self._refresh_fav_nm();
|
self._refresh_fav_nm();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
// Bind favorite de-select
|
// Bind favorite de-select
|
||||||
var egw_fw = egw_getFramework();
|
var egw_fw = egw_getFramework();
|
||||||
|
@ -20,6 +20,13 @@ egw.extend('jsonq', egw.MODULE_GLOBAL, function()
|
|||||||
{
|
{
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicit registered push callbacks
|
||||||
|
*
|
||||||
|
* @type {Function[]}
|
||||||
|
*/
|
||||||
|
let push_callbacks = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queued json requests (objects with attributes menuaction, parameters, context, callback, sender and callbeforesend)
|
* Queued json requests (objects with attributes menuaction, parameters, context, callback, sender and callbeforesend)
|
||||||
*
|
*
|
||||||
@ -149,6 +156,34 @@ egw.extend('jsonq', egw.MODULE_GLOBAL, function()
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
return uid;
|
return uid;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback to receive push broadcasts eg. in a popup or iframe
|
||||||
|
*
|
||||||
|
* It's also used internally by egw_message's push method to dispatch to the registered callbacks.
|
||||||
|
*
|
||||||
|
* @param {Function|PushData} data callback (with bound context) or PushData to dispatch to callbacks
|
||||||
|
*/
|
||||||
|
registerPush: function(data)
|
||||||
|
{
|
||||||
|
if (typeof data === "function")
|
||||||
|
{
|
||||||
|
push_callbacks.push(data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (let n in push_callbacks)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
push_callbacks[n].call(this, data);
|
||||||
|
}
|
||||||
|
// if we get an exception, we assume the callback is no longer available and remove it
|
||||||
|
catch (ex) {
|
||||||
|
push_callbacks.splice(n, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -459,6 +459,9 @@ egw.extend('message', egw.MODULE_WND_LOCAL, function(_app, _wnd)
|
|||||||
app_obj.push(pushData);
|
app_obj.push(pushData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// call the global registered push callbacks
|
||||||
|
this.registerPush(pushData);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -241,7 +241,6 @@ class Bundle
|
|||||||
// generate api bundle
|
// generate api bundle
|
||||||
$inc_mgr->include_js_file('/vendor/bower-asset/jquery/dist/jquery.js');
|
$inc_mgr->include_js_file('/vendor/bower-asset/jquery/dist/jquery.js');
|
||||||
$inc_mgr->include_js_file('/api/js/jquery/jquery.noconflict.js');
|
$inc_mgr->include_js_file('/api/js/jquery/jquery.noconflict.js');
|
||||||
$inc_mgr->include_js_file('/vendor/bower-asset/jquery-ui/jquery-ui.js');
|
|
||||||
$inc_mgr->include_js_file('/api/js/jsapi/jsapi.js');
|
$inc_mgr->include_js_file('/api/js/jsapi/jsapi.js');
|
||||||
$inc_mgr->include_js_file('/api/js/egw_json.js');
|
$inc_mgr->include_js_file('/api/js/egw_json.js');
|
||||||
$inc_mgr->include_js_file('/api/js/jsapi/egw.js');
|
$inc_mgr->include_js_file('/api/js/jsapi/egw.js');
|
||||||
|
@ -465,7 +465,7 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
|
|||||||
{
|
{
|
||||||
var drop_date = dropEnd.date||false;
|
var drop_date = dropEnd.date||false;
|
||||||
|
|
||||||
var event_data = timegrid._get_event_info(ui.draggable);
|
var event_data = timegrid._get_event_info(ui.item);
|
||||||
var event_widget = timegrid.getWidgetById(event_data.widget_id);
|
var event_widget = timegrid.getWidgetById(event_data.widget_id);
|
||||||
if(!event_widget)
|
if(!event_widget)
|
||||||
{
|
{
|
||||||
@ -1272,7 +1272,7 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
|
|||||||
// Determine target node
|
// Determine target node
|
||||||
var event = _data.event || false;
|
var event = _data.event || false;
|
||||||
if(!event) return;
|
if(!event) return;
|
||||||
if(_data.ui.draggable.hasClass('rowNoEdit')) return;
|
if(_data.ui.item.hasClass('rowNoEdit')) return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We have to handle the drop in the normal event stream instead of waiting
|
We have to handle the drop in the normal event stream instead of waiting
|
||||||
@ -1307,9 +1307,9 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
|
|||||||
case EGW_AI_DRAG_OVER:
|
case EGW_AI_DRAG_OVER:
|
||||||
// Listen to the drag and update the helper with the time
|
// Listen to the drag and update the helper with the time
|
||||||
// This part lets us drag between different timegrids
|
// This part lets us drag between different timegrids
|
||||||
_data.ui.draggable.on('drag.et2_timegrid'+widget_object.id, drag_listener);
|
_data.ui.item.on('drag.et2_timegrid'+widget_object.id, drag_listener);
|
||||||
_data.ui.draggable.on('dragend.et2_timegrid'+widget_object.id, function() {
|
_data.ui.item.on('dragend.et2_timegrid'+widget_object.id, function() {
|
||||||
_data.ui.draggable.off('drag.et2_timegrid' + widget_object.id);
|
_data.ui.item.off('drag.et2_timegrid' + widget_object.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove formatting for out-of-view events (full day non-blocking)
|
// Remove formatting for out-of-view events (full day non-blocking)
|
||||||
@ -1317,7 +1317,7 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
|
|||||||
jQuery('.calendar_calEventBody',_data.ui.helper).css('padding-top','');
|
jQuery('.calendar_calEventBody',_data.ui.helper).css('padding-top','');
|
||||||
|
|
||||||
// Disable invite / change actions for same calendar or already participant
|
// Disable invite / change actions for same calendar or already participant
|
||||||
var event = _data.ui.draggable.data('selected')[0];
|
var event = _data.ui.item.data('selected')[0];
|
||||||
if(!event || event.id && event.id.indexOf('calendar') !== 0)
|
if(!event || event.id && event.id.indexOf('calendar') !== 0)
|
||||||
{
|
{
|
||||||
event = false;
|
event = false;
|
||||||
@ -1346,7 +1346,7 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
|
|||||||
// Triggered once, when something is dragged out of the timegrid
|
// Triggered once, when something is dragged out of the timegrid
|
||||||
case EGW_AI_DRAG_OUT:
|
case EGW_AI_DRAG_OUT:
|
||||||
// Stop listening
|
// Stop listening
|
||||||
_data.ui.draggable.off('drag.et2_timegrid'+widget_object.id);
|
_data.ui.item.off('drag.et2_timegrid'+widget_object.id);
|
||||||
// Remove highlighted time square
|
// Remove highlighted time square
|
||||||
var timegrid = aoi.getWidget();
|
var timegrid = aoi.getWidget();
|
||||||
timegrid.gridHover.hide();
|
timegrid.gridHover.hide();
|
||||||
|
3496
package-lock.json
generated
3496
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@
|
|||||||
"@rollup/plugin-typescript": "^8.2.1",
|
"@rollup/plugin-typescript": "^8.2.1",
|
||||||
"@types/jquery": "^3.5.5",
|
"@types/jquery": "^3.5.5",
|
||||||
"@types/jqueryui": "^1.12.14",
|
"@types/jqueryui": "^1.12.14",
|
||||||
|
"@types/sortablejs": "1.10.0",
|
||||||
"grunt": "^1.3.0",
|
"grunt": "^1.3.0",
|
||||||
"grunt-contrib-cssmin": "^2.2.1",
|
"grunt-contrib-cssmin": "^2.2.1",
|
||||||
"grunt-newer": "^1.3.0",
|
"grunt-newer": "^1.3.0",
|
||||||
@ -48,7 +49,9 @@
|
|||||||
"carbon-components": "^10.37.0",
|
"carbon-components": "^10.37.0",
|
||||||
"carbon-web-components": "^1.14.1",
|
"carbon-web-components": "^1.14.1",
|
||||||
"lit-element": "^2.5.1",
|
"lit-element": "^2.5.1",
|
||||||
"lit-html": "^1.4.1"
|
"lit-html": "^1.4.1",
|
||||||
|
"sortablejs": "^1.14.0",
|
||||||
|
"egw-touch-dnd": "^1.2.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user