ponkotsu-md-editor 0.1.13 → 0.1.14

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad323ed8812d439732f1623eac62f59c34e461d872337209cc5690bfc4ddec33
4
- data.tar.gz: d7a0d46aff9ca2811b04eaf6002d68b9d61598ca29be64398882f2c5e9a9ed93
3
+ metadata.gz: fbb4edacc4c389fd1e7b470381b07861c0534c41b48248cfd41bcb295d3a032d
4
+ data.tar.gz: deff4f5d9c78cf564d348cf4efad276ac60867271ebd65ec4311e5bc0bf20915
5
5
  SHA512:
6
- metadata.gz: db0be49e3c8f4af5e164f4d3cba8718e5e93a193f9c9b3b2a5d50ba91d5ae250f8923194e1072e19406f1677b9b49436024a02ac6f511fefa9edc8b716ba8b58
7
- data.tar.gz: b395cfc3cdd5f23e493f18f736b29e521d864220443f1cd079e2c295cf646a070015f41ae27fc9625928c96fc56511d1fcfbff2c77a76ff59ce19bb35cfe6e20
6
+ metadata.gz: aeb2396debdb11aafc9bc81efcaf672f6d31c48768a446a8c4120466928c71ebc3650c3ab1394ef581474f9053d55214e1ef54bfe740a257e10e0bc6f438b353
7
+ data.tar.gz: d8fdfde9fb05016c27214e22d415cac9dbba2ca57e0655bcfa2f7bb0e37da8165f439ccf50ae4b475d8e161cb3799e445b2f88cbb5c84cbf2bf1b0692a67f4f8
@@ -30,6 +30,81 @@
30
30
 
31
31
  let isPreviewMode = false;
32
32
 
33
+ // contenteditable要素用の選択範囲取得・設定機能
34
+ function getContentEditableSelection(element) {
35
+ const selection = window.getSelection();
36
+ if (selection.rangeCount === 0) {
37
+ return { start: 0, end: 0, selectedText: '' };
38
+ }
39
+
40
+ const range = selection.getRangeAt(0);
41
+
42
+ // 要素内のテキスト全体を取得
43
+ const fullText = element.innerText || element.textContent || '';
44
+
45
+ // 選択範囲の開始位置を計算
46
+ const preRange = document.createRange();
47
+ preRange.selectNodeContents(element);
48
+ preRange.setEnd(range.startContainer, range.startOffset);
49
+ const start = (preRange.toString()).length;
50
+
51
+ // 選択範囲の終了位置を計算
52
+ const selectedText = range.toString();
53
+ const end = start + selectedText.length;
54
+
55
+ return {
56
+ start: start,
57
+ end: end,
58
+ selectedText: selectedText
59
+ };
60
+ }
61
+
62
+ function setContentEditableSelection(element, start, end) {
63
+ const textNodes = [];
64
+ const walker = document.createTreeWalker(
65
+ element,
66
+ NodeFilter.SHOW_TEXT,
67
+ null,
68
+ false
69
+ );
70
+
71
+ let node;
72
+ while (node = walker.nextNode()) {
73
+ textNodes.push(node);
74
+ }
75
+
76
+ let currentOffset = 0;
77
+ let startNode = null, startOffset = 0;
78
+ let endNode = null, endOffset = 0;
79
+
80
+ for (const textNode of textNodes) {
81
+ const nodeLength = textNode.textContent.length;
82
+
83
+ if (startNode === null && currentOffset + nodeLength >= start) {
84
+ startNode = textNode;
85
+ startOffset = start - currentOffset;
86
+ }
87
+
88
+ if (endNode === null && currentOffset + nodeLength >= end) {
89
+ endNode = textNode;
90
+ endOffset = end - currentOffset;
91
+ break;
92
+ }
93
+
94
+ currentOffset += nodeLength;
95
+ }
96
+
97
+ if (startNode && endNode) {
98
+ const range = document.createRange();
99
+ range.setStart(startNode, startOffset);
100
+ range.setEnd(endNode, endOffset);
101
+
102
+ const selection = window.getSelection();
103
+ selection.removeAllRanges();
104
+ selection.addRange(range);
105
+ }
106
+ }
107
+
33
108
  // Markdownテキスト挿入機能
