ponkotsu-md-editor 0.1.10 → 0.1.11
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 +27 -122
- 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: f368e5ac8edd2f609cb8d806e1a9396468883cd9455ce681ede8f1e61d33278a
|
|
4
|
+
data.tar.gz: 3cf05435af1e6ddac2d45fffa72158cabf61f94387a1e67d9d0010098358ab12
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 06d90cf57121c150bba6cedfb5ad0e5077588177b0ed53dcccd9c00263a125386c90b2ad854fcdf952e0ea68bf456efaef232bef2ee0842249d046913eb970c6
|
|
7
|
+
data.tar.gz: 5d08cdf6a4b4226985a78b54eb12c3707a1c7c0dc2520559afeb9a3b06af5a2fadbb917888c4c1d02782a5c52d02c5a09f05f6b30ef6b5cc30abf49fb0a5d0f8
|
|
@@ -27,10 +27,6 @@
|
|
|
27
27
|
const textarea = getElement('.markdown-textarea');
|
|
28
28
|
const previewContainer = getElement('#markdownPreview');
|
|
29
29
|
const previewToggle = getElement('#previewToggle');
|
|
30
|
-
const titleField = getElement('#article_title');
|
|
31
|
-
const slugField = getElement('#article_slug');
|
|
32
|
-
const generateBtn = getElement('#generateSlugBtn');
|
|
33
|
-
const slugPreview = getElement('#slugPreview');
|
|
34
30
|
|
|
35
31
|
let isPreviewMode = false;
|
|
36
32
|
|
|
@@ -73,7 +69,7 @@
|
|
|
73
69
|
};
|
|
74
70
|
|
|
75
71
|
window.insertCode = function() {
|
|
76
|
-
const textarea = document.getElementById('
|
|
72
|
+
const textarea = document.getElementById('editor_content');
|
|
77
73
|
const selectedText = textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
|
|
78
74
|
|
|
79
75
|
if (selectedText.includes('\n')) {
|
|
@@ -648,16 +644,6 @@
|
|
|
648
644
|
}
|
|
649
645
|
};
|
|
650
646
|
|
|
651
|
-
// デバッグ用:サニタイズテスト
|
|
652
|
-
window.testSanitization = function() {
|
|
653
|
-
const testInput = `<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ニーアでも聞きながら作業しますかね。<a href="https://t.co/Ac9X8lEaZL">https://t.co/Ac9X8lEaZL</a></p>— ボイラー (@dhq_boiler) <a href="https://twitter.com/dhq_boiler/status/1942584009550409780?ref_src=twsrc%5Etfw">July 8, 2025</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>`;
|
|
654
|
-
|
|
655
|
-
const result = convertMarkdownToHtml(testInput);
|
|
656
|
-
console.log('Original:', testInput);
|
|
657
|
-
console.log('Converted:', result);
|
|
658
|
-
return result;
|
|
659
|
-
};
|
|
660
|
-
|
|
661
647
|
// Twitter埋め込み用のヘルパー関数
|
|
662
648
|
window.insertTwitterEmbed = function() {
|
|
663
649
|
const tweetUrl = prompt('TwitterのツイートURLを入力してください:');
|
|
@@ -669,7 +655,7 @@
|
|
|
669
655
|
return;
|
|
670
656
|
}
|
|
671
657
|
|
|
672
|
-
const textarea = document.getElementById('
|
|
658
|
+
const textarea = document.getElementById('editor_content');
|
|
673
659
|
if (!textarea) return;
|
|
674
660
|
|
|
675
661
|
// 簡単なTwitter埋め込みコードのテンプレート
|
|
@@ -686,6 +672,31 @@
|
|
|
686
672
|
alert('基本的なTwitter埋め込みを挿入しました。\n\n完全な埋め込みには、Twitter公式から生成されたコードを使用してください。');
|
|
687
673
|
};
|
|
688
674
|
|
|
675
|
+
// テキストエリアのカーソル位置にテキストを挿入
|
|
676
|
+
window.insertTextAtCursor = function(textarea, text) {
|
|
677
|
+
if (!textarea || !text) return;
|
|
678
|
+
|
|
679
|
+
const start = textarea.selectionStart;
|
|
680
|
+
const end = textarea.selectionEnd;
|
|
681
|
+
const currentValue = textarea.value;
|
|
682
|
+
|
|
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
|
+
}
|
|
691
|
+
|
|
692
|
+
textarea.value = currentValue.substring(0, start) + insertText + currentValue.substring(end);
|
|
693
|
+
textarea.focus();
|
|
694
|
+
textarea.selectionStart = textarea.selectionEnd = start + insertText.length;
|
|
695
|
+
|
|
696
|
+
// Railsのフォームバリデーション用にchangeイベントを発火
|
|
697
|
+
textarea.dispatchEvent(new Event('change', { bubbles: true }));
|
|
698
|
+
}
|
|
699
|
+
|
|
689
700
|
// 遅延実行のためのデバウンス関数
|
|
690
701
|
function debounce(func, wait) {
|
|
691
702
|
let timeout;
|
|
@@ -738,115 +749,9 @@
|
|
|
738
749
|
});
|
|
739
750
|
}
|
|
740
751
|
|
|
741
|
-
// フォームバリデーション
|
|
742
|
-
const form = getElement('.article-form');
|
|
743
|
-
if (form) {
|
|
744
|
-
form.addEventListener('submit', function(e) {
|
|
745
|
-
const title = titleField && titleField.value.trim();
|
|
746
|
-
const content = textarea && textarea.value.trim();
|
|
747
|
-
|
|
748
|
-
if (!title) {
|
|
749
|
-
e.preventDefault();
|
|
750
|
-
alert('タイトルを入力してください');
|
|
751
|
-
if (titleField) {
|
|
752
|
-
titleField.focus();
|
|
753
|
-
titleField.scrollIntoView({ behavior: 'smooth' });
|
|
754
|
-
}
|
|
755
|
-
return false;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
if (!content) {
|
|
759
|
-
e.preventDefault();
|
|
760
|
-
alert('本文を入力してください');
|
|
761
|
-
if (textarea) {
|
|
762
|
-
textarea.focus();
|
|
763
|
-
textarea.scrollIntoView({ behavior: 'smooth' });
|
|
764
|
-
}
|
|
765
|
-
return false;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
// スラッグが空の場合は最後の努力で生成
|
|
769
|
-
if (slugField && !slugField.value.trim() && title) {
|
|
770
|
-
e.preventDefault();
|
|
771
|
-
|
|
772
|
-
generateHighQualitySlug(title).then(slug => {
|
|
773
|
-
if (slug) {
|
|
774
|
-
slugField.value = slug;
|
|
775
|
-
form.submit(); // 再送信
|
|
776
|
-
} else {
|
|
777
|
-
alert('スラッグの生成に失敗しました。手動で入力してください。');
|
|
778
|
-
slugField.focus();
|
|
779
|
-
}
|
|
780
|
-
}).catch(error => {
|
|
781
|
-
console.error('Final slug generation failed:', error);
|
|
782
|
-
alert('スラッグの生成でエラーが発生しました。手動で入力してください。');
|
|
783
|
-
slugField.focus();
|
|
784
|
-
});
|
|
785
|
-
|
|
786
|
-
return false;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// スラッグの形式チェック
|
|
790
|
-
if (slugField && slugField.value.trim()) {
|
|
791
|
-
const slug = slugField.value.trim();
|
|
792
|
-
if (!/^[a-z0-9\-]+$/.test(slug)) {
|
|
793
|
-
e.preventDefault();
|
|
794
|
-
alert('スラッグは英小文字、数字、ハイフンのみ使用できます');
|
|
795
|
-
slugField.focus();
|
|
796
|
-
slugField.select();
|
|
797
|
-
return false;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
// リアルタイムバリデーション
|
|
804
|
-
if (slugField) {
|
|
805
|
-
slugField.addEventListener('blur', function() {
|
|
806
|
-
const slug = this.value.trim();
|
|
807
|
-
if (slug && !/^[a-z0-9\-]+$/.test(slug)) {
|
|
808
|
-
this.classList.add('is-invalid');
|
|
809
|
-
|
|
810
|
-
// エラーメッセージを表示
|
|
811
|
-
let errorDiv = this.parentNode.querySelector('.invalid-feedback');
|
|
812
|
-
if (!errorDiv) {
|
|
813
|
-
errorDiv = document.createElement('div');
|
|
814
|
-
errorDiv.className = 'invalid-feedback';
|
|
815
|
-
this.parentNode.appendChild(errorDiv);
|
|
816
|
-
}
|
|
817
|
-
errorDiv.textContent = '英小文字、数字、ハイフンのみ使用できます';
|
|
818
|
-
} else {
|
|
819
|
-
this.classList.remove('is-invalid');
|
|
820
|
-
const errorDiv = this.parentNode.querySelector('.invalid-feedback');
|
|
821
|
-
if (errorDiv) {
|
|
822
|
-
errorDiv.remove();
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
|
|
828
752
|
console.log('ponkotsu Markdown editor initialized successfully');
|
|
829
753
|
});
|
|
830
754
|
|
|
831
|
-
// ページ離脱確認
|
|
832
|
-
window.addEventListener('beforeunload', function(e) {
|
|
833
|
-
try {
|
|
834
|
-
const textarea = getElement('.markdown-textarea');
|
|
835
|
-
const titleField = getElement('#article_title');
|
|
836
|
-
|
|
837
|
-
const hasContent = (textarea && textarea.value.trim()) ||
|
|
838
|
-
(titleField && titleField.value.trim());
|
|
839
|
-
|
|
840
|
-
if (hasContent) {
|
|
841
|
-
const message = '編集中の内容が失われますがよろしいですか?';
|
|
842
|
-
e.returnValue = message;
|
|
843
|
-
return message;
|
|
844
|
-
}
|
|
845
|
-
} catch (error) {
|
|
846
|
-
console.error('Beforeunload error:', error);
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
|
|
850
755
|
// エラーハンドリングの強化
|
|
851
756
|
window.addEventListener('error', function(e) {
|
|
852
757
|
if (e.message.includes('markdown') || e.message.includes('slug')) {
|