handsontable 14.0.0-next-caddcb8-20231120 → 14.0.0-next-6009c41-20231120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/base.js +2 -2
- package/base.mjs +2 -2
- package/dist/handsontable.css +2 -2
- package/dist/handsontable.full.css +2 -2
- package/dist/handsontable.full.js +1031 -1033
- package/dist/handsontable.full.min.css +2 -2
- package/dist/handsontable.full.min.js +5 -5
- package/dist/handsontable.js +1033 -1035
- package/dist/handsontable.min.css +2 -2
- package/dist/handsontable.min.js +12 -12
- package/editors/textEditor/textEditor.js +3 -36
- package/editors/textEditor/textEditor.mjs +3 -36
- package/helpers/mixed.js +1 -1
- package/helpers/mixed.mjs +1 -1
- package/package.json +1 -1
- package/utils/autoResize.js +204 -0
- package/utils/autoResize.mjs +200 -0
- package/3rdparty/autoResize/autoResize.js +0 -162
- package/3rdparty/autoResize/autoResize.mjs +0 -158
- package/3rdparty/autoResize/index.js +0 -5
- package/3rdparty/autoResize/index.mjs +0 -1
@@ -7,8 +7,7 @@ var _eventManager = _interopRequireDefault(require("../../eventManager"));
|
|
7
7
|
var _browser = require("../../helpers/browser");
|
8
8
|
var _element = require("../../helpers/dom/element");
|
9
9
|
var _number = require("../../helpers/number");
|
10
|
-
var
|
11
|
-
var _autoResize = require("../../3rdparty/autoResize");
|
10
|
+
var _autoResize = require("../../utils/autoResize");
|
12
11
|
var _mixed = require("../../helpers/mixed");
|
13
12
|
var _editorManager = require("../../editorManager");
|
14
13
|
var _baseEditor2 = require("../baseEditor/baseEditor");
|
@@ -51,7 +50,7 @@ class TextEditor extends _baseEditor.BaseEditor {
|
|
51
50
|
* @private
|
52
51
|
* @type {Function}
|
53
52
|
*/
|
54
|
-
_defineProperty(this, "autoResize", (0, _autoResize.
|
53
|
+
_defineProperty(this, "autoResize", (0, _autoResize.createInputElementResizer)(this.hot.rootDocument));
|
55
54
|
/**
|
56
55
|
* An TEXTAREA element.
|
57
56
|
*
|
@@ -117,9 +116,7 @@ class TextEditor extends _baseEditor.BaseEditor {
|
|
117
116
|
open() {
|
118
117
|
this.refreshDimensions(); // need it instantly, to prevent https://github.com/handsontable/handsontable/issues/348
|
119
118
|
this.showEditableElement();
|
120
|
-
|
121
|
-
shortcutManager.setActiveContextName('editor');
|
122
|
-
this.addHook('afterDocumentKeyDown', event => this.onAfterDocumentKeyDown(event));
|
119
|
+
this.hot.getShortcutManager().setActiveContextName('editor');
|
123
120
|
this.registerShortcuts();
|
124
121
|
}
|
125
122
|
|
@@ -134,7 +131,6 @@ class TextEditor extends _baseEditor.BaseEditor {
|
|
134
131
|
|
135
132
|
this.hideEditableElement();
|
136
133
|
this.unregisterShortcuts();
|
137
|
-
this.removeHooksByKey('afterDocumentKeyDown');
|
138
134
|
}
|
139
135
|
|
140
136
|
/**
|
@@ -437,22 +433,6 @@ class TextEditor extends _baseEditor.BaseEditor {
|
|
437
433
|
let [keyName] = _ref2;
|
438
434
|
(0, _caretPositioner.updateCaretPosition)(keyName, this.TEXTAREA);
|
439
435
|
}
|
440
|
-
}, {
|
441
|
-
keys: [['Control/Meta', 'Z']],
|
442
|
-
preventDefault: false,
|
443
|
-
callback: () => {
|
444
|
-
this.hot._registerTimeout(() => {
|
445
|
-
this.autoResize.resize();
|
446
|
-
}, 10);
|
447
|
-
}
|
448
|
-
}, {
|
449
|
-
keys: [['Control/Meta', 'Shift', 'Z']],
|
450
|
-
preventDefault: false,
|
451
|
-
callback: () => {
|
452
|
-
this.hot._registerTimeout(() => {
|
453
|
-
this.autoResize.resize();
|
454
|
-
}, 10);
|
455
|
-
}
|
456
436
|
}], contextConfig);
|
457
437
|
}
|
458
438
|
|
@@ -468,18 +448,5 @@ class TextEditor extends _baseEditor.BaseEditor {
|
|
468
448
|
editorContext.removeShortcutsByGroup(SHORTCUTS_GROUP);
|
469
449
|
editorContext.removeShortcutsByGroup(_baseEditor2.SHORTCUTS_GROUP_EDITOR);
|
470
450
|
}
|
471
|
-
|
472
|
-
/**
|
473
|
-
* OnAfterDocumentKeyDown callback.
|
474
|
-
*
|
475
|
-
* @private
|
476
|
-
* @param {KeyboardEvent} event The keyboard event object.
|
477
|
-
*/
|
478
|
-
onAfterDocumentKeyDown(event) {
|
479
|
-
const arrowKeyCodes = [_unicode.KEY_CODES.ARROW_UP, _unicode.KEY_CODES.ARROW_RIGHT, _unicode.KEY_CODES.ARROW_DOWN, _unicode.KEY_CODES.ARROW_LEFT];
|
480
|
-
if (arrowKeyCodes.indexOf(event.keyCode) === -1) {
|
481
|
-
this.autoResize.resize(String.fromCharCode(event.keyCode));
|
482
|
-
}
|
483
|
-
}
|
484
451
|
}
|
485
452
|
exports.TextEditor = TextEditor;
|
@@ -7,8 +7,7 @@ import EventManager from "../../eventManager.mjs";
|
|
7
7
|
import { isEdge, isIOS } from "../../helpers/browser.mjs";
|
8
8
|
import { addClass, getComputedStyle, isThisHotChild, setCaretPosition, hasClass, removeClass, setAttribute } from "../../helpers/dom/element.mjs";
|
9
9
|
import { rangeEach } from "../../helpers/number.mjs";
|
10
|
-
import {
|
11
|
-
import { autoResize as autoResizer } from "../../3rdparty/autoResize/index.mjs";
|
10
|
+
import { createInputElementResizer } from "../../utils/autoResize.mjs";
|
12
11
|
import { isDefined } from "../../helpers/mixed.mjs";
|
13
12
|
import { SHORTCUTS_GROUP_NAVIGATION } from "../../editorManager.mjs";
|
14
13
|
import { SHORTCUTS_GROUP_EDITOR } from "../baseEditor/baseEditor.mjs";
|
@@ -47,7 +46,7 @@ export class TextEditor extends BaseEditor {
|
|
47
46
|
* @private
|
48
47
|
* @type {Function}
|
49
48
|
*/
|
50
|
-
_defineProperty(this, "autoResize",
|
49
|
+
_defineProperty(this, "autoResize", createInputElementResizer(this.hot.rootDocument));
|
51
50
|
/**
|
52
51
|
* An TEXTAREA element.
|
53
52
|
*
|
@@ -113,9 +112,7 @@ export class TextEditor extends BaseEditor {
|
|
113
112
|
open() {
|
114
113
|
this.refreshDimensions(); // need it instantly, to prevent https://github.com/handsontable/handsontable/issues/348
|
115
114
|
this.showEditableElement();
|
116
|
-
|
117
|
-
shortcutManager.setActiveContextName('editor');
|
118
|
-
this.addHook('afterDocumentKeyDown', event => this.onAfterDocumentKeyDown(event));
|
115
|
+
this.hot.getShortcutManager().setActiveContextName('editor');
|
119
116
|
this.registerShortcuts();
|
120
117
|
}
|
121
118
|
|
@@ -130,7 +127,6 @@ export class TextEditor extends BaseEditor {
|
|
130
127
|
|
131
128
|
this.hideEditableElement();
|
132
129
|
this.unregisterShortcuts();
|
133
|
-
this.removeHooksByKey('afterDocumentKeyDown');
|
134
130
|
}
|
135
131
|
|
136
132
|
/**
|
@@ -433,22 +429,6 @@ export class TextEditor extends BaseEditor {
|
|
433
429
|
let [keyName] = _ref2;
|
434
430
|
updateCaretPosition(keyName, this.TEXTAREA);
|
435
431
|
}
|
436
|
-
}, {
|
437
|
-
keys: [['Control/Meta', 'Z']],
|
438
|
-
preventDefault: false,
|
439
|
-
callback: () => {
|
440
|
-
this.hot._registerTimeout(() => {
|
441
|
-
this.autoResize.resize();
|
442
|
-
}, 10);
|
443
|
-
}
|
444
|
-
}, {
|
445
|
-
keys: [['Control/Meta', 'Shift', 'Z']],
|
446
|
-
preventDefault: false,
|
447
|
-
callback: () => {
|
448
|
-
this.hot._registerTimeout(() => {
|
449
|
-
this.autoResize.resize();
|
450
|
-
}, 10);
|
451
|
-
}
|
452
432
|
}], contextConfig);
|
453
433
|
}
|
454
434
|
|
@@ -464,17 +444,4 @@ export class TextEditor extends BaseEditor {
|
|
464
444
|
editorContext.removeShortcutsByGroup(SHORTCUTS_GROUP);
|
465
445
|
editorContext.removeShortcutsByGroup(SHORTCUTS_GROUP_EDITOR);
|
466
446
|
}
|
467
|
-
|
468
|
-
/**
|
469
|
-
* OnAfterDocumentKeyDown callback.
|
470
|
-
*
|
471
|
-
* @private
|
472
|
-
* @param {KeyboardEvent} event The keyboard event object.
|
473
|
-
*/
|
474
|
-
onAfterDocumentKeyDown(event) {
|
475
|
-
const arrowKeyCodes = [KEY_CODES.ARROW_UP, KEY_CODES.ARROW_RIGHT, KEY_CODES.ARROW_DOWN, KEY_CODES.ARROW_LEFT];
|
476
|
-
if (arrowKeyCodes.indexOf(event.keyCode) === -1) {
|
477
|
-
this.autoResize.resize(String.fromCharCode(event.keyCode));
|
478
|
-
}
|
479
|
-
}
|
480
447
|
}
|
package/helpers/mixed.js
CHANGED
@@ -134,7 +134,7 @@ const domMessages = {
|
|
134
134
|
function _injectProductInfo(key, element) {
|
135
135
|
const hasValidType = !isEmpty(key);
|
136
136
|
const isNonCommercial = typeof key === 'string' && key.toLowerCase() === 'non-commercial-and-evaluation';
|
137
|
-
const hotVersion = "14.0.0-next-
|
137
|
+
const hotVersion = "14.0.0-next-6009c41-20231120";
|
138
138
|
let keyValidityDate;
|
139
139
|
let consoleMessageState = 'invalid';
|
140
140
|
let domMessageState = 'invalid';
|
package/helpers/mixed.mjs
CHANGED
@@ -124,7 +124,7 @@ const domMessages = {
|
|
124
124
|
export function _injectProductInfo(key, element) {
|
125
125
|
const hasValidType = !isEmpty(key);
|
126
126
|
const isNonCommercial = typeof key === 'string' && key.toLowerCase() === 'non-commercial-and-evaluation';
|
127
|
-
const hotVersion = "14.0.0-next-
|
127
|
+
const hotVersion = "14.0.0-next-6009c41-20231120";
|
128
128
|
let keyValidityDate;
|
129
129
|
let consoleMessageState = 'invalid';
|
130
130
|
let domMessageState = 'invalid';
|
package/package.json
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
"url": "https://github.com/handsontable/handsontable/issues"
|
11
11
|
},
|
12
12
|
"author": "Handsoncode <hello@handsontable.com>",
|
13
|
-
"version": "14.0.0-next-
|
13
|
+
"version": "14.0.0-next-6009c41-20231120",
|
14
14
|
"main": "index",
|
15
15
|
"module": "index.mjs",
|
16
16
|
"jsnext:main": "index.mjs",
|
@@ -0,0 +1,204 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
exports.__esModule = true;
|
4
|
+
exports.createInputElementResizer = createInputElementResizer;
|
5
|
+
/* eslint-disable jsdoc/require-description-complete-sentence */
|
6
|
+
/**
|
7
|
+
* autoResize - resizes a DOM element to the width and height of another DOM element
|
8
|
+
*
|
9
|
+
* Copyright 2014, Marcin Warpechowski
|
10
|
+
* Licensed under the MIT license
|
11
|
+
*/
|
12
|
+
/* eslint-enable jsdoc/require-description-complete-sentence */
|
13
|
+
/**
|
14
|
+
* Attaches an event listener to the given element.
|
15
|
+
*
|
16
|
+
* @param {HTMLElement} element The element to observe.
|
17
|
+
* @param {string} eventName The name of the event to listen for.
|
18
|
+
* @param {Function} handler The function to call when the event is triggered.
|
19
|
+
*/
|
20
|
+
function observe(element, eventName, handler) {
|
21
|
+
element.addEventListener(eventName, handler, false);
|
22
|
+
}
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Removes an event listener from an element.
|
26
|
+
*
|
27
|
+
* @param {HTMLElement} element The element to remove the event listener from.
|
28
|
+
* @param {string} eventName The name of the event to remove.
|
29
|
+
* @param {Function} handler The function to remove as a listener.
|
30
|
+
*/
|
31
|
+
function unObserve(element, eventName, handler) {
|
32
|
+
element.removeEventListener(eventName, handler, false);
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Returns the computed style of an element.
|
37
|
+
*
|
38
|
+
* @param {Element} element The element to get the computed style from.
|
39
|
+
* @returns {CSSStyleDeclaration} The computed style of the element.
|
40
|
+
*/
|
41
|
+
function getComputedStyle(element) {
|
42
|
+
return element.ownerDocument.defaultView.getComputedStyle(element);
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* @typedef InputElementResizerConfig
|
47
|
+
* @property {number} minWidth The minimum width of the element.
|
48
|
+
* @property {number} maxWidth The maximum width of the element.
|
49
|
+
* @property {number} minHeight The minimum height of the element.
|
50
|
+
* @property {number} maxHeight The maximum height of the element.
|
51
|
+
*/
|
52
|
+
/**
|
53
|
+
* @typedef InputElementResizer
|
54
|
+
* @property {function(HTMLElement, InputElementResizerConfig, boolean): void} init Initializes the resizer.
|
55
|
+
* @property {function(): void} resize Resizes the element.
|
56
|
+
* @property {function(): void} unObserve Removes the event listeners.
|
57
|
+
*/
|
58
|
+
/**
|
59
|
+
* Creates an input element resizer.
|
60
|
+
*
|
61
|
+
* @param {Document} ownerDocument The document to create the resizer for.
|
62
|
+
* @returns {InputElementResizer}
|
63
|
+
*/
|
64
|
+
function createInputElementResizer(ownerDocument) {
|
65
|
+
const defaults = {
|
66
|
+
minHeight: 200,
|
67
|
+
maxHeight: 300,
|
68
|
+
minWidth: 100,
|
69
|
+
maxWidth: 300
|
70
|
+
};
|
71
|
+
const body = ownerDocument.body;
|
72
|
+
const textHolder = ownerDocument.createTextNode('');
|
73
|
+
const textContainer = ownerDocument.createElement('span');
|
74
|
+
let observedElement;
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Resizes the element.
|
78
|
+
*/
|
79
|
+
function resize() {
|
80
|
+
textHolder.textContent = observedElement.value;
|
81
|
+
// Won't expand the element size for displaying body as for example, `grid`, `inline-grid` or `flex` with
|
82
|
+
// `flex-direction` set as `column`.
|
83
|
+
textContainer.style.position = 'absolute';
|
84
|
+
textContainer.style.fontSize = getComputedStyle(observedElement).fontSize;
|
85
|
+
textContainer.style.fontFamily = getComputedStyle(observedElement).fontFamily;
|
86
|
+
textContainer.style.whiteSpace = 'pre';
|
87
|
+
body.appendChild(textContainer);
|
88
|
+
const width = textContainer.clientWidth + 2;
|
89
|
+
body.removeChild(textContainer);
|
90
|
+
const elementStyle = observedElement.style;
|
91
|
+
elementStyle.height = `${defaults.minHeight}px`;
|
92
|
+
if (defaults.minWidth > width) {
|
93
|
+
elementStyle.width = `${defaults.minWidth}px`;
|
94
|
+
} else if (width > defaults.maxWidth) {
|
95
|
+
elementStyle.width = `${defaults.maxWidth}px`;
|
96
|
+
} else {
|
97
|
+
elementStyle.width = `${width}px`;
|
98
|
+
}
|
99
|
+
const scrollHeight = observedElement.scrollHeight ? observedElement.scrollHeight - 1 : 0;
|
100
|
+
if (defaults.minHeight > scrollHeight) {
|
101
|
+
elementStyle.height = `${defaults.minHeight}px`;
|
102
|
+
} else if (defaults.maxHeight < scrollHeight) {
|
103
|
+
elementStyle.height = `${defaults.maxHeight}px`;
|
104
|
+
elementStyle.overflowY = 'visible';
|
105
|
+
} else {
|
106
|
+
elementStyle.height = `${scrollHeight}px`;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* Resizes the element after a delay.
|
112
|
+
*/
|
113
|
+
function delayedResize() {
|
114
|
+
ownerDocument.defaultView.setTimeout(resize, 0);
|
115
|
+
}
|
116
|
+
|
117
|
+
/**
|
118
|
+
* Extends the default configuration.
|
119
|
+
*
|
120
|
+
* @param {InputElementResizerConfig} config The configuration to extend the defaults with.
|
121
|
+
*/
|
122
|
+
function extendDefaults(config) {
|
123
|
+
if (config && config.minHeight) {
|
124
|
+
if (config.minHeight === 'inherit') {
|
125
|
+
defaults.minHeight = observedElement.clientHeight;
|
126
|
+
} else {
|
127
|
+
const minHeight = parseInt(config.minHeight, 10);
|
128
|
+
if (!isNaN(minHeight)) {
|
129
|
+
defaults.minHeight = minHeight;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
133
|
+
if (config && config.maxHeight) {
|
134
|
+
if (config.maxHeight === 'inherit') {
|
135
|
+
defaults.maxHeight = observedElement.clientHeight;
|
136
|
+
} else {
|
137
|
+
const maxHeight = parseInt(config.maxHeight, 10);
|
138
|
+
if (!isNaN(maxHeight)) {
|
139
|
+
defaults.maxHeight = maxHeight;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
if (config && config.minWidth) {
|
144
|
+
if (config.minWidth === 'inherit') {
|
145
|
+
defaults.minWidth = observedElement.clientWidth;
|
146
|
+
} else {
|
147
|
+
const minWidth = parseInt(config.minWidth, 10);
|
148
|
+
if (!isNaN(minWidth)) {
|
149
|
+
defaults.minWidth = minWidth;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
if (config && config.maxWidth) {
|
154
|
+
if (config.maxWidth === 'inherit') {
|
155
|
+
defaults.maxWidth = observedElement.clientWidth;
|
156
|
+
} else {
|
157
|
+
const maxWidth = parseInt(config.maxWidth, 10);
|
158
|
+
if (!isNaN(maxWidth)) {
|
159
|
+
defaults.maxWidth = maxWidth;
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
if (!textContainer.firstChild) {
|
164
|
+
textContainer.className = 'autoResize';
|
165
|
+
textContainer.style.display = 'inline-block';
|
166
|
+
textContainer.appendChild(textHolder);
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
/**
|
171
|
+
* Initializes the resizer.
|
172
|
+
*
|
173
|
+
* @param {HTMLElement} elementToObserve The element to observe.
|
174
|
+
* @param {InputElementResizerConfig} config The configuration to extend the defaults with.
|
175
|
+
* @param {boolean} [doObserve=false] Whether to observe the element and resize it on every input change.
|
176
|
+
*/
|
177
|
+
function init(elementToObserve, config) {
|
178
|
+
let doObserve = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
179
|
+
observedElement = elementToObserve;
|
180
|
+
extendDefaults(config);
|
181
|
+
if (observedElement.nodeName === 'TEXTAREA') {
|
182
|
+
observedElement.style.resize = 'none';
|
183
|
+
observedElement.style.overflowY = '';
|
184
|
+
observedElement.style.height = `${defaults.minHeight}px`;
|
185
|
+
observedElement.style.minWidth = `${defaults.minWidth}px`;
|
186
|
+
observedElement.style.maxWidth = `${defaults.maxWidth}px`;
|
187
|
+
observedElement.style.overflowY = 'hidden';
|
188
|
+
}
|
189
|
+
if (doObserve) {
|
190
|
+
observe(observedElement, 'input', resize);
|
191
|
+
// the keydown event is necessary for undo stack to work properly
|
192
|
+
observe(observedElement, 'keydown', delayedResize);
|
193
|
+
}
|
194
|
+
resize();
|
195
|
+
}
|
196
|
+
return {
|
197
|
+
init,
|
198
|
+
resize,
|
199
|
+
unObserve() {
|
200
|
+
unObserve(observedElement, 'input', resize);
|
201
|
+
unObserve(observedElement, 'keydown', delayedResize);
|
202
|
+
}
|
203
|
+
};
|
204
|
+
}
|
@@ -0,0 +1,200 @@
|
|
1
|
+
/* eslint-disable jsdoc/require-description-complete-sentence */
|
2
|
+
/**
|
3
|
+
* autoResize - resizes a DOM element to the width and height of another DOM element
|
4
|
+
*
|
5
|
+
* Copyright 2014, Marcin Warpechowski
|
6
|
+
* Licensed under the MIT license
|
7
|
+
*/
|
8
|
+
/* eslint-enable jsdoc/require-description-complete-sentence */
|
9
|
+
/**
|
10
|
+
* Attaches an event listener to the given element.
|
11
|
+
*
|
12
|
+
* @param {HTMLElement} element The element to observe.
|
13
|
+
* @param {string} eventName The name of the event to listen for.
|
14
|
+
* @param {Function} handler The function to call when the event is triggered.
|
15
|
+
*/
|
16
|
+
function observe(element, eventName, handler) {
|
17
|
+
element.addEventListener(eventName, handler, false);
|
18
|
+
}
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Removes an event listener from an element.
|
22
|
+
*
|
23
|
+
* @param {HTMLElement} element The element to remove the event listener from.
|
24
|
+
* @param {string} eventName The name of the event to remove.
|
25
|
+
* @param {Function} handler The function to remove as a listener.
|
26
|
+
*/
|
27
|
+
function unObserve(element, eventName, handler) {
|
28
|
+
element.removeEventListener(eventName, handler, false);
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Returns the computed style of an element.
|
33
|
+
*
|
34
|
+
* @param {Element} element The element to get the computed style from.
|
35
|
+
* @returns {CSSStyleDeclaration} The computed style of the element.
|
36
|
+
*/
|
37
|
+
function getComputedStyle(element) {
|
38
|
+
return element.ownerDocument.defaultView.getComputedStyle(element);
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* @typedef InputElementResizerConfig
|
43
|
+
* @property {number} minWidth The minimum width of the element.
|
44
|
+
* @property {number} maxWidth The maximum width of the element.
|
45
|
+
* @property {number} minHeight The minimum height of the element.
|
46
|
+
* @property {number} maxHeight The maximum height of the element.
|
47
|
+
*/
|
48
|
+
/**
|
49
|
+
* @typedef InputElementResizer
|
50
|
+
* @property {function(HTMLElement, InputElementResizerConfig, boolean): void} init Initializes the resizer.
|
51
|
+
* @property {function(): void} resize Resizes the element.
|
52
|
+
* @property {function(): void} unObserve Removes the event listeners.
|
53
|
+
*/
|
54
|
+
/**
|
55
|
+
* Creates an input element resizer.
|
56
|
+
*
|
57
|
+
* @param {Document} ownerDocument The document to create the resizer for.
|
58
|
+
* @returns {InputElementResizer}
|
59
|
+
*/
|
60
|
+
export function createInputElementResizer(ownerDocument) {
|
61
|
+
const defaults = {
|
62
|
+
minHeight: 200,
|
63
|
+
maxHeight: 300,
|
64
|
+
minWidth: 100,
|
65
|
+
maxWidth: 300
|
66
|
+
};
|
67
|
+
const body = ownerDocument.body;
|
68
|
+
const textHolder = ownerDocument.createTextNode('');
|
69
|
+
const textContainer = ownerDocument.createElement('span');
|
70
|
+
let observedElement;
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Resizes the element.
|
74
|
+
*/
|
75
|
+
function resize() {
|
76
|
+
textHolder.textContent = observedElement.value;
|
77
|
+
// Won't expand the element size for displaying body as for example, `grid`, `inline-grid` or `flex` with
|
78
|
+
// `flex-direction` set as `column`.
|
79
|
+
textContainer.style.position = 'absolute';
|
80
|
+
textContainer.style.fontSize = getComputedStyle(observedElement).fontSize;
|
81
|
+
textContainer.style.fontFamily = getComputedStyle(observedElement).fontFamily;
|
82
|
+
textContainer.style.whiteSpace = 'pre';
|
83
|
+
body.appendChild(textContainer);
|
84
|
+
const width = textContainer.clientWidth + 2;
|
85
|
+
body.removeChild(textContainer);
|
86
|
+
const elementStyle = observedElement.style;
|
87
|
+
elementStyle.height = `${defaults.minHeight}px`;
|
88
|
+
if (defaults.minWidth > width) {
|
89
|
+
elementStyle.width = `${defaults.minWidth}px`;
|
90
|
+
} else if (width > defaults.maxWidth) {
|
91
|
+
elementStyle.width = `${defaults.maxWidth}px`;
|
92
|
+
} else {
|
93
|
+
elementStyle.width = `${width}px`;
|
94
|
+
}
|
95
|
+
const scrollHeight = observedElement.scrollHeight ? observedElement.scrollHeight - 1 : 0;
|
96
|
+
if (defaults.minHeight > scrollHeight) {
|
97
|
+
elementStyle.height = `${defaults.minHeight}px`;
|
98
|
+
} else if (defaults.maxHeight < scrollHeight) {
|
99
|
+
elementStyle.height = `${defaults.maxHeight}px`;
|
100
|
+
elementStyle.overflowY = 'visible';
|
101
|
+
} else {
|
102
|
+
elementStyle.height = `${scrollHeight}px`;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Resizes the element after a delay.
|
108
|
+
*/
|
109
|
+
function delayedResize() {
|
110
|
+
ownerDocument.defaultView.setTimeout(resize, 0);
|
111
|
+
}
|
112
|
+
|
113
|
+
/**
|
114
|
+
* Extends the default configuration.
|
115
|
+
*
|
116
|
+
* @param {InputElementResizerConfig} config The configuration to extend the defaults with.
|
117
|
+
*/
|
118
|
+
function extendDefaults(config) {
|
119
|
+
if (config && config.minHeight) {
|
120
|
+
if (config.minHeight === 'inherit') {
|
121
|
+
defaults.minHeight = observedElement.clientHeight;
|
122
|
+
} else {
|
123
|
+
const minHeight = parseInt(config.minHeight, 10);
|
124
|
+
if (!isNaN(minHeight)) {
|
125
|
+
defaults.minHeight = minHeight;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
if (config && config.maxHeight) {
|
130
|
+
if (config.maxHeight === 'inherit') {
|
131
|
+
defaults.maxHeight = observedElement.clientHeight;
|
132
|
+
} else {
|
133
|
+
const maxHeight = parseInt(config.maxHeight, 10);
|
134
|
+
if (!isNaN(maxHeight)) {
|
135
|
+
defaults.maxHeight = maxHeight;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
}
|
139
|
+
if (config && config.minWidth) {
|
140
|
+
if (config.minWidth === 'inherit') {
|
141
|
+
defaults.minWidth = observedElement.clientWidth;
|
142
|
+
} else {
|
143
|
+
const minWidth = parseInt(config.minWidth, 10);
|
144
|
+
if (!isNaN(minWidth)) {
|
145
|
+
defaults.minWidth = minWidth;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
if (config && config.maxWidth) {
|
150
|
+
if (config.maxWidth === 'inherit') {
|
151
|
+
defaults.maxWidth = observedElement.clientWidth;
|
152
|
+
} else {
|
153
|
+
const maxWidth = parseInt(config.maxWidth, 10);
|
154
|
+
if (!isNaN(maxWidth)) {
|
155
|
+
defaults.maxWidth = maxWidth;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
if (!textContainer.firstChild) {
|
160
|
+
textContainer.className = 'autoResize';
|
161
|
+
textContainer.style.display = 'inline-block';
|
162
|
+
textContainer.appendChild(textHolder);
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
/**
|
167
|
+
* Initializes the resizer.
|
168
|
+
*
|
169
|
+
* @param {HTMLElement} elementToObserve The element to observe.
|
170
|
+
* @param {InputElementResizerConfig} config The configuration to extend the defaults with.
|
171
|
+
* @param {boolean} [doObserve=false] Whether to observe the element and resize it on every input change.
|
172
|
+
*/
|
173
|
+
function init(elementToObserve, config) {
|
174
|
+
let doObserve = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
175
|
+
observedElement = elementToObserve;
|
176
|
+
extendDefaults(config);
|
177
|
+
if (observedElement.nodeName === 'TEXTAREA') {
|
178
|
+
observedElement.style.resize = 'none';
|
179
|
+
observedElement.style.overflowY = '';
|
180
|
+
observedElement.style.height = `${defaults.minHeight}px`;
|
181
|
+
observedElement.style.minWidth = `${defaults.minWidth}px`;
|
182
|
+
observedElement.style.maxWidth = `${defaults.maxWidth}px`;
|
183
|
+
observedElement.style.overflowY = 'hidden';
|
184
|
+
}
|
185
|
+
if (doObserve) {
|
186
|
+
observe(observedElement, 'input', resize);
|
187
|
+
// the keydown event is necessary for undo stack to work properly
|
188
|
+
observe(observedElement, 'keydown', delayedResize);
|
189
|
+
}
|
190
|
+
resize();
|
191
|
+
}
|
192
|
+
return {
|
193
|
+
init,
|
194
|
+
resize,
|
195
|
+
unObserve() {
|
196
|
+
unObserve(observedElement, 'input', resize);
|
197
|
+
unObserve(observedElement, 'keydown', delayedResize);
|
198
|
+
}
|
199
|
+
};
|
200
|
+
}
|