ponkotsu-md-editor 0.2.16 → 0.2.18
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/markdown_editor.js +59 -20
- data/lib/ponkotsu/md/editor/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0cee3f1cda79e611392ecd15c3f373a0e65de3ae4895c875878c47108a265ab8
|
|
4
|
+
data.tar.gz: 194fb5f55df7e26a535a1209303e0316bc3d107f1635a1ec077782ea77c6b451
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 313668a4f9c9d78b212ee0c28413f0854fa1e4656137bb2b6f2397b201e131f3e413536f786daf2c00acba0719108b1c5b4ce296017367fab3c26b30b4431340
|
|
7
|
+
data.tar.gz: 166ddd5ecd7ad645305069a5c3649e5b949ae82eaacf99eef700a187f8a56c8195f5dbdce668d7897733acb3047d18968a1b3d29dd04d860346a93f4ab60ae58
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
(function() {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
// Debounce function for delayed execution
|
|
5
|
+
function debounce(func, wait) {
|
|
6
|
+
let timeout;
|
|
7
|
+
return function executedFunction(...args) {
|
|
8
|
+
const later = () => {
|
|
9
|
+
clearTimeout(timeout);
|
|
10
|
+
func(...args);
|
|
11
|
+
};
|
|
12
|
+
clearTimeout(timeout);
|
|
13
|
+
timeout = setTimeout(later, wait);
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
4
17
|
// Safe DOM element retrieval
|
|
5
18
|
function getElement(selector) {
|
|
6
19
|
try {
|
|
@@ -23,7 +36,7 @@
|
|
|
23
36
|
const syncToHidden = () => {
|
|
24
37
|
hiddenField.value = (textarea.innerText || '').replaceAll('\u00A0', ' ');
|
|
25
38
|
};
|
|
26
|
-
textarea.addEventListener('input', syncToHidden);
|
|
39
|
+
textarea.addEventListener('input', debounce(syncToHidden, 150));
|
|
27
40
|
textarea.addEventListener('blur', syncToHidden);
|
|
28
41
|
// 初期化時にも同期
|
|
29
42
|
syncToHidden();
|
|
@@ -42,7 +55,7 @@
|
|
|
42
55
|
updatePlaceholderVisibility();
|
|
43
56
|
|
|
44
57
|
// 入力時にプレースホルダの表示/非表示を制御
|
|
45
|
-
textarea.addEventListener('input', updatePlaceholderVisibility);
|
|
58
|
+
textarea.addEventListener('input', debounce(updatePlaceholderVisibility, 150));
|
|
46
59
|
textarea.addEventListener('blur', updatePlaceholderVisibility);
|
|
47
60
|
}
|
|
48
61
|
} else {
|
|
@@ -86,20 +99,44 @@
|
|
|
86
99
|
beforeEndRange.setEnd(range.endContainer, range.endOffset);
|
|
87
100
|
let endPos = beforeEndRange.toString().length;
|
|
88
101
|
|
|
89
|
-
// --- 再スキャンで<br>と改行の取りこぼしを防ぐ ---
|
|
90
102
|
function scanOffset(pos) {
|
|
103
|
+
// キャッシュを追加
|
|
104
|
+
if (this._scanOffsetCache && this._scanOffsetCache.pos === pos) {
|
|
105
|
+
return this._scanOffsetCache.result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// HTML全体を一度だけ取得(これは良い改善)
|
|
109
|
+
const fullHTML = textarea.innerHTML;
|
|
110
|
+
const fullText = textarea.innerText;
|
|
111
|
+
|
|
91
112
|
let offset = pos;
|
|
92
113
|
let lastAdded = -1;
|
|
93
|
-
|
|
94
|
-
|
|
114
|
+
let iterations = 0;
|
|
115
|
+
const MAX_ITERATIONS = 100; // より安全な上限
|
|
116
|
+
|
|
117
|
+
while (iterations < MAX_ITERATIONS) {
|
|
118
|
+
const htmlUpTo = fullHTML.substring(0, offset);
|
|
119
|
+
const textUpTo = fullText.substring(0, offset);
|
|
120
|
+
|
|
121
|
+
// 元の正規表現を維持(安全性優先)
|
|
95
122
|
const brCount = (htmlUpTo.match(/<br\s*\/?>(?![\w\W]*<)/g) || []).length;
|
|
96
|
-
const textUpTo = textarea.innerText.substring(0, offset);
|
|
97
123
|
const nlCount = (textUpTo.match(/\n/g) || []).length;
|
|
124
|
+
|
|
98
125
|
const added = brCount + nlCount;
|
|
99
126
|
if (added === lastAdded) break;
|
|
127
|
+
|
|
100
128
|
offset = pos + added;
|
|
101
129
|
lastAdded = added;
|
|
130
|
+
iterations++;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (iterations >= MAX_ITERATIONS) {
|
|
134
|
+
console.warn('scanOffset: Maximum iterations reached, possible infinite loop');
|
|
102
135
|
}
|
|
136
|
+
|
|
137
|
+
// 結果をキャッシュ
|
|
138
|
+
this._scanOffsetCache = { pos: pos, result: offset };
|
|
139
|
+
|
|
103
140
|
return offset;
|
|
104
141
|
}
|
|
105
142
|
startPos = scanOffset(startPos);
|
|
@@ -117,7 +154,7 @@
|
|
|
117
154
|
caretPosition.end = textarea.selectionEnd;
|
|
118
155
|
}
|
|
119
156
|
};
|
|
120
|
-
textarea.addEventListener('input', saveCaretPosition);
|
|
157
|
+
textarea.addEventListener('input', debounce(saveCaretPosition, 100));
|
|
121
158
|
textarea.addEventListener('keyup', saveCaretPosition);
|
|
122
159
|
textarea.addEventListener('click', saveCaretPosition);
|
|
123
160
|
}
|
|
@@ -692,7 +729,16 @@
|
|
|
692
729
|
}
|
|
693
730
|
}
|
|
694
731
|
|
|
732
|
+
const analyzeHtmlCache = new Map();
|
|
733
|
+
|
|
695
734
|
function analyzeHtml(target, isCountEmptyDiv = false) {
|
|
735
|
+
|
|
736
|
+
const cacheKey = `${target}_${isCountEmptyDiv}`;
|
|
737
|
+
|
|
738
|
+
if (analyzeHtmlCache.has(cacheKey)) {
|
|
739
|
+
return analyzeHtmlCache.get(cacheKey);
|
|
740
|
+
}
|
|
741
|
+
|
|
696
742
|
let lines = [];
|
|
697
743
|
let remain = target;
|
|
698
744
|
|
|
@@ -758,6 +804,12 @@
|
|
|
758
804
|
}
|
|
759
805
|
}
|
|
760
806
|
|
|
807
|
+
if (analyzeHtmlCache.size > 100) {
|
|
808
|
+
const firstKey = analyzeHtmlCache.keys().next().value;
|
|
809
|
+
analyzeHtmlCache.delete(firstKey);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
analyzeHtmlCache.set(cacheKey, lines);
|
|
761
813
|
return lines;
|
|
762
814
|
}
|
|
763
815
|
|
|
@@ -1975,19 +2027,6 @@
|
|
|
1975
2027
|
}
|
|
1976
2028
|
}
|
|
1977
2029
|
|
|
1978
|
-
// Debounce function for delayed execution
|
|
1979
|
-
function debounce(func, wait) {
|
|
1980
|
-
let timeout;
|
|
1981
|
-
return function executedFunction(...args) {
|
|
1982
|
-
const later = () => {
|
|
1983
|
-
clearTimeout(timeout);
|
|
1984
|
-
func(...args);
|
|
1985
|
-
};
|
|
1986
|
-
clearTimeout(timeout);
|
|
1987
|
-
timeout = setTimeout(later, wait);
|
|
1988
|
-
};
|
|
1989
|
-
}
|
|
1990
|
-
|
|
1991
2030
|
// Keyboard shortcuts
|
|
1992
2031
|
if (textarea) {
|
|
1993
2032
|
textarea.addEventListener('keydown', function(e) {
|