Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit 12571c2

Browse files
sebgeelendmo-odoo
authored andcommitted
[ADD] Resizer: tool to allow easy editor resising
Add a small bar on the bottom of the editor that allow the user to resize the editor with drag and drop
1 parent 9a027b4 commit 12571c2

File tree

8 files changed

+202
-0
lines changed

8 files changed

+202
-0
lines changed

examples/resizable/index.html

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<html>
2+
<head>
3+
<title>Jabberwock Editor | resizable</title>
4+
<link rel="shortcut icon" href="#" />
5+
</head>
6+
<body style="font-family: sans-serif">
7+
<main>
8+
<h1 style="text-align: center;"> The Poem :</h1>
9+
<div style="border: 1px solid #bbb; margin: 10px 10%;">
10+
<section id="contentToEdit">content</section>
11+
</div>
12+
<br><br><br><br><br><br><br>
13+
</main>
14+
<!-- The following file is created by webpack in the config file -->
15+
<!-- The path generated is "/<filename>.js" -->
16+
<script type="text/javascript" src="resizable.js" charset="UTF-8"></script>
17+
</body>
18+
</html>

examples/resizable/resizable.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { BasicEditor } from '../../packages/bundle-basic-editor/BasicEditor';
2+
import { jabberwocky } from '../utils/jabberwocky';
3+
import '../utils/jabberwocky.css';
4+
import { DomLayout } from '../../packages/plugin-dom-layout/src/DomLayout';
5+
import { Resizer } from '../../packages/plugin-resizer/src/Resizer';
6+
7+
import '../utils/fontawesomeAssets';
8+
9+
const target = document.getElementById('contentToEdit');
10+
jabberwocky.init(target);
11+
12+
const editor = new BasicEditor({ editable: target });
13+
editor.configure(DomLayout, {
14+
location: [target, 'replace'],
15+
});
16+
17+
editor.load(Resizer);
18+
editor.start();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
jw-editor {
22
display: flex;
33
flex-direction: column;
4+
position: relative;
45
}

