Last modified by Super Admin on 2026/04/05 18:59

From version 1.1 Icon
edited by Super Admin
on 2026/03/05 22:05
Change comment: There is no comment for this version
To version Icon 4.1 Icon
edited by Super Admin
on 2026/03/06 00:42
Change comment: There is no comment for this version

Summary

Details

Icon Page properties
Content
... ... @@ -228,6 +228,10 @@
228 228   ## 役割バッジ
229 229   #if($authorUserRole == 'student')
230 230   <span class="badge badge-role-student"><svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 10l-10-5L2 10l10 5 10-5z"/><path d="M6 12v5c0 1.66 2.69 3 6 3s6-1.34 6-3v-5"/></svg> 生徒</span>
231 + #set($authorIsOfficer = $!lastAuthorDoc.getValue('isOfficer'))
232 + #if($authorIsOfficer == 'true')
233 + <span class="badge badge-role-officer"><svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> 役員</span>
234 + #end
231 231   #elseif($authorUserRole == 'teacher')
232 232   <span class="badge badge-role-teacher"><svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 016.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z"/></svg> 教員</span>
233 233   #elseif($authorUserRole == 'graduate')
... ... @@ -649,6 +649,26 @@
649 649   #set($postGrade = $!post.getValue('authorGrade'))
650 650   #set($postSchoolCode = $!post.getValue('authorSchoolCode'))
651 651   #set($postDate = $post.getValue('createdDate'))
656 + ## 論理削除チェック
657 + #set($postDeleted = $!post.getValue('deleted'))
658 + #if($postDeleted == 1 || $postDeleted == '1')
659 + #if($viewerAccountType == 'admin')
660 + <div class="thread-post thread-post-deleted" style="opacity:0.5;border:2px dashed #9ca3af;">
661 + <div style="padding:10px 16px;font-size:0.85em;color:var(--text-light);">
662 + <svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
663 + <strong>投稿者により削除済み</strong>($!post.getValue('deletedAt'))
664 + <div style="margin-top:4px;font-size:0.92em;color:var(--text-mid);">$escapetool.xml($!postContent)</div>
665 + </div>
666 + </div>
667 + #else
668 + <div class="thread-post thread-post-deleted" style="opacity:0.6;">
669 + <div style="padding:12px 16px;font-size:0.88em;color:var(--text-light);font-style:italic;">
670 + <svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
671 + この投稿は削除されました
672 + </div>
673 + </div>
674 + #end
675 + #else
652 652   ## 通報による非表示チェック
653 653   #set($postHidden = $!post.getValue('hidden'))
654 654   #if($postHidden == 1 || $postHidden == '1')
... ... @@ -724,6 +724,10 @@
724 724   #end
725 725   #if($postUserRole == 'student')
726 726   <span class="badge badge-role-student" style="font-size:0.75em;padding:1px 7px;"><svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 10l-10-5L2 10l10 5 10-5z"/><path d="M6 12v5c0 1.66 2.69 3 6 3s6-1.34 6-3v-5"/></svg> 生徒</span>
751 + #set($postIsOfficer = $!post.getValue('authorIsOfficer'))
752 + #if($postIsOfficer == 'true')
753 + <span class="badge badge-role-officer" style="font-size:0.75em;padding:1px 7px;"><svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> 役員</span>
754 + #end
727 727   #elseif($postUserRole == 'teacher')
728 728   <span class="badge badge-role-teacher" style="font-size:0.75em;padding:1px 7px;"><svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 016.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z"/></svg> 教員</span>
729 729   #elseif($postUserRole == 'graduate')
... ... @@ -734,6 +734,10 @@
734 734   #end
735 735   </span>
736 736   <span class="thread-post-date">$!postDate</span>
765 + #set($postEdited = $!post.getValue('edited'))
766 + #if($postEdited == 1 || $postEdited == '1')
767 + <span class="post-edited-label">(編集済み)</span>
768 + #end
737 737   </div>
738 738   <div class="thread-post-body">
739 739   $escapetool.xml($!postContent)
... ... @@ -815,10 +815,26 @@
815 815   #end
816 816   </div>
817 817   #end
850 + ## 編集・削除ボタン(投稿者本人 or 管理者)
851 + #set($postAuthorRef = $!post.getValue('authorRef'))
852 + #set($postObjNumED = $post.number)
853 + #if($xcontext.user == $postAuthorRef || $viewerAccountType == 'admin')
854 + <div class="post-edit-actions" style="margin-top:6px;display:flex;gap:8px;">
855 + #if($xcontext.user == $postAuthorRef)
856 + <button type="button" class="btn-post-edit" onclick="openEditPost(this, '${doc.fullName}', $postObjNumED, '$escapetool.javascript($!postContent)')" title="この投稿を編集">
857 + <svg style="width:13px;height:13px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg> 編集
858 + </button>
859 + #end
860 + <button type="button" class="btn-post-delete" onclick="confirmDeletePost('${doc.fullName}', $postObjNumED, '${services.csrf.getToken()}')" title="この投稿を削除">
861 + <svg style="width:13px;height:13px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg> 削除
862 + </button>
863 + </div>
864 + #end
818 818   </div>
819 819   </div>
820 820   #end## /canViewPost
821 821   #end## /postHidden
869 + #end## /postDeleted
822 822   #end
823 823  
824 824   #if($xcontext.user != "XWiki.XWikiGuest")
... ... @@ -977,6 +977,71 @@
977 977   card.classList.toggle('collapsed');
978 978   card.classList.remove('mobile-collapse');
979 979  }
1028 +
1029 +// 投稿の編集(インライン編集フォームを開く)
1030 +function openEditPost(btn, schoolPage, postObjNum, currentContent) {
1031 + var postEl = btn.closest('.thread-post');
1032 + if (!postEl) return;
1033 + // 既存の編集フォームがあれば閉じる
1034 + var existing = postEl.querySelector('.post-edit-form');
1035 + if (existing) { existing.remove(); return; }
1036 + var bodyEl = postEl.querySelector('.thread-post-body');
1037 + if (!bodyEl) return;
1038 + var form = document.createElement('div');
1039 + form.className = 'post-edit-form';
1040 + form.innerHTML = '<textarea id="editContent_' + postObjNum + '">' + currentContent.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') + '</textarea>' +
1041 + '<div class="post-edit-form-actions">' +
1042 + '<button type="button" class="btn-cancel-edit" onclick="this.closest(\'.post-edit-form\').remove()">キャンセル</button>' +
1043 + '<button type="button" class="btn-save" onclick="saveEditPost(\'' + schoolPage + '\', ' + postObjNum + ')">保存</button>' +
1044 + '</div>';
1045 + bodyEl.parentNode.insertBefore(form, bodyEl.nextSibling);
1046 + form.querySelector('textarea').focus();
1047 +}
1048 +
1049 +// 投稿の編集を保存
1050 +function saveEditPost(schoolPage, postObjNum) {
1051 + var textarea = document.getElementById('editContent_' + postObjNum);
1052 + if (!textarea) return;
1053 + var newContent = textarea.value.trim();
1054 + if (!newContent) { alert('投稿内容を入力してください'); return; }
1055 + var csrfEl = document.querySelector('input[name="form_token"]');
1056 + var csrfToken = csrfEl ? csrfEl.value : '';
1057 + var xhr = new XMLHttpRequest();
1058 + xhr.open('GET', '/xwiki/bin/view/SeitokaiCode/EditPost?outputSyntax=plain&schoolPage=' + encodeURIComponent(schoolPage) + '&postObj=' + postObjNum + '&newContent=' + encodeURIComponent(newContent) + '&form_token=' + encodeURIComponent(csrfToken), true);
1059 + xhr.onload = function() {
1060 + try {
1061 + var res = JSON.parse(xhr.responseText);
1062 + if (res.success) {
1063 + showToast('投稿を更新しました', 'success');
1064 + setTimeout(function() { location.reload(); }, 800);
1065 + } else {
1066 + alert('編集に失敗しました: ' + (res.error || ''));
1067 + }
1068 + } catch(e) { alert('編集に失敗しました'); }
1069 + };
1070 + xhr.onerror = function() { alert('通信エラーが発生しました'); };
1071 + xhr.send();
1072 +}
1073 +
1074 +// 投稿の削除(確認ダイアログ付き)
1075 +function confirmDeletePost(schoolPage, postObjNum, token) {
1076 + if (!confirm('この投稿を削除しますか?\\n削除後は「この投稿は削除されました」と表示されます。')) return;
1077 + var xhr = new XMLHttpRequest();
1078 + xhr.open('GET', '/xwiki/bin/view/SeitokaiCode/DeletePost?outputSyntax=plain&schoolPage=' + encodeURIComponent(schoolPage) + '&postObj=' + postObjNum + '&form_token=' + encodeURIComponent(token), true);
1079 + xhr.onload = function() {
1080 + try {
1081 + var res = JSON.parse(xhr.responseText);
1082 + if (res.success) {
1083 + showToast('投稿を削除しました', 'success');
1084 + setTimeout(function() { location.reload(); }, 800);
1085 + } else {
1086 + alert('削除に失敗しました: ' + (res.error || ''));
1087 + }
1088 + } catch(e) { alert('削除に失敗しました'); }
1089 + };
1090 + xhr.onerror = function() { alert('通信エラーが発生しました'); };
1091 + xhr.send();
1092 +}
980 980  </script>
981 981  {{/html}}
982 982  {{/velocity}}