@zzish/math-rich-input 0.1.53 → 0.1.54
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/dist/index.js +89 -27
- package/dist/standalone.js +1 -1
- package/package.json +1 -1
- package/src/MathRichInput.jsx +90 -30
- package/src/mathRichInputHelper.js +9 -0
package/dist/index.js
CHANGED
|
@@ -21963,6 +21963,15 @@ function plainTextOffsetToGlobalOffset(editableDiv, plainTextOffset) {
|
|
|
21963
21963
|
return Math.min(plainTextOffset, plainText.length);
|
|
21964
21964
|
}
|
|
21965
21965
|
|
|
21966
|
+
/**
|
|
21967
|
+
* The character used to mark a position in text while content is being rewritten.
|
|
21968
|
+
*
|
|
21969
|
+
* Exported so a caller can tell whether a mark was actually placed. `insertCharacterBeforeMarks` warns
|
|
21970
|
+
* and returns its input UNCHANGED when there is no mark, which reads as success at the call site — the
|
|
21971
|
+
* value comes back looking valid with the inserted text silently missing.
|
|
21972
|
+
*/
|
|
21973
|
+
var SELECTION_MARK = MARK$1;
|
|
21974
|
+
|
|
21966
21975
|
var MIME_TYPE_PLAIN_TEXT = "text/plain";
|
|
21967
21976
|
var MIME_TYPE_HTML = "text/html";
|
|
21968
21977
|
var MIME_TYPE_TEX = "application/x-tex";
|
|
@@ -23342,29 +23351,18 @@ var MathRichInput = /*#__PURE__*/function (_React$Component) {
|
|
|
23342
23351
|
var pasteHtml = clipboardData.getData("text/html");
|
|
23343
23352
|
var pasteText = clipboardData.getData("text/plain");
|
|
23344
23353
|
|
|
23345
|
-
|
|
23346
|
-
|
|
23347
|
-
|
|
23348
|
-
|
|
23349
|
-
|
|
23350
|
-
|
|
23351
|
-
|
|
23352
|
-
|
|
23353
|
-
|
|
23354
|
-
|
|
23355
|
-
|
|
23356
|
-
|
|
23357
|
-
// Read the caret BEFORE, so there is something to fall back on, and AGAIN after the delete.
|
|
23358
|
-
var paramsBeforeDelete = _this2._getRangeParams();
|
|
23359
|
-
var selection = window.getSelection();
|
|
23360
|
-
if (selection && selection.rangeCount > 0) {
|
|
23361
|
-
selection.deleteFromDocument();
|
|
23362
|
-
}
|
|
23363
|
-
|
|
23364
|
-
// The caret AFTER the delete is the one that counts: `rangeParams` is a node index, and the delete
|
|
23365
|
-
// removed the very nodes it counts. The pre-delete value is kept only as a fallback — bailing out
|
|
23366
|
-
// here having already emptied the selection is how a paste turns into a deletion.
|
|
23367
|
-
var rangeParams = _this2._getRangeParams() || paramsBeforeDelete;
|
|
23354
|
+
/*
|
|
23355
|
+
* The caret is read BEFORE the selection is removed, and that order is deliberate.
|
|
23356
|
+
*
|
|
23357
|
+
* Reading it afterwards looks more correct — `deleteFromDocument()` removes the very nodes the
|
|
23358
|
+
* index counts — and it was tried, on the theory that a stale index was why pasting over a
|
|
23359
|
+
* selection emptied the field. It was not: the field emptied because React never wrote the
|
|
23360
|
+
* content back (see `reconcileEditableDomWithRender`), and the reordering was left in on a theory
|
|
23361
|
+
* that had already been disproved. In a host whose field holds unwrapped text rather than a `<p>`,
|
|
23362
|
+
* the emptied div yields a caret that `elementToMarkedRawText` cannot mark at all — no mark, so the
|
|
23363
|
+
* pasted text is inserted nowhere and the paste becomes a deletion.
|
|
23364
|
+
*/
|
|
23365
|
+
var rangeParams = _this2._getRangeParams();
|
|
23368
23366
|
if (!rangeParams) {
|
|
23369
23367
|
console.warn("Could not get range params for paste");
|
|
23370
23368
|
return;
|
|
@@ -23372,6 +23370,12 @@ var MathRichInput = /*#__PURE__*/function (_React$Component) {
|
|
|
23372
23370
|
|
|
23373
23371
|
// Store old range params for cursor positioning (like equation editor)
|
|
23374
23372
|
_this2.setOldRangeParams(rangeParams);
|
|
23373
|
+
|
|
23374
|
+
// Clear any existing selection
|
|
23375
|
+
var selection = window.getSelection();
|
|
23376
|
+
if (selection && selection.rangeCount > 0) {
|
|
23377
|
+
selection.deleteFromDocument();
|
|
23378
|
+
}
|
|
23375
23379
|
var finalText = "";
|
|
23376
23380
|
var finalMimeType = _this2.props.mimeType || "text/html";
|
|
23377
23381
|
var hasMathContent = false;
|
|
@@ -23468,12 +23472,70 @@ var MathRichInput = /*#__PURE__*/function (_React$Component) {
|
|
|
23468
23472
|
|
|
23469
23473
|
// Use the component's insert mechanism to handle paste properly
|
|
23470
23474
|
if (finalText) {
|
|
23471
|
-
|
|
23472
|
-
|
|
23473
|
-
|
|
23475
|
+
/*
|
|
23476
|
+
* WHERE TO PUT THE PASTED TEXT, found in the document rather than by index.
|
|
23477
|
+
*
|
|
23478
|
+
* `elementToMarkedRawText` marks ONE position — a node and an offset — and the selection has to
|
|
23479
|
+
* be gone from the document before that position means anything. It was, and then the position
|
|
23480
|
+
* was looked up by INDEX, which is where every version of this went wrong: an index read before
|
|
23481
|
+
* the delete counts nodes the delete then removes, and an index read after it does not resolve in
|
|
23482
|
+
* a field whose content is unwrapped text. Either way `_findNodeWithIndex` returns nothing, no
|
|
23483
|
+
* mark is placed, `insertCharacterBeforeMarks` warns "Start: -1" and returns the text UNCHANGED —
|
|
23484
|
+
* so the pasted words go nowhere, and what the teacher sees is their field emptied.
|
|
23485
|
+
*
|
|
23486
|
+
* The browser's own selection is the answer: after `deleteFromDocument()` it is left collapsed at
|
|
23487
|
+
* exactly the point where the pasted text belongs, in a node that exists by construction. The
|
|
23488
|
+
* index lookup stays as a fallback for the case where the selection has gone elsewhere.
|
|
23489
|
+
*/
|
|
23490
|
+
var live = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
|
|
23491
|
+
var liveNode = live && _this2.editableDiv.contains(live.startContainer) ? live.startContainer : null;
|
|
23492
|
+
var currentNode = liveNode !== null ? liveNode : _this2._findNodeWithIndex(rangeParams.startNodeIndex);
|
|
23493
|
+
var currentOffset = liveNode !== null ? live.startOffset : rangeParams.startOffset;
|
|
23494
|
+
var markedText = elementToMarkedRawText(_this2.editableDiv, currentNode, currentOffset, _this2.enableHtml());
|
|
23495
|
+
|
|
23496
|
+
/*
|
|
23497
|
+
* A FIELD WITH NOTHING LEFT IN IT NEEDS NO MARK.
|
|
23498
|
+
*
|
|
23499
|
+
* Marking only works on a TEXT node, and an emptied field has none: the browser leaves the caret
|
|
23500
|
+
* in the element itself, so `elementToMarkedRawText` has nothing to mark and returns text with no
|
|
23501
|
+
* mark in it. `insertCharacterBeforeMarks` then warns and hands back its input UNCHANGED, which
|
|
23502
|
+
* reads as success — the value comes out valid with the pasted words missing, and the teacher
|
|
23503
|
+
* watches their field empty itself.
|
|
23504
|
+
*
|
|
23505
|
+
* But an empty field after the delete says something exact: the selection covered everything, so
|
|
23506
|
+
* the result of the paste IS the pasted text. Nothing needs to be worked out. This is the
|
|
23507
|
+
* select-all-and-paste that every report of this bug has been.
|
|
23508
|
+
*/
|
|
23509
|
+
var remainingText = _this2.editableDiv.textContent.split(SMALL_SPACE).join("").trim();
|
|
23510
|
+
var fieldIsEmpty = remainingText === "" && _this2.editableDiv.querySelector(".katex") === null;
|
|
23511
|
+
var marked = markedText.indexOf(SELECTION_MARK) !== -1;
|
|
23512
|
+
|
|
23513
|
+
/*
|
|
23514
|
+
* NOTHING IS BETTER THAN DESTRUCTION.
|
|
23515
|
+
*
|
|
23516
|
+
* No mark and content still standing means the caret cannot be located inside text that must be
|
|
23517
|
+
* kept. Carrying on would write a value with the pasted text missing over a field whose selection
|
|
23518
|
+
* has already been removed from the document — a paste that performs a deletion. Stopping leaves
|
|
23519
|
+
* `props.value` untouched and `reconcileEditableDomWithRender` puts the document back from it:
|
|
23520
|
+
* the paste does nothing, which is a disappointment rather than a loss.
|
|
23521
|
+
*/
|
|
23522
|
+
if (!marked && !fieldIsEmpty) {
|
|
23523
|
+
console.warn("[math-rich-input] paste found nowhere to insert; the field is left as it was", {
|
|
23524
|
+
rangeParams: rangeParams,
|
|
23525
|
+
hadLiveSelection: liveNode !== null
|
|
23526
|
+
});
|
|
23527
|
+
queueMicrotask(function () {
|
|
23528
|
+
try {
|
|
23529
|
+
_this2.reconcileEditableDomWithRender(true);
|
|
23530
|
+
} catch (error) {
|
|
23531
|
+
console.error(error);
|
|
23532
|
+
}
|
|
23533
|
+
});
|
|
23534
|
+
return;
|
|
23535
|
+
}
|
|
23474
23536
|
|
|
23475
23537
|
// Insert the new content at the marked position
|
|
23476
|
-
var newRawText = removeMarks(insertCharacterBeforeMarks(markedText, finalText));
|
|
23538
|
+
var newRawText = marked ? removeMarks(insertCharacterBeforeMarks(markedText, finalText)) : finalText;
|
|
23477
23539
|
// Convert any remaining \[...\] LaTeX expressions to <math>...</math> format
|
|
23478
23540
|
// This ensures consistency when paste adds <math> tags alongside existing \[...\] expressions
|
|
23479
23541
|
if (_this2.enableMath()) {
|