34
109
  window.insertMarkdown = function(before, after) {
35
110
  after = after || '';
@@ -40,15 +115,40 @@
40
115
  }
41
116
 
42
117
  try {
43
- const start = textarea.selectionStart || 0;
44
- const end = textarea.selectionEnd || 0;
45
- const selectedText = textarea.innerText.substring(start, end);
118
+ // contenteditable要素かどうかを判定
119
+ const isContentEditable = textarea.contentEditable === 'true' ||
120
+ textarea.getAttribute('contenteditable') === 'true';
121
+
122
+ let start, end, selectedText;
123
+
124
+ if (isContentEditable) {
125
+ // contenteditable要素の場合
126
+ const selection = getContentEditableSelection(textarea);
127
+ start = selection.start;
128
+ end = selection.end;
129
+ selectedText = selection.selectedText;
130
+ } else {
131
+ // 通常のtextarea要素の場合
132
+ start = textarea.selectionStart || 0;
133
+ end = textarea.selectionEnd || 0;
134
+ selectedText = textarea.value.substring(start, end);
135
+ }
136
+
137
+ const fullText = isContentEditable ?
138
+ (textarea.innerText || textarea.textContent || '') :
139
+ textarea.value;
46
140
 
47
- const beforeText = textarea.innerText.substring(0, start);
48
- const afterText = textarea.innerText.substring(end);
141
+ const beforeText = fullText.substring(0, start);
142
+ const afterText = fullText.substring(end);
49
143
  const newText = before + selectedText + after;
50
144
 
51
- textarea.innerText = beforeText + newText + afterText;
145
+ const newFullText = beforeText + newText + afterText;
146
+
147
+ if (isContentEditable) {
148
+ textarea.innerText = newFullText;
149
+ } else {
150
+ textarea.value = newFullText;
151
+ }
52
152
 
53
153
  // カーソル位置調整
54
154
  const newCursorPos = selectedText.length > 0 ?
@@ -56,7 +156,10 @@
56
156
  start + before.length;
57
157
 
58
158
  textarea.focus();
59
- if (textarea.setSelectionRange) {
159
+
160
+ if (isContentEditable) {
161
+ setContentEditableSelection(textarea, newCursorPos, newCursorPos);
162
+ } else if (textarea.setSelectionRange) {
60
163
  textarea.setSelectionRange(newCursorPos, newCursorPos);
61
164
  }
62
165
 
@@ -70,7 +173,18 @@
70
173
 
71
174
  window.insertCode = function() {
72
175
  const textarea = document.getElementById('editor_content');
73
- const selectedText = textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
176
+
177
+ // contenteditable要素かどうかを判定
178
+ const isContentEditable = textarea.contentEditable === 'true' ||
179
+ textarea.getAttribute('contenteditable') === 'true';
180
+
181
+ let selectedText;
182
+ if (isContentEditable) {
183
+ const selection = getContentEditableSelection(textarea);
184
+ selectedText = selection.selectedText;
185
+ } else {
186
+ selectedText = textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
187
+ }
74
188
 
75
189
  if (selectedText.includes('\n')) {
76
190
  // 改行が含まれている場合はコードブロック
@@ -93,7 +207,14 @@
93
207
 
94
208
  if (isPreviewMode) {
95
209
  // プレビューモードに切り替え
96
- const markdownText = textarea.value || '';
210
+ // contenteditable要素かどうかを判定してテキストを取得
211
+ const isContentEditable = textarea.contentEditable === 'true' ||
212
+ textarea.getAttribute('contenteditable') === 'true';
213
+
214
+ const markdownText = isContentEditable ?
215
+ (textarea.innerText || textarea.textContent || '') :
216
+ (textarea.value || '');
217
+
97
218
  const htmlContent = convertMarkdownToHtml(markdownText);
98
219
 
99
220
  previewContainer.innerHTML = htmlContent;
@@ -676,25 +797,58 @@
676
797
  window.insertTextAtCursor = function(textarea, text) {
677
798
  if (!textarea || !text) return;
678
799
 
679
- const start = textarea.selectionStart;
680
- const end = textarea.selectionEnd;
681
- const currentValue = textarea.value;
800
+ // contenteditable要素かどうかを判定
801
+ const isContentEditable = textarea.contentEditable === 'true' ||
802
+ textarea.getAttribute('contenteditable') === 'true';
803
+
804
+ if (isContentEditable) {
805
+ // contenteditable要素の場合
806
+ const selection = getContentEditableSelection(textarea);
807
+ const start = selection.start;
808
+ const end = selection.end;
809
+ const currentValue = textarea.innerText || textarea.textContent || '';
810
+
811
+ // 挿入位置の前後に改行を追加(必要に応じて)
812
+ let insertText = text;
813
+ if (start > 0 && currentValue[start - 1] !== '\n') {
814
+ insertText = '\n' + insertText;
815
+ }
816
+ if (end < currentValue.length && currentValue[end] !== '\n') {
817
+ insertText = insertText + '\n';
818
+ }
682
819
 
683
- // 挿入位置の前後に改行を追加(必要に応じて)
684
- let insertText = text;
685
- if (start > 0 && currentValue[start - 1] !== '\n') {
686
- insertText = '\n' + insertText;
687
- }
688
- if (end < currentValue.length && currentValue[end] !== '\n') {
689
- insertText = insertText + '\n';
690
- }
820
+ const newValue = currentValue.substring(0, start) + insertText + currentValue.substring(end);
821
+ textarea.innerText = newValue;
822
+ textarea.focus();
823
+
824
+ const newCursorPos = start + insertText.length;
825
+ setContentEditableSelection(textarea, newCursorPos, newCursorPos);
826
+
827
+ // 入力イベントを発火
828
+ textarea.dispatchEvent(new Event('input', { bubbles: true }));
691
829
 
692
- textarea.value = currentValue.substring(0, start) + insertText + currentValue.substring(end);
693
- textarea.focus();
694
- textarea.selectionStart = textarea.selectionEnd = start + insertText.length;
830
+ } else {
831
+ // 通常のtextarea要素の場合
832
+ const start = textarea.selectionStart;
833
+ const end = textarea.selectionEnd;
834
+ const currentValue = textarea.value;
835
+
836
+ // 挿入位置の前後に改行を追加(必要に応じて)
837
+ let insertText = text;
838
+ if (start > 0 && currentValue[start - 1] !== '\n') {
839
+ insertText = '\n' + insertText;
840
+ }
841
+ if (end < currentValue.length && currentValue[end] !== '\n') {
842
+ insertText = insertText + '\n';
843
+ }
695
844
 
696
- // Railsのフォームバリデーション用にchangeイベントを発火
697
- textarea.dispatchEvent(new Event('change', { bubbles: true }));
845
+ textarea.value = currentValue.substring(0, start) + insertText + currentValue.substring(end);
846
+ textarea.focus();
847
+ textarea.selectionStart = textarea.selectionEnd = start + insertText.length;
848
+
849
+ // Railsのフォームバリデーション用にchangeイベントを発火
850
+ textarea.dispatchEvent(new Event('change', { bubbles: true }));
851
+ }
698
852
  }
699
853
 
700
854
  // 遅延実行のためのデバウンス関数
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PonkotsuMdEditor
4
- VERSION = "0.1.13"
4
+ VERSION = "0.1.14"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ponkotsu-md-editor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13
4
+ version: 0.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - dhq_boiler