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 6.1 Icon
edited by Super Admin
on 2026/03/06 15:39
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')
... ... @@ -245,7 +245,7 @@
245 245   #elseif($authorUserStatus == 'transferred')
246 246   <span class="badge badge-status-transferred"><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="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/></svg> 転校済み</span>
247 247   #end
248 - <span class="badge-info">最終編集: $escapetool.xml($authorDisplayName) ($xwiki.formatDate($doc.date, "yyyy/MM/dd"))</span>
252 + <span class="badge-info">最終編集: $!escapetool.xml($authorDisplayName) ($xwiki.formatDate($doc.date, "yyyy/MM/dd"))</span>
249 249  </div>
250 250  {{/html}}
251 251  
... ... @@ -256,20 +256,20 @@
256 256   <div class="school-info-card mobile-collapse" id="card-basic-info">
257 257   <h2 onclick="toggleInfoCard('card-basic-info')"><span><svg class="ico" style="width:1.1em;height:1.1em;vertical-align:-0.15em;" 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><span class="collapse-toggle"><span class="collapse-label-open">たたむ</span><span class="collapse-label-closed">開く</span> <span class="collapse-arrow">▼</span></span></h2>
258 258   <table class="wiki-table school-info-table">
259 - <tr><th>学校コード</th><td>$escapetool.xml($!schoolCode)</td></tr>
260 - <tr><th>学校名</th><td>$escapetool.xml($!schoolName)</td></tr>
261 - <tr><th>所在地</th><td>$escapetool.xml($!prefecture) #if($city && $city != '')$escapetool.xml($city)#end</td></tr>
263 + <tr><th>学校コード</th><td>$!escapetool.xml($!schoolCode)</td></tr>
264 + <tr><th>学校名</th><td>$!escapetool.xml($!schoolName)</td></tr>
265 + <tr><th>所在地</th><td>$!escapetool.xml($!prefecture) #if($city && $city != '')$!escapetool.xml($city)#end</td></tr>
262 262   <tr><th>学級数・生徒数</th><td>#if($classCount && $classCount != '')${classCount}学級#end #if($studentCount && $studentCount != '')/ 約${studentCount}名#end</td></tr>
263 - <tr><th>共学・別学</th><td>$escapetool.xml($!coeducation)</td></tr>
264 - <tr><th>設置者</th><td>$escapetool.xml($!establishment)</td></tr>
265 - <tr><th>学校種</th><td>$escapetool.xml($!schoolLevel)</td></tr>
266 - <tr><th>課程</th><td>$escapetool.xml($!schoolSystem)</td></tr>
267 - <tr><th>公式サイト</th><td>#if($website && $website != '')<a href="$escapetool.xml($website)" target="_blank" rel="noopener">$escapetool.xml($website)</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
267 + <tr><th>共学・別学</th><td>$!escapetool.xml($!coeducation)</td></tr>
268 + <tr><th>設置者</th><td>$!escapetool.xml($!establishment)</td></tr>
269 + <tr><th>学校種</th><td>$!escapetool.xml($!schoolLevel)</td></tr>
270 + <tr><th>課程</th><td>$!escapetool.xml($!schoolSystem)</td></tr>
271 + <tr><th>公式サイト</th><td>#if($website && $website != '')<a href="$!escapetool.xml($website)" target="_blank" rel="noopener">$!escapetool.xml($website)</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
268 268   </table>
269 269   #set($infoEditDate = $!doc.getValue('lastInfoEditedDate'))
270 270   #set($infoEditBy = $!doc.getValue('lastInfoEditedBy'))
271 271   #if($infoEditDate && $infoEditDate != '')
272 - <div class="info-last-updated"><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="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> 基本情報の最終更新: $escapetool.xml($infoEditBy) — $escapetool.xml($infoEditDate)</div>
276 + <div class="info-last-updated"><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="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> 基本情報の最終更新: $!escapetool.xml($infoEditBy) — $!escapetool.xml($infoEditDate)</div>
273 273   #end
274 274   </div>
275 275  
... ... @@ -276,12 +276,12 @@
276 276   <div class="school-info-card mobile-collapse" id="card-contact">
277 277   <h2 onclick="toggleInfoCard('card-contact')"><span><svg class="ico" style="width:1.1em;height:1.1em;vertical-align:-0.15em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 16.92z"/></svg> 連絡先・SNS</span><span class="collapse-toggle"><span class="collapse-label-open">たたむ</span><span class="collapse-label-closed">開く</span> <span class="collapse-arrow">▼</span></span></h2>
278 278   <table class="wiki-table school-info-table">
279 - <tr><th>問い合わせ先</th><td>#if($contactInfo && $contactInfo != '')$escapetool.xml($contactInfo)#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
280 - <tr><th>生徒会Web</th><td>#if($seitokaiWebsite && $seitokaiWebsite != '')<a href="$escapetool.xml($seitokaiWebsite)" target="_blank" rel="noopener"><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"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg> $escapetool.xml($seitokaiWebsite)</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
281 - <tr><th>X (Twitter)</th><td>#if($seitokaiTwitter && $seitokaiTwitter != '')<a href="https://x.com/$escapetool.url($seitokaiTwitter)" target="_blank" rel="noopener">𝕏 @$escapetool.xml($seitokaiTwitter)</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
282 - <tr><th>Instagram</th><td>#if($seitokaiInstagram && $seitokaiInstagram != '')<a href="https://instagram.com/$escapetool.url($seitokaiInstagram)" target="_blank" rel="noopener"><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="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg> @$escapetool.xml($seitokaiInstagram)</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
283 - <tr><th>YouTube</th><td>#if($seitokaiYoutube && $seitokaiYoutube != '')<a href="$escapetool.xml($seitokaiYoutube)" target="_blank" rel="noopener"><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"><polygon points="5 3 19 12 5 21 5 3"/></svg> YouTubeチャンネル</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
284 - <tr><th>その他SNS</th><td>#if($seitokaiOtherSns && $seitokaiOtherSns != '')$escapetool.xml($seitokaiOtherSns)#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
283 + <tr><th>問い合わせ先</th><td>#if($contactInfo && $contactInfo != '')$!escapetool.xml($contactInfo)#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
284 + <tr><th>生徒会Web</th><td>#if($seitokaiWebsite && $seitokaiWebsite != '')<a href="$!escapetool.xml($seitokaiWebsite)" target="_blank" rel="noopener"><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"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg> $!escapetool.xml($seitokaiWebsite)</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
285 + <tr><th>X (Twitter)</th><td>#if($seitokaiTwitter && $seitokaiTwitter != '')<a href="https://x.com/$!escapetool.url($seitokaiTwitter)" target="_blank" rel="noopener">𝕏 @$!escapetool.xml($seitokaiTwitter)</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
286 + <tr><th>Instagram</th><td>#if($seitokaiInstagram && $seitokaiInstagram != '')<a href="https://instagram.com/$!escapetool.url($seitokaiInstagram)" target="_blank" rel="noopener"><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="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg> @$!escapetool.xml($seitokaiInstagram)</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
287 + <tr><th>YouTube</th><td>#if($seitokaiYoutube && $seitokaiYoutube != '')<a href="$!escapetool.xml($seitokaiYoutube)" target="_blank" rel="noopener"><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"><polygon points="5 3 19 12 5 21 5 3"/></svg> YouTubeチャンネル</a>#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
288 + <tr><th>その他SNS</th><td>#if($seitokaiOtherSns && $seitokaiOtherSns != '')$!escapetool.xml($seitokaiOtherSns)#else<span style="color:#9ca3af;">未登録</span>#end</td></tr>
285 285   </table>
286 286   </div>
287 287  </div>
... ... @@ -311,7 +311,7 @@
311 311   #if($orgChartImage && $orgChartImage != '')
312 312   <div style="margin-bottom:12px;"><img src="$doc.getAttachmentURL($orgChartImage)" alt="組織図" style="max-width:100%; border-radius:8px;" /></div>
313 313   #end
314 - #if($orgChart && $orgChart != '')$escapetool.xml($orgChart)#end
318 + #if($orgChart && $orgChart != '')$!escapetool.xml($orgChart)#end
315 315   </div>
316 316  </div>
317 317   #else
... ... @@ -329,12 +329,12 @@
329 329   <div class="tag-container">
330 330   #set($daIdx = 1)
331 331   #foreach($da in $dailyActivities.split(","))
332 - <span class="tag tag-accent">${daIdx}. $escapetool.xml($da.trim())</span>
336 + <span class="tag tag-accent">${daIdx}. $!escapetool.xml($da.trim())</span>
333 333   #set($daIdx = $daIdx + 1)
334 334   #end
335 335   </div>
336 336   #if($dailyActivitiesNote && $dailyActivitiesNote.trim() != '')
337 - <div class="free-note">$escapetool.xml($dailyActivitiesNote)</div>
341 + <div class="free-note">$!escapetool.xml($dailyActivitiesNote)</div>
338 338   #end
339 339   </div>
340 340   </div>
... ... @@ -346,16 +346,16 @@
346 346   <div class="card-inner">
347 347   <div class="info-row">
348 348   <span class="info-label">役員選挙</span>
349 - <span class="info-value">$escapetool.xml($!electionExists)</span>
353 + <span class="info-value">$!escapetool.xml($!electionExists)</span>
350 350   </div>
351 351   #if($electionType && $electionType != '')
352 352   <div class="info-row">
353 353   <span class="info-label">直近の選挙方式</span>
354 - <span class="info-value">$escapetool.xml($!electionType)</span>
358 + <span class="info-value">$!escapetool.xml($!electionType)</span>
355 355   </div>
356 356   #end
357 357   #if($electionNote && $electionNote.trim() != '')
358 - <div class="free-note">$escapetool.xml($electionNote)</div>
362 + <div class="free-note">$!escapetool.xml($electionNote)</div>
359 359   #end
360 360   </div>
361 361   </div>
... ... @@ -369,10 +369,10 @@
369 369   <div class="card-inner">
370 370   <div class="info-row">
371 371   <span class="info-label">役員定例会の頻度</span>
372 - <span class="info-value">$escapetool.xml($!meetingFrequency)</span>
376 + <span class="info-value">$!escapetool.xml($!meetingFrequency)</span>
373 373   </div>
374 374   #if($regularActivitiesNote && $regularActivitiesNote.trim() != '')
375 - <div class="free-note">$escapetool.xml($regularActivitiesNote)</div>
379 + <div class="free-note">$!escapetool.xml($regularActivitiesNote)</div>
376 376   #end
377 377   </div>
378 378   </div>
... ... @@ -396,7 +396,7 @@
396 396   <span class="info-value">
397 397   <div class="selection-display">
398 398   #foreach($bp in $budgetProcess.split(","))
399 - <span class="selection-item">$escapetool.xml($bp.trim())</span>
403 + <span class="selection-item">$!escapetool.xml($bp.trim())</span>
400 400   #end
401 401   </div>
402 402   </span>
... ... @@ -405,13 +405,13 @@
405 405   #if($studentFee && $studentFee != '')
406 406   <div class="info-row">
407 407   <span class="info-label">生徒会費(年額)</span>
408 - <span class="info-value">$escapetool.xml($!studentFee)</span>
412 + <span class="info-value">$!escapetool.xml($!studentFee)</span>
409 409   </div>
410 410   #end
411 411   #if($budgetScale && $budgetScale != '')
412 412   <div class="info-row">
413 413   <span class="info-label">予算規模</span>
414 - <span class="info-value">$escapetool.xml($!budgetScale)</span>
418 + <span class="info-value">$!escapetool.xml($!budgetScale)</span>
415 415   </div>
416 416   #end
417 417   #if($budgetAllocation && $budgetAllocation != '')
... ... @@ -420,7 +420,7 @@
420 420   <span class="info-value">
421 421   <div class="selection-display">
422 422   #foreach($ba in $budgetAllocation.split(","))
423 - <span class="selection-item">$escapetool.xml($ba.trim())</span>
427 + <span class="selection-item">$!escapetool.xml($ba.trim())</span>
424 424   #end
425 425   </div>
426 426   </span>
... ... @@ -427,7 +427,7 @@
427 427   </div>
428 428   #end
429 429   #if($budgetNote && $budgetNote.trim() != '')
430 - <div class="free-note">$escapetool.xml($budgetNote)</div>
434 + <div class="free-note">$!escapetool.xml($budgetNote)</div>
431 431   #end
432 432   </div>
433 433   </div>
... ... @@ -450,7 +450,7 @@
450 450   <div class="card-inner">
451 451   <div class="info-row">
452 452   <span class="info-label">見直しの有無(3年以内)</span>
453 - <span class="info-value"><span class="tag tag-primary" style="font-size:0.9em;">$escapetool.xml($!ruleReviewStatus)</span></span>
457 + <span class="info-value"><span class="tag tag-primary" style="font-size:0.9em;">$!escapetool.xml($!ruleReviewStatus)</span></span>
454 454   </div>
455 455   #if($ruleReviewContent && $ruleReviewContent != '')
456 456   <div class="info-row">
... ... @@ -458,7 +458,7 @@
458 458   <span class="info-value">
459 459   <div class="selection-display">
460 460   #foreach($rc in $ruleReviewContent.split(","))
461 - <span class="selection-item">$escapetool.xml($rc.trim())</span>
465 + <span class="selection-item">$!escapetool.xml($rc.trim())</span>
462 462   #end
463 463   </div>
464 464   </span>
... ... @@ -470,7 +470,7 @@
470 470   <span class="info-value">
471 471   <div class="selection-display">
472 472   #foreach($rp in $ruleReviewProposer.split(","))
473 - <span class="selection-item">$escapetool.xml($rp.trim())</span>
477 + <span class="selection-item">$!escapetool.xml($rp.trim())</span>
474 474   #end
475 475   </div>
476 476   </span>
... ... @@ -482,7 +482,7 @@
482 482   <span class="info-value">
483 483   <div class="selection-display">
484 484   #foreach($ri in $ruleReviewImplementer.split(","))
485 - <span class="selection-item">$escapetool.xml($ri.trim())</span>
489 + <span class="selection-item">$!escapetool.xml($ri.trim())</span>
486 486   #end
487 487   </div>
488 488   </span>
... ... @@ -491,7 +491,7 @@
491 491   #if($ruleReviewSystem && $ruleReviewSystem != '')
492 492   <div class="info-row">
493 493   <span class="info-label">見直しの仕組み</span>
494 - <span class="info-value">$escapetool.xml($!ruleReviewSystem)</span>
498 + <span class="info-value">$!escapetool.xml($!ruleReviewSystem)</span>
495 495   </div>
496 496   #end
497 497   </div>
... ... @@ -510,7 +510,7 @@
510 510   #end
511 511   #if($canViewChallenges)
512 512  <h2 class="section-title">生徒会の課題意識 #if($visibilityChallenges != 'public')<span class="visibility-badge visibility-${visibilityChallenges}">#if($visibilityChallenges == 'members')<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="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/></svg> 登録者限定#else<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="M2 20h20"/><path d="M5 20V10l7-5 7 5v10"/><path d="M9 20v-5h6v5"/></svg> 校内限定#end</span>#end</h2>
513 -<div class="challenge-text">$escapetool.xml($challenges)</div>
517 +<div class="challenge-text">$!escapetool.xml($challenges)</div>
514 514   #else
515 515  <div class="visibility-restricted-notice"><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"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg> 課題情報は #if($visibilityChallenges == 'members')登録ユーザー#else校内メンバー#end のみ閲覧可能です</div>
516 516   #end
... ... @@ -521,7 +521,7 @@
521 521  {{/html}}
522 522  
523 523  ## --- ⑩ 活動報告一覧(スレッド型・年度タブ付き) ---
524 -= <svg class="ico" style="width:1.1em;height:1.1em;vertical-align:-0.15em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg> 活動報告 =
528 += 活動報告 =
525 525  
526 526  ## --- 投稿者ステータス凡例(折りたたみ) ---
527 527  {{html clean="false"}}
... ... @@ -623,11 +623,11 @@
623 623   #set($discard = $threadPosts.addAll($normalPosts))
624 624  
625 625  {{html clean="false"}}
626 -<div class="activity-thread" data-fiscal-year="$escapetool.xml($actFY)">
630 +<div class="activity-thread" data-fiscal-year="$!escapetool.xml($actFY)">
627 627   <div class="activity-thread-header">
628 628   <div class="activity-thread-title">
629 - <h3 #if($actFeatured == '1')class="featured-title"#end>$escapetool.xml($!actTitle) #if($actFeatured == '1')<svg style="width:14px;height:14px;vertical-align:-1px;margin-left:4px;" viewBox="0 0 24 24" fill="currentColor" stroke="none"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>#end</h3>
630 - <span class="activity-meta">$escapetool.xml($!actCommittee) | $escapetool.xml($!actPeriod) #if($actFY != 'unknown')| $escapetool.xml($actFY)年度#end</span>
633 + <h3 #if($actFeatured == '1')class="featured-title"#end>$!escapetool.xml($!actTitle) #if($actFeatured == '1')<svg style="width:14px;height:14px;vertical-align:-1px;margin-left:4px;" viewBox="0 0 24 24" fill="currentColor" stroke="none"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>#end</h3>
634 + <span class="activity-meta">$!escapetool.xml($!actCommittee) | $!escapetool.xml($!actPeriod) #if($actFY != 'unknown')| $!escapetool.xml($actFY)年度#end</span>
631 631   </div>
632 632   <div style="display:flex;align-items:center;gap:8px;">
633 633   <span class="thread-post-count">${threadPosts.size()}件の投稿</span>
... ... @@ -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')
... ... @@ -656,8 +656,8 @@
656 656   <div class="thread-post" style="opacity:0.5;border:2px dashed #dc2626;">
657 657   <div style="padding:10px 16px;font-size:0.85em;color:#dc2626;">
658 658   <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="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
659 - <strong>通報により非表示中</strong>(理由: $escapetool.xml($!post.getValue('hiddenReason')))
660 - <div style="margin-top:4px;font-size:0.92em;color:var(--text-mid);">$escapetool.xml($!postContent)</div>
683 + <strong>通報により非表示中</strong>(理由: $!escapetool.xml($!post.getValue('hiddenReason')))
684 + <div style="margin-top:4px;font-size:0.92em;color:var(--text-mid);">$!escapetool.xml($!postContent)</div>
661 661   </div>
662 662   </div>
663 663   #end
... ... @@ -695,9 +695,9 @@
695 695   #set($postAuthorRef = $!post.getValue('authorRef'))
696 696   <span class="thread-post-author">
697 697   #if($postAuthorRef && $postAuthorRef != '')
698 - <a href="$xwiki.getURL('SeitokaiCode.UserProfile', 'view', "user=${escapetool.url($postAuthorRef)}")">$escapetool.xml($!postAuthor)</a>
722 + <a href="$xwiki.getURL('SeitokaiCode.UserProfile', 'view', "user=${escapetool.url($postAuthorRef)}")">$!escapetool.xml($!postAuthor)</a>
699 699   #else
700 - $escapetool.xml($!postAuthor)
724 + $!escapetool.xml($!postAuthor)
701 701   #end
702 702   </span>
703 703   <span class="author-badge">
... ... @@ -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,9 +734,13 @@
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 - $escapetool.xml($!postContent)
771 + $!escapetool.xml($!postContent)
740 740   #set($postImages = $!post.getValue('images'))
741 741   #if($postImages && $postImages.trim() != '')
742 742   <div class="post-images">
... ... @@ -750,7 +750,7 @@
750 750   #if($imgName != '')
751 751   <div class="post-image-item">
752 752   <a href="$doc.getAttachmentURL($imgName)" target="_blank">
753 - <img src="$doc.getAttachmentURL($imgName)" alt="$escapetool.xml($imgName)" loading="lazy"/>
785 + <img src="$doc.getAttachmentURL($imgName)" alt="$!escapetool.xml($imgName)" loading="lazy"/>
754 754   </a>
755 755   </div>
756 756   #end
... ... @@ -781,7 +781,7 @@
781 781   #set($displayName = $fName.replaceFirst('file_\d{14}_\d+_', ''))
782 782   #end
783 783   <div class="post-file-item">
784 - <a href="$doc.getAttachmentURL($fName)" target="_blank" download="$escapetool.xml($displayName)">
816 + <a href="$doc.getAttachmentURL($fName)" target="_blank" download="$!escapetool.xml($displayName)">
785 785   #if($fIcon == 'pdf')<svg class="ico" style="width:1.1em;height:1.1em;vertical-align:-0.15em;color:${fColor};" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M9 15v-2h1.5a1.5 1.5 0 010 3H9"/></svg>
786 786   #elseif($fIcon == 'word')<svg class="ico" style="width:1.1em;height:1.1em;vertical-align:-0.15em;color:${fColor};" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M8 15l1.5-5 1.5 5 1.5-5 1.5 5"/></svg>
787 787   #elseif($fIcon == 'excel')<svg class="ico" style="width:1.1em;height:1.1em;vertical-align:-0.15em;color:${fColor};" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="16" y2="17"/><line x1="12" y1="13" x2="12" y2="17"/></svg>
... ... @@ -788,7 +788,7 @@
788 788   #elseif($fIcon == 'ppt')<svg class="ico" style="width:1.1em;height:1.1em;vertical-align:-0.15em;color:${fColor};" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><rect x="8" y="12" width="8" height="6" rx="1"/></svg>
789 789   #else<svg class="ico" style="width:1.1em;height:1.1em;vertical-align:-0.15em;color:${fColor};" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
790 790   #end
791 - <span class="post-file-name">$escapetool.xml($displayName)</span>
823 + <span class="post-file-name">$!escapetool.xml($displayName)</span>
792 792   </a>
793 793   </div>
794 794   #end
... ... @@ -815,18 +815,34 @@
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")
825 825   <div class="thread-add-post">
826 - <a href="/xwiki/bin/view/SeitokaiCode/ActivityPostForm?schoolPage=${doc.fullName}&activityIndex=${actIdx}&schoolCode=$escapetool.url($schoolCode)&postType=report" class="btn-thread-add">
874 + <a href="/xwiki/bin/view/SeitokaiCode/ActivityPostForm?schoolPage=${doc.fullName}&activityIndex=${actIdx}&schoolCode=$!escapetool.url($schoolCode)&postType=report" class="btn-thread-add">
827 827   + 活動報告を追加
828 828   </a>
829 - <a href="/xwiki/bin/view/SeitokaiCode/ActivityPostForm?schoolPage=${doc.fullName}&activityIndex=${actIdx}&schoolCode=$escapetool.url($schoolCode)&postType=comment" class="btn-thread-comment">
877 + <a href="/xwiki/bin/view/SeitokaiCode/ActivityPostForm?schoolPage=${doc.fullName}&activityIndex=${actIdx}&schoolCode=$!escapetool.url($schoolCode)&postType=comment" class="btn-thread-comment">
830 830   <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="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg> コメントを書く
831 831   </a>
832 832   </div>
... ... @@ -848,7 +848,7 @@
848 848  #if($xcontext.user != "XWiki.XWikiGuest")
849 849  {{html clean="false"}}
850 850  <div class="activity-add-section">
851 - <a href="/xwiki/bin/view/SeitokaiCode/ActivityForm?schoolPage=${doc.fullName}&schoolCode=$escapetool.url($schoolCode)" class="btn btn-primary btn-add-activity">
899 + <a href="/xwiki/bin/view/SeitokaiCode/ActivityForm?schoolPage=${doc.fullName}&schoolCode=$!escapetool.url($schoolCode)" class="btn btn-primary btn-add-activity">
852 852   <svg class="ico" style="width:1em;height:1em;vertical-align:-0.125em;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg> 活動を追加
853 853   </a>
854 854  </div>
... ... @@ -866,7 +866,7 @@
866 866   現在のページ: <strong>${pageFiscalYear}年度</strong>
867 867   #set($lyud = $!doc.getValue('lastYearUpdateDate'))
868 868   #if($lyud && $lyud != '')
869 - | 最終年度更新: $escapetool.xml($lyud) ($escapetool.xml($!doc.getValue('lastYearUpdateBy')))
917 + | 最終年度更新: $!escapetool.xml($lyud) ($!escapetool.xml($!doc.getValue('lastYearUpdateBy')))
870 870   #end
871 871   </div>
872 872  
... ... @@ -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}}