Move converse-dragresize plugin to folder
This commit is contained in:
parent
f2ef8c7206
commit
12bb9375f4
@ -17,7 +17,7 @@ import "shared/registry.js";
|
|||||||
import "./plugins/bookmark-views.js"; // Views for XEP-0048 Bookmarks
|
import "./plugins/bookmark-views.js"; // Views for XEP-0048 Bookmarks
|
||||||
import "./plugins/chatview/index.js"; // Renders standalone chat boxes for single user chat
|
import "./plugins/chatview/index.js"; // Renders standalone chat boxes for single user chat
|
||||||
import "./plugins/controlbox/index.js"; // The control box
|
import "./plugins/controlbox/index.js"; // The control box
|
||||||
import "./plugins/dragresize.js"; // Allows chat boxes to be resized by dragging them
|
import "./plugins/dragresize/index.js"; // Allows chat boxes to be resized by dragging them
|
||||||
import "./plugins/fullscreen.js";
|
import "./plugins/fullscreen.js";
|
||||||
import "./plugins/mam-views.js";
|
import "./plugins/mam-views.js";
|
||||||
import "./plugins/minimize.js"; // Allows chat boxes to be minimized
|
import "./plugins/minimize.js"; // Allows chat boxes to be minimized
|
||||||
|
@ -1,382 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module converse-dragresize
|
|
||||||
* @copyright 2020, the Converse.js contributors
|
|
||||||
* @license Mozilla Public License (MPLv2)
|
|
||||||
*/
|
|
||||||
import "./chatview/index.js";
|
|
||||||
import "./controlbox/index.js";
|
|
||||||
import { debounce } from "lodash-es";
|
|
||||||
import { _converse, api, converse } from "@converse/headless/core";
|
|
||||||
import tpl_dragresize from "../templates/dragresize.html";
|
|
||||||
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
function renderDragResizeHandles (_converse, view) {
|
|
||||||
const flyout = view.el.querySelector('.box-flyout');
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.innerHTML = tpl_dragresize();
|
|
||||||
flyout.insertBefore(
|
|
||||||
div,
|
|
||||||
flyout.firstChild
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
converse.plugins.add('converse-dragresize', {
|
|
||||||
/* Plugin dependencies are other plugins which might be
|
|
||||||
* overridden or relied upon, and therefore need to be loaded before
|
|
||||||
* this plugin.
|
|
||||||
*
|
|
||||||
* If the setting "strict_plugin_dependencies" is set to true,
|
|
||||||
* an error will be raised if the plugin is not found. By default it's
|
|
||||||
* false, which means these plugins are only loaded opportunistically.
|
|
||||||
*
|
|
||||||
* NB: These plugins need to have already been loaded via require.js.
|
|
||||||
*/
|
|
||||||
dependencies: ["converse-chatview", "converse-headlines-view", "converse-muc-views"],
|
|
||||||
|
|
||||||
enabled (_converse) {
|
|
||||||
return _converse.api.settings.get("view_mode") == 'overlayed';
|
|
||||||
},
|
|
||||||
|
|
||||||
overrides: {
|
|
||||||
// Overrides mentioned here will be picked up by converse.js's
|
|
||||||
// plugin architecture they will replace existing methods on the
|
|
||||||
// relevant objects or classes.
|
|
||||||
ChatBox: {
|
|
||||||
initialize () {
|
|
||||||
const result = this.__super__.initialize.apply(this, arguments);
|
|
||||||
const height = this.get('height'), width = this.get('width');
|
|
||||||
const save = this.get('id') === 'controlbox' ? a => this.set(a) : a => this.save(a);
|
|
||||||
save({
|
|
||||||
'height': u.applyDragResistance(height, this.get('default_height')),
|
|
||||||
'width': u.applyDragResistance(width, this.get('default_width')),
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ChatBoxView: {
|
|
||||||
events: {
|
|
||||||
'mousedown .dragresize-top': 'onStartVerticalResize',
|
|
||||||
'mousedown .dragresize-left': 'onStartHorizontalResize',
|
|
||||||
'mousedown .dragresize-topleft': 'onStartDiagonalResize'
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const result = this.__super__.render.apply(this, arguments);
|
|
||||||
renderDragResizeHandles(this.__super__._converse, this);
|
|
||||||
this.setWidth();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
HeadlinesBoxView: {
|
|
||||||
events: {
|
|
||||||
'mousedown .dragresize-top': 'onStartVerticalResize',
|
|
||||||
'mousedown .dragresize-left': 'onStartHorizontalResize',
|
|
||||||
'mousedown .dragresize-topleft': 'onStartDiagonalResize'
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const result = this.__super__.render.apply(this, arguments);
|
|
||||||
renderDragResizeHandles(this.__super__._converse, this);
|
|
||||||
this.setWidth();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ControlBoxView: {
|
|
||||||
events: {
|
|
||||||
'mousedown .dragresize-top': 'onStartVerticalResize',
|
|
||||||
'mousedown .dragresize-left': 'onStartHorizontalResize',
|
|
||||||
'mousedown .dragresize-topleft': 'onStartDiagonalResize'
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const result = this.__super__.render.apply(this, arguments);
|
|
||||||
renderDragResizeHandles(this.__super__._converse, this);
|
|
||||||
this.setWidth();
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
renderLoginPanel () {
|
|
||||||
const result = this.__super__.renderLoginPanel.apply(this, arguments);
|
|
||||||
this.initDragResize().setDimensions();
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
renderControlBoxPane () {
|
|
||||||
const result = this.__super__.renderControlBoxPane.apply(this, arguments);
|
|
||||||
this.initDragResize().setDimensions();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ChatRoomView: {
|
|
||||||
events: {
|
|
||||||
'mousedown .dragresize-top': 'onStartVerticalResize',
|
|
||||||
'mousedown .dragresize-left': 'onStartHorizontalResize',
|
|
||||||
'mousedown .dragresize-topleft': 'onStartDiagonalResize'
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const result = this.__super__.render.apply(this, arguments);
|
|
||||||
renderDragResizeHandles(this.__super__._converse, this);
|
|
||||||
this.setWidth();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize () {
|
|
||||||
/* The initialize function gets called as soon as the plugin is
|
|
||||||
* loaded by converse.js's plugin machinery.
|
|
||||||
*/
|
|
||||||
api.settings.extend({
|
|
||||||
'allow_dragresize': true,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const dragResizable = {
|
|
||||||
|
|
||||||
initDragResize () {
|
|
||||||
const view = this;
|
|
||||||
const debouncedSetDimensions = debounce(() => view.setDimensions());
|
|
||||||
window.addEventListener('resize', view.debouncedSetDimensions)
|
|
||||||
this.listenTo(this.model, 'destroy', () => window.removeEventListener('resize', debouncedSetDimensions));
|
|
||||||
|
|
||||||
// Determine and store the default box size.
|
|
||||||
// We need this information for the drag-resizing feature.
|
|
||||||
const flyout = this.el.querySelector('.box-flyout');
|
|
||||||
const style = window.getComputedStyle(flyout);
|
|
||||||
|
|
||||||
if (this.model.get('height') === undefined) {
|
|
||||||
const height = parseInt(style.height.replace(/px$/, ''), 10);
|
|
||||||
const width = parseInt(style.width.replace(/px$/, ''), 10);
|
|
||||||
this.model.set('height', height);
|
|
||||||
this.model.set('default_height', height);
|
|
||||||
this.model.set('width', width);
|
|
||||||
this.model.set('default_width', width);
|
|
||||||
}
|
|
||||||
const min_width = style['min-width'];
|
|
||||||
const min_height = style['min-height'];
|
|
||||||
this.model.set('min_width', min_width.endsWith('px') ? Number(min_width.replace(/px$/, '')) :0);
|
|
||||||
this.model.set('min_height', min_height.endsWith('px') ? Number(min_height.replace(/px$/, '')) :0);
|
|
||||||
// Initialize last known mouse position
|
|
||||||
this.prev_pageY = 0;
|
|
||||||
this.prev_pageX = 0;
|
|
||||||
if (_converse.connection?.connected) {
|
|
||||||
this.height = this.model.get('height');
|
|
||||||
this.width = this.model.get('width');
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
resizeChatBox (ev) {
|
|
||||||
let diff;
|
|
||||||
if (_converse.resizing.direction.indexOf('top') === 0) {
|
|
||||||
diff = ev.pageY - this.prev_pageY;
|
|
||||||
if (diff) {
|
|
||||||
this.height = ((this.height-diff) > (this.model.get('min_height') || 0)) ? (this.height-diff) : this.model.get('min_height');
|
|
||||||
this.prev_pageY = ev.pageY;
|
|
||||||
this.setChatBoxHeight(this.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_converse.resizing.direction.includes('left')) {
|
|
||||||
diff = this.prev_pageX - ev.pageX;
|
|
||||||
if (diff) {
|
|
||||||
this.width = ((this.width+diff) > (this.model.get('min_width') || 0)) ? (this.width+diff) : this.model.get('min_width');
|
|
||||||
this.prev_pageX = ev.pageX;
|
|
||||||
this.setChatBoxWidth(this.width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setWidth () {
|
|
||||||
// If a custom width is applied (due to drag-resizing),
|
|
||||||
// then we need to set the width of the .chatbox element as well.
|
|
||||||
if (this.model.get('width')) {
|
|
||||||
this.el.style.width = this.model.get('width');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setDimensions () {
|
|
||||||
// Make sure the chat box has the right height and width.
|
|
||||||
this.adjustToViewport();
|
|
||||||
this.setChatBoxHeight(this.model.get('height'));
|
|
||||||
this.setChatBoxWidth(this.model.get('width'));
|
|
||||||
},
|
|
||||||
|
|
||||||
setChatBoxHeight (height) {
|
|
||||||
if (height) {
|
|
||||||
height = u.applyDragResistance(height, this.model.get('default_height'))+'px';
|
|
||||||
} else {
|
|
||||||
height = "";
|
|
||||||
}
|
|
||||||
const flyout_el = this.el.querySelector('.box-flyout');
|
|
||||||
if (flyout_el !== null) {
|
|
||||||
flyout_el.style.height = height;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setChatBoxWidth (width) {
|
|
||||||
if (width) {
|
|
||||||
width = u.applyDragResistance(width, this.model.get('default_width'))+'px';
|
|
||||||
} else {
|
|
||||||
width = "";
|
|
||||||
}
|
|
||||||
this.el.style.width = width;
|
|
||||||
const flyout_el = this.el.querySelector('.box-flyout');
|
|
||||||
if (flyout_el !== null) {
|
|
||||||
flyout_el.style.width = width;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
adjustToViewport () {
|
|
||||||
/* Event handler called when viewport gets resized. We remove
|
|
||||||
* custom width/height from chat boxes.
|
|
||||||
*/
|
|
||||||
const viewport_width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
|
|
||||||
const viewport_height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
|
|
||||||
if (viewport_width <= 480) {
|
|
||||||
this.model.set('height', undefined);
|
|
||||||
this.model.set('width', undefined);
|
|
||||||
} else if (viewport_width <= this.model.get('width')) {
|
|
||||||
this.model.set('width', undefined);
|
|
||||||
} else if (viewport_height <= this.model.get('height')) {
|
|
||||||
this.model.set('height', undefined);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onStartVerticalResize (ev, trigger=true) {
|
|
||||||
if (!api.settings.get('allow_dragresize')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ev.preventDefault();
|
|
||||||
// Record element attributes for mouseMove().
|
|
||||||
const flyout = this.el.querySelector('.box-flyout'),
|
|
||||||
style = window.getComputedStyle(flyout);
|
|
||||||
this.height = parseInt(style.height.replace(/px$/, ''), 10);
|
|
||||||
_converse.resizing = {
|
|
||||||
'chatbox': this,
|
|
||||||
'direction': 'top'
|
|
||||||
};
|
|
||||||
this.prev_pageY = ev.pageY;
|
|
||||||
if (trigger) {
|
|
||||||
/**
|
|
||||||
* Triggered once the user starts to vertically resize a {@link _converse.ChatBoxView}
|
|
||||||
* @event _converse#startVerticalResize
|
|
||||||
* @example _converse.api.listen.on('startVerticalResize', (view) => { ... });
|
|
||||||
*/
|
|
||||||
api.trigger('startVerticalResize', this);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onStartHorizontalResize (ev, trigger=true) {
|
|
||||||
if (!api.settings.get('allow_dragresize')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ev.preventDefault();
|
|
||||||
const flyout = this.el.querySelector('.box-flyout'),
|
|
||||||
style = window.getComputedStyle(flyout);
|
|
||||||
this.width = parseInt(style.width.replace(/px$/, ''), 10);
|
|
||||||
_converse.resizing = {
|
|
||||||
'chatbox': this,
|
|
||||||
'direction': 'left'
|
|
||||||
};
|
|
||||||
this.prev_pageX = ev.pageX;
|
|
||||||
if (trigger) {
|
|
||||||
/**
|
|
||||||
* Triggered once the user starts to horizontally resize a {@link _converse.ChatBoxView}
|
|
||||||
* @event _converse#startHorizontalResize
|
|
||||||
* @example _converse.api.listen.on('startHorizontalResize', (view) => { ... });
|
|
||||||
*/
|
|
||||||
api.trigger('startHorizontalResize', this);
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
onStartDiagonalResize (ev) {
|
|
||||||
this.onStartHorizontalResize(ev, false);
|
|
||||||
this.onStartVerticalResize(ev, false);
|
|
||||||
_converse.resizing.direction = 'topleft';
|
|
||||||
/**
|
|
||||||
* Triggered once the user starts to diagonally resize a {@link _converse.ChatBoxView}
|
|
||||||
* @event _converse#startDiagonalResize
|
|
||||||
* @example _converse.api.listen.on('startDiagonalResize', (view) => { ... });
|
|
||||||
*/
|
|
||||||
api.trigger('startDiagonalResize', this);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Object.assign(_converse.ChatBoxView.prototype, dragResizable);
|
|
||||||
|
|
||||||
|
|
||||||
u.applyDragResistance = function (value, default_value) {
|
|
||||||
/* This method applies some resistance around the
|
|
||||||
* default_value. If value is close enough to
|
|
||||||
* default_value, then default_value is returned instead.
|
|
||||||
*/
|
|
||||||
if (value === undefined) {
|
|
||||||
return undefined;
|
|
||||||
} else if (default_value === undefined) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
const resistance = 10;
|
|
||||||
if ((value !== default_value) &&
|
|
||||||
(Math.abs(value- default_value) < resistance)) {
|
|
||||||
return default_value;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function onMouseMove (ev) {
|
|
||||||
if (!_converse.resizing || !api.settings.get('allow_dragresize')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ev.preventDefault();
|
|
||||||
_converse.resizing.chatbox.resizeChatBox(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function onMouseUp (ev) {
|
|
||||||
if (!_converse.resizing || !api.settings.get('allow_dragresize')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ev.preventDefault();
|
|
||||||
const height = u.applyDragResistance(
|
|
||||||
_converse.resizing.chatbox.height,
|
|
||||||
_converse.resizing.chatbox.model.get('default_height')
|
|
||||||
);
|
|
||||||
const width = u.applyDragResistance(
|
|
||||||
_converse.resizing.chatbox.width,
|
|
||||||
_converse.resizing.chatbox.model.get('default_width')
|
|
||||||
);
|
|
||||||
if (api.connection.connected()) {
|
|
||||||
_converse.resizing.chatbox.model.save({'height': height});
|
|
||||||
_converse.resizing.chatbox.model.save({'width': width});
|
|
||||||
} else {
|
|
||||||
_converse.resizing.chatbox.model.set({'height': height});
|
|
||||||
_converse.resizing.chatbox.model.set({'width': width});
|
|
||||||
}
|
|
||||||
_converse.resizing = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************ BEGIN Event Handlers ************************/
|
|
||||||
function registerGlobalEventHandlers () {
|
|
||||||
document.addEventListener('mousemove', onMouseMove);
|
|
||||||
document.addEventListener('mouseup', onMouseUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unregisterGlobalEventHandlers () {
|
|
||||||
document.removeEventListener('mousemove', onMouseMove);
|
|
||||||
document.removeEventListener('mouseup', onMouseUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
api.listen.on('registeredGlobalEventHandlers', registerGlobalEventHandlers);
|
|
||||||
api.listen.on('unregisteredGlobalEventHandlers', unregisterGlobalEventHandlers);
|
|
||||||
api.listen.on('beforeShowingChatView', view => view.initDragResize().setDimensions());
|
|
||||||
/************************ END Event Handlers ************************/
|
|
||||||
}
|
|
||||||
});
|
|
145
src/plugins/dragresize/index.js
Normal file
145
src/plugins/dragresize/index.js
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* @module converse-dragresize
|
||||||
|
* @copyright 2020, the Converse.js contributors
|
||||||
|
* @license Mozilla Public License (MPLv2)
|
||||||
|
*/
|
||||||
|
import 'plugins/chatview/index.js';
|
||||||
|
import 'plugins/controlbox/index.js';
|
||||||
|
import { applyDragResistance, onMouseUp, onMouseMove, renderDragResizeHandles } from './utils.js';
|
||||||
|
import DragResizableMixin from './mixin.js';
|
||||||
|
import { _converse, api, converse } from '@converse/headless/core';
|
||||||
|
|
||||||
|
converse.plugins.add('converse-dragresize', {
|
||||||
|
/* Plugin dependencies are other plugins which might be
|
||||||
|
* overridden or relied upon, and therefore need to be loaded before
|
||||||
|
* this plugin.
|
||||||
|
*
|
||||||
|
* If the setting "strict_plugin_dependencies" is set to true,
|
||||||
|
* an error will be raised if the plugin is not found. By default it's
|
||||||
|
* false, which means these plugins are only loaded opportunistically.
|
||||||
|
*
|
||||||
|
* NB: These plugins need to have already been loaded via require.js.
|
||||||
|
*/
|
||||||
|
dependencies: ['converse-chatview', 'converse-headlines-view', 'converse-muc-views'],
|
||||||
|
|
||||||
|
enabled (_converse) {
|
||||||
|
return _converse.api.settings.get('view_mode') == 'overlayed';
|
||||||
|
},
|
||||||
|
|
||||||
|
overrides: {
|
||||||
|
// Overrides mentioned here will be picked up by converse.js's
|
||||||
|
// plugin architecture they will replace existing methods on the
|
||||||
|
// relevant objects or classes.
|
||||||
|
ChatBox: {
|
||||||
|
initialize () {
|
||||||
|
const result = this.__super__.initialize.apply(this, arguments);
|
||||||
|
const height = this.get('height'),
|
||||||
|
width = this.get('width');
|
||||||
|
const save = this.get('id') === 'controlbox' ? a => this.set(a) : a => this.save(a);
|
||||||
|
save({
|
||||||
|
'height': applyDragResistance(height, this.get('default_height')),
|
||||||
|
'width': applyDragResistance(width, this.get('default_width'))
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ChatBoxView: {
|
||||||
|
events: {
|
||||||
|
'mousedown .dragresize-top': 'onStartVerticalResize',
|
||||||
|
'mousedown .dragresize-left': 'onStartHorizontalResize',
|
||||||
|
'mousedown .dragresize-topleft': 'onStartDiagonalResize'
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const result = this.__super__.render.apply(this, arguments);
|
||||||
|
renderDragResizeHandles(this.__super__._converse, this);
|
||||||
|
this.setWidth();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
HeadlinesBoxView: {
|
||||||
|
events: {
|
||||||
|
'mousedown .dragresize-top': 'onStartVerticalResize',
|
||||||
|
'mousedown .dragresize-left': 'onStartHorizontalResize',
|
||||||
|
'mousedown .dragresize-topleft': 'onStartDiagonalResize'
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const result = this.__super__.render.apply(this, arguments);
|
||||||
|
renderDragResizeHandles(this.__super__._converse, this);
|
||||||
|
this.setWidth();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ControlBoxView: {
|
||||||
|
events: {
|
||||||
|
'mousedown .dragresize-top': 'onStartVerticalResize',
|
||||||
|
'mousedown .dragresize-left': 'onStartHorizontalResize',
|
||||||
|
'mousedown .dragresize-topleft': 'onStartDiagonalResize'
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const result = this.__super__.render.apply(this, arguments);
|
||||||
|
renderDragResizeHandles(this.__super__._converse, this);
|
||||||
|
this.setWidth();
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderLoginPanel () {
|
||||||
|
const result = this.__super__.renderLoginPanel.apply(this, arguments);
|
||||||
|
this.initDragResize().setDimensions();
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderControlBoxPane () {
|
||||||
|
const result = this.__super__.renderControlBoxPane.apply(this, arguments);
|
||||||
|
this.initDragResize().setDimensions();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ChatRoomView: {
|
||||||
|
events: {
|
||||||
|
'mousedown .dragresize-top': 'onStartVerticalResize',
|
||||||
|
'mousedown .dragresize-left': 'onStartHorizontalResize',
|
||||||
|
'mousedown .dragresize-topleft': 'onStartDiagonalResize'
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const result = this.__super__.render.apply(this, arguments);
|
||||||
|
renderDragResizeHandles(this.__super__._converse, this);
|
||||||
|
this.setWidth();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize () {
|
||||||
|
/* The initialize function gets called as soon as the plugin is
|
||||||
|
* loaded by converse.js's plugin machinery.
|
||||||
|
*/
|
||||||
|
api.settings.extend({
|
||||||
|
'allow_dragresize': true
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.assign(_converse.ChatBoxView.prototype, DragResizableMixin);
|
||||||
|
|
||||||
|
/************************ BEGIN Event Handlers ************************/
|
||||||
|
function registerGlobalEventHandlers () {
|
||||||
|
document.addEventListener('mousemove', onMouseMove);
|
||||||
|
document.addEventListener('mouseup', onMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterGlobalEventHandlers () {
|
||||||
|
document.removeEventListener('mousemove', onMouseMove);
|
||||||
|
document.removeEventListener('mouseup', onMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
api.listen.on('registeredGlobalEventHandlers', registerGlobalEventHandlers);
|
||||||
|
api.listen.on('unregisteredGlobalEventHandlers', unregisterGlobalEventHandlers);
|
||||||
|
api.listen.on('beforeShowingChatView', view => view.initDragResize().setDimensions());
|
||||||
|
}
|
||||||
|
});
|
181
src/plugins/dragresize/mixin.js
Normal file
181
src/plugins/dragresize/mixin.js
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import { _converse, api } from '@converse/headless/core';
|
||||||
|
import { applyDragResistance } from './utils.js';
|
||||||
|
import { debounce } from 'lodash-es';
|
||||||
|
|
||||||
|
const DragResizableMixin = {
|
||||||
|
initDragResize () {
|
||||||
|
const view = this;
|
||||||
|
const debouncedSetDimensions = debounce(() => view.setDimensions());
|
||||||
|
window.addEventListener('resize', view.debouncedSetDimensions);
|
||||||
|
this.listenTo(this.model, 'destroy', () => window.removeEventListener('resize', debouncedSetDimensions));
|
||||||
|
|
||||||
|
// Determine and store the default box size.
|
||||||
|
// We need this information for the drag-resizing feature.
|
||||||
|
const flyout = this.el.querySelector('.box-flyout');
|
||||||
|
const style = window.getComputedStyle(flyout);
|
||||||
|
|
||||||
|
if (this.model.get('height') === undefined) {
|
||||||
|
const height = parseInt(style.height.replace(/px$/, ''), 10);
|
||||||
|
const width = parseInt(style.width.replace(/px$/, ''), 10);
|
||||||
|
this.model.set('height', height);
|
||||||
|
this.model.set('default_height', height);
|
||||||
|
this.model.set('width', width);
|
||||||
|
this.model.set('default_width', width);
|
||||||
|
}
|
||||||
|
const min_width = style['min-width'];
|
||||||
|
const min_height = style['min-height'];
|
||||||
|
this.model.set('min_width', min_width.endsWith('px') ? Number(min_width.replace(/px$/, '')) : 0);
|
||||||
|
this.model.set('min_height', min_height.endsWith('px') ? Number(min_height.replace(/px$/, '')) : 0);
|
||||||
|
// Initialize last known mouse position
|
||||||
|
this.prev_pageY = 0;
|
||||||
|
this.prev_pageX = 0;
|
||||||
|
if (_converse.connection?.connected) {
|
||||||
|
this.height = this.model.get('height');
|
||||||
|
this.width = this.model.get('width');
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
resizeChatBox (ev) {
|
||||||
|
let diff;
|
||||||
|
if (_converse.resizing.direction.indexOf('top') === 0) {
|
||||||
|
diff = ev.pageY - this.prev_pageY;
|
||||||
|
if (diff) {
|
||||||
|
this.height =
|
||||||
|
this.height - diff > (this.model.get('min_height') || 0)
|
||||||
|
? this.height - diff
|
||||||
|
: this.model.get('min_height');
|
||||||
|
this.prev_pageY = ev.pageY;
|
||||||
|
this.setChatBoxHeight(this.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_converse.resizing.direction.includes('left')) {
|
||||||
|
diff = this.prev_pageX - ev.pageX;
|
||||||
|
if (diff) {
|
||||||
|
this.width =
|
||||||
|
this.width + diff > (this.model.get('min_width') || 0)
|
||||||
|
? this.width + diff
|
||||||
|
: this.model.get('min_width');
|
||||||
|
this.prev_pageX = ev.pageX;
|
||||||
|
this.setChatBoxWidth(this.width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setWidth () {
|
||||||
|
// If a custom width is applied (due to drag-resizing),
|
||||||
|
// then we need to set the width of the .chatbox element as well.
|
||||||
|
if (this.model.get('width')) {
|
||||||
|
this.el.style.width = this.model.get('width');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setDimensions () {
|
||||||
|
// Make sure the chat box has the right height and width.
|
||||||
|
this.adjustToViewport();
|
||||||
|
this.setChatBoxHeight(this.model.get('height'));
|
||||||
|
this.setChatBoxWidth(this.model.get('width'));
|
||||||
|
},
|
||||||
|
|
||||||
|
setChatBoxHeight (height) {
|
||||||
|
if (height) {
|
||||||
|
height = applyDragResistance(height, this.model.get('default_height')) + 'px';
|
||||||
|
} else {
|
||||||
|
height = '';
|
||||||
|
}
|
||||||
|
const flyout_el = this.el.querySelector('.box-flyout');
|
||||||
|
if (flyout_el !== null) {
|
||||||
|
flyout_el.style.height = height;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setChatBoxWidth (width) {
|
||||||
|
if (width) {
|
||||||
|
width = applyDragResistance(width, this.model.get('default_width')) + 'px';
|
||||||
|
} else {
|
||||||
|
width = '';
|
||||||
|
}
|
||||||
|
this.el.style.width = width;
|
||||||
|
const flyout_el = this.el.querySelector('.box-flyout');
|
||||||
|
if (flyout_el !== null) {
|
||||||
|
flyout_el.style.width = width;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
adjustToViewport () {
|
||||||
|
/* Event handler called when viewport gets resized. We remove
|
||||||
|
* custom width/height from chat boxes.
|
||||||
|
*/
|
||||||
|
const viewport_width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
|
||||||
|
const viewport_height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
|
||||||
|
if (viewport_width <= 480) {
|
||||||
|
this.model.set('height', undefined);
|
||||||
|
this.model.set('width', undefined);
|
||||||
|
} else if (viewport_width <= this.model.get('width')) {
|
||||||
|
this.model.set('width', undefined);
|
||||||
|
} else if (viewport_height <= this.model.get('height')) {
|
||||||
|
this.model.set('height', undefined);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onStartVerticalResize (ev, trigger = true) {
|
||||||
|
if (!api.settings.get('allow_dragresize')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ev.preventDefault();
|
||||||
|
// Record element attributes for mouseMove().
|
||||||
|
const flyout = this.el.querySelector('.box-flyout'),
|
||||||
|
style = window.getComputedStyle(flyout);
|
||||||
|
this.height = parseInt(style.height.replace(/px$/, ''), 10);
|
||||||
|
_converse.resizing = {
|
||||||
|
'chatbox': this,
|
||||||
|
'direction': 'top'
|
||||||
|
};
|
||||||
|
this.prev_pageY = ev.pageY;
|
||||||
|
if (trigger) {
|
||||||
|
/**
|
||||||
|
* Triggered once the user starts to vertically resize a {@link _converse.ChatBoxView}
|
||||||
|
* @event _converse#startVerticalResize
|
||||||
|
* @example _converse.api.listen.on('startVerticalResize', (view) => { ... });
|
||||||
|
*/
|
||||||
|
api.trigger('startVerticalResize', this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onStartHorizontalResize (ev, trigger = true) {
|
||||||
|
if (!api.settings.get('allow_dragresize')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ev.preventDefault();
|
||||||
|
const flyout = this.el.querySelector('.box-flyout'),
|
||||||
|
style = window.getComputedStyle(flyout);
|
||||||
|
this.width = parseInt(style.width.replace(/px$/, ''), 10);
|
||||||
|
_converse.resizing = {
|
||||||
|
'chatbox': this,
|
||||||
|
'direction': 'left'
|
||||||
|
};
|
||||||
|
this.prev_pageX = ev.pageX;
|
||||||
|
if (trigger) {
|
||||||
|
/**
|
||||||
|
* Triggered once the user starts to horizontally resize a {@link _converse.ChatBoxView}
|
||||||
|
* @event _converse#startHorizontalResize
|
||||||
|
* @example _converse.api.listen.on('startHorizontalResize', (view) => { ... });
|
||||||
|
*/
|
||||||
|
api.trigger('startHorizontalResize', this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onStartDiagonalResize (ev) {
|
||||||
|
this.onStartHorizontalResize(ev, false);
|
||||||
|
this.onStartVerticalResize(ev, false);
|
||||||
|
_converse.resizing.direction = 'topleft';
|
||||||
|
/**
|
||||||
|
* Triggered once the user starts to diagonally resize a {@link _converse.ChatBoxView}
|
||||||
|
* @event _converse#startDiagonalResize
|
||||||
|
* @example _converse.api.listen.on('startDiagonalResize', (view) => { ... });
|
||||||
|
*/
|
||||||
|
api.trigger('startDiagonalResize', this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DragResizableMixin;
|
61
src/plugins/dragresize/utils.js
Normal file
61
src/plugins/dragresize/utils.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import tpl_dragresize from './templates/dragresize.html';
|
||||||
|
import { _converse, api } from '@converse/headless/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies some resistance to `value` around the `default_value`.
|
||||||
|
* If value is close enough to `default_value`, then it is returned, otherwise
|
||||||
|
* `value` is returned.
|
||||||
|
* @param { Integer } value
|
||||||
|
* @param { Integer } default_value
|
||||||
|
* @returns { Integer }
|
||||||
|
*/
|
||||||
|
export function applyDragResistance (value, default_value) {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
} else if (default_value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
const resistance = 10;
|
||||||
|
if (value !== default_value && Math.abs(value - default_value) < resistance) {
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderDragResizeHandles (_converse, view) {
|
||||||
|
const flyout = view.el.querySelector('.box-flyout');
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.innerHTML = tpl_dragresize();
|
||||||
|
flyout.insertBefore(div, flyout.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onMouseMove (ev) {
|
||||||
|
if (!_converse.resizing || !api.settings.get('allow_dragresize')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ev.preventDefault();
|
||||||
|
_converse.resizing.chatbox.resizeChatBox(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onMouseUp (ev) {
|
||||||
|
if (!_converse.resizing || !api.settings.get('allow_dragresize')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ev.preventDefault();
|
||||||
|
const height = applyDragResistance(
|
||||||
|
_converse.resizing.chatbox.height,
|
||||||
|
_converse.resizing.chatbox.model.get('default_height')
|
||||||
|
);
|
||||||
|
const width = applyDragResistance(
|
||||||
|
_converse.resizing.chatbox.width,
|
||||||
|
_converse.resizing.chatbox.model.get('default_width')
|
||||||
|
);
|
||||||
|
if (api.connection.connected()) {
|
||||||
|
_converse.resizing.chatbox.model.save({ 'height': height });
|
||||||
|
_converse.resizing.chatbox.model.save({ 'width': width });
|
||||||
|
} else {
|
||||||
|
_converse.resizing.chatbox.model.set({ 'height': height });
|
||||||
|
_converse.resizing.chatbox.model.set({ 'width': width });
|
||||||
|
}
|
||||||
|
_converse.resizing = null;
|
||||||
|
}
|
@ -155,30 +155,6 @@ u.getOOBURLMarkup = function (_converse, url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies some resistance to `value` around the `default_value`.
|
|
||||||
* If value is close enough to `default_value`, then it is returned, otherwise
|
|
||||||
* `value` is returned.
|
|
||||||
* @method u#applyDragResistance
|
|
||||||
* @param { Integer } value
|
|
||||||
* @param { Integer } default_value
|
|
||||||
* @returns { Integer }
|
|
||||||
*/
|
|
||||||
u.applyDragResistance = function (value, default_value) {
|
|
||||||
if (value === undefined) {
|
|
||||||
return undefined;
|
|
||||||
} else if (default_value === undefined) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
const resistance = 10;
|
|
||||||
if ((value !== default_value) &&
|
|
||||||
(Math.abs(value- default_value) < resistance)) {
|
|
||||||
return default_value;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the height of the passed in DOM element,
|
* Return the height of the passed in DOM element,
|
||||||
* based on the heights of its children.
|
* based on the heights of its children.
|
||||||
|
Loading…
Reference in New Issue
Block a user