packages/bundle-basic-editor/basicLayout.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<jw-body><t t-zone="main"/></jw-body>
44
<jw-footer>
55
<t t-zone="status"/>
6+
<t t-zone="resizer"/>
67
</jw-footer>
78
<t-dialog>
89
<t t-zone="dialog"/>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
jw-resizer{
2+
display: block;
3+
height: 7px;
4+
background-color: #eee;
5+
border-top: 1px solid #999;
6+
text-align: center;
7+
width: 100%;
8+
line-height: 6px;
9+
position: absolute;
10+
bottom: 0;
11+
cursor: row-resize;
12+
}
13+
14+
jw-resizer::before {
15+
content: "☰";
16+
font-size: 6px;
17+
margin-top: 1px;
18+
display: inline-block;
19+
transform: scale(5,1);
20+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Loadables } from '../../core/src/JWEditor';
2+
import { JWPlugin } from '../../core/src/JWPlugin';
3+
import { DomLayout } from '../../plugin-dom-layout/src/DomLayout';
4+
import { Layout } from '../../plugin-layout/src/Layout';
5+
6+
import '../assets/Resizer.css';
7+
import { ResizerNode } from './ResizerNode';
8+
import { ResizerDomObjectRenderer } from './ResizerDomObjectRenderer';
9+
import { Renderer } from '../../plugin-renderer/src/Renderer';
10+
11+
export class Resizer<T = {}> extends JWPlugin<T> {
12+
static dependencies = [DomLayout];
13+
readonly loadables: Loadables<Layout & Renderer> = {
14+
renderers: [ResizerDomObjectRenderer],
15+
components: [
16+
{
17+
id: 'resizer',
18+
render: async (): Promise<ResizerNode[]> => {
19+
return [new ResizerNode()];
20+
},
21+
},
22+
],
23+
componentZones: [['resizer', ['resizer']]],
24+
};
25+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import {
2+
DomObject,
3+
DomObjectRenderingEngine,
4+
} from '../../plugin-renderer-dom-object/src/DomObjectRenderingEngine';
5+
import { ResizerNode } from './ResizerNode';
6+
import { AbstractRenderer } from '../../plugin-renderer/src/AbstractRenderer';
7+
import { Layout } from '../../plugin-layout/src/Layout';
8+
import { DomLayoutEngine } from '../../plugin-dom-layout/src/DomLayoutEngine';
9+
import { ZoneNode } from '../../plugin-layout/src/ZoneNode';
10+
11+
export class ResizerDomObjectRenderer extends AbstractRenderer<DomObject> {
12+
static id = DomObjectRenderingEngine.id;
13+
engine: DomObjectRenderingEngine;
14+
predicate = ResizerNode;
15+
16+
domEngine: DomLayoutEngine;
17+
targetToResize: HTMLElement;
18+
19+
async render(node: ResizerNode): Promise<DomObject> {
20+
const objectResizer: DomObject = {
21+
tag: 'JW-RESIZER',
22+
};
23+
// This should become obsolete when we refactor the resiser (see _initTargetToResize() comment).
24+
this.domEngine = this.engine.editor.plugins.get(Layout).engines.dom as DomLayoutEngine;
25+
26+
objectResizer.attach = (el: HTMLElement): void => {
27+
el.addEventListener('mousedown', this.startResize.bind(this));
28+
el.addEventListener('touchstart', this.startResize.bind(this));
29+
};
30+
return objectResizer;
31+
}
32+
33+
//--------------------------------------------------------------------------
34+
// Public
35+
//--------------------------------------------------------------------------
36+
/**
37+
* Drag the Resizer to change the editor size.
38+
*
39+
* @param {MouseEvent} event
40+
*/
41+
startResize(event: MouseEvent | TouchEvent): void {
42+
event.preventDefault();
43+
this._initTargetToResize();
44+
if (!this.targetToResize) return;
45+
46+
const startHeight = this.targetToResize.clientHeight;
47+
const startY: number =
48+
event instanceof MouseEvent ? event.pageY : event.targetTouches[0].pageY; // Y position of the mousedown
49+
50+
/**
51+
* Perform the resizing on every mouse mouvement.
52+
*
53+
* @param e
54+
*/
55+
const doResize = (e: MouseEvent | TouchEvent): void => {
56+
const currentY: number = e instanceof MouseEvent ? e.pageY : e.targetTouches[0].pageY;
57+
const offset: number = currentY - startY;
58+
this._resizeTargetHeight(startHeight + offset);
59+
};
60+
/**
61+
* Stop resizing on mouse up.
62+
*/
63+
const stopResize = (): void => {
64+
window.removeEventListener('mousemove', doResize, false);
65+
window.removeEventListener('mouseup', stopResize, false);
66+
window.removeEventListener('touchmove', doResize, false);
67+
window.removeEventListener('touchend', stopResize, false);
68+
};
69+
70+
window.addEventListener('mousemove', doResize);
71+
window.addEventListener('mouseup', stopResize);
72+
window.addEventListener('touchmove', doResize);
73+
window.addEventListener('touchend', stopResize);
74+
}
75+
76+
//--------------------------------------------------------------------------
77+
// Private
78+
//--------------------------------------------------------------------------
79+
/**
80+
* Discover the HTMLElement to resize and set it as a class property.
81+
*/
82+
_initTargetToResize(): void {
83+
// This way of HTMLElement discovery is far from ideal.
84+
// The Resizer should never be aware of the HTMLElement.
85+
//
86+
// TODO: We should change this to use a shared variable whose value would be listen to by another plugin.
87+
// The other plugin can then use the shared height value to change the height of his children element.
88+
//
89+
// Result: the resizer plugin will become agnostic of the HTMLElement afected by the resize.
90+
// Problem: We don't yet have a way to do this properly.
91+
if (this.targetToResize) return;
92+
93+
const mainZone = this.domEngine.root.descendants(
94+
node => node instanceof ZoneNode && node.managedZones.includes('main'),
95+
)[0];
96+
this.targetToResize = (this.domEngine.getDomNodes(
97+
mainZone,
98+
)[0] as HTMLElement)?.parentElement;
99+
100+
// Force the overflow on the targetElement.
101+
// Necesary to make the resizer works out of the box.
102+
this.targetToResize.style.overflow = 'auto';
103+
}
104+
/**
105+
* Change the height of the target HTMLElement.
106+
*
107+
* @param {number} height
108+
*/
109+
_resizeTargetHeight(height: number): void {
110+
height = Math.max(height, 50); // todo : implement a way to force the min-height with resizer parameters ?
111+
if (this.targetToResize) this.targetToResize.style.height = height + 'px';
112+
}
113+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { ContainerNode } from '../../core/src/VNodes/ContainerNode';
2+
3+
export class ResizerNode extends ContainerNode {
4+
editable = false;
5+
breakable = false;
6+
}

0 commit comments

Comments
 (0)