ELDER.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ELDER - ソーシャルネットワーキングサービス</title>
  <!-- CSSファイルの読み込み -->
  <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"> 
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
  <!-- RiTa.jsライブラリの読み込み -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/rita/1.3.63/rita-full.min.js"></script>
  <style>
    /* 既存のスタイルシート */
    body {
      padding-top: 20px;
      background: linear-gradient(to right, #f8f9fa, #e9ecef);
      font-family: 'Arial', sans-serif;
      color: #343a40;
    }

    .navbar {
      background-color: #007bff;
      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    }

    .navbar-brand,
    .nav-link {
      color: #fff !important;
      font-weight: bold;
    }

    .navbar-toggler {
      border: none;
    }

    .card {
      border-radius: 12px;
      box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
      transition: transform 0.3s, box-shadow 0.3s;
    }

    .card:hover {
      transform: translateY(-5px);
      box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
    }

    .card-body {
      padding: 30px;
    }

    .form-control {
      border-radius: 20px;
      border: 1px solid #ced4da;
      padding: 15px;
      transition: border-color 0.3s;
    }

    .form-control:focus {
      border-color: #007bff;
      box-shadow: none;
    }

    .btn-primary {
      background-color: #007bff;
      border: none;
      border-radius: 20px;
      padding: 10px 20px;
      font-weight: bold;
      transition: background-color 0.3s, transform 0.3s;
    }

    .btn-primary:hover {
      background-color: #0056b3;
      transform: translateY(-3px);
    }

    .btn-secondary {
      border-radius: 20px;
      padding: 10px 20px;
      font-weight: bold;
      transition: background-color 0.3s, transform 0.3s;
    }

    .btn-secondary:hover {
      background-color: #6c757d;
      transform: translateY(-3px);
    }

    .profile-img {
      width: 80px;
      height: 80px;
      object-fit: cover;
      border-radius: 50%;
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
    }

    .text-center h1 {
      font-weight: 700;
      font-size: 2.5em;
      margin-bottom: 20px;
      color: #007bff;
    }

    .comment-section {
      margin-top: 20px;
      padding: 20px;
      background-color: #f1f3f5;
      border-radius: 8px;
    }

    .comment-section .card {
      border: none;
      background: #ffffff;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }

    .modal-content {
      border-radius: 15px;
      overflow: hidden;
    }

    .modal-header {
      background-color: #007bff;
      color: white;
      border-bottom: none;
    }

    .modal-footer {
      border-top: none;
    }

    .form-error {
      color: red;
      font-size: 0.9em;
    }

    /* タイムラインのデザイン */
    #timeline {
      margin-top: 20px;
    }

    #timeline .card {
      border-radius: 15px;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
      margin-bottom: 20px;
      overflow: hidden;
      background-color: #fff;
    }

    #timeline .card-body {
      padding: 20px;
    }

    #timeline .btn {
      border-radius: 20px;
    }

    /* 投稿のシェアボタン */
    .btn-share {
      background-color: #ff9800;
      border: none;
      border-radius: 20px;
      padding: 5px 10px;
      color: #fff;
      font-weight: bold;
      transition: background-color 0.3s;
    }

    .btn-share:hover {
      background-color: #e68900;
    }

    /* X(旧Twitter)シェアボタン */
    .btn-share-twitter {
      background-color: #1da1f2;
      border: none;
      border-radius: 20px;
      padding: 5px 10px;
      color: #fff;
      font-weight: bold;
      transition: background-color 0.3s;
    }

    .btn-share-twitter:hover {
      background-color: #1480bf;
    }

    /* 通知エリア */
    #notificationArea {
      position: fixed;
      top: 80px;
      right: 20px;
      z-index: 1000;
      max-width: 300px;
    }

    /* FEEDアイコンをRSSの文字に変更 */
    .nav-item .rss-icon {
      font-weight: bold;
      color: #fff;
    }
  </style>
</head>
<body>

<!-- ナビゲーションバー -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="#">ELDER</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="ナビゲーションの切り替え">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNav">
    <ul class="navbar-nav ml-auto">
      <li class="nav-item">
        <a class="nav-link" href="#" onclick="showLoginForm()">ログイン</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#" onclick="showRegisterForm()">登録</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#" onclick="showProfile()" style="display: none;" id="navProfile">プロフィール</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#" onclick="logout()" style="display: none;" id="navLogout">ログアウト</a>
      </li>
      <!-- FEEDアイコンをRSSの文字に変更 -->
      <li class="nav-item" id="navFeed" style="display: none;">
        <a class="nav-link rss-icon" href="#" onclick="showFeedForm()">RSS</a>
      </li>
    </ul>
  </div>
</nav>

<div class="container">
  <!-- ログインフォーム -->
  <div id="loginForm" class="card w-50 mx-auto">
    <div class="card-body">
      <h2 class="card-title text-center mb-4">ログイン</h2>
      <div class="form-group">
        <input type="text" id="loginUsername" class="form-control" placeholder="ユーザー名">
        <span id="loginUsernameError" class="form-error" style="display: none;">ユーザー名を入力してください</span>
      </div>
      <div class="form-group">
        <input type="password" id="loginPassword" class="form-control" placeholder="パスワード">
        <span id="loginPasswordError" class="form-error" style="display: none;">パスワードを入力してください</span>
      </div>
      <button onclick="login()" class="btn btn-primary btn-block">ログイン</button>
      <button onclick="showRegisterForm()" class="btn btn-secondary btn-block">登録</button>
    </div>
  </div>

  <!-- 登録フォーム -->
  <div id="registerForm" class="card w-50 mx-auto" style="display: none;">
    <div class="card-body">
      <h2 class="card-title text-center mb-4">登録</h2>
      <div class="form-group">
        <input type="text" id="registerName" class="form-control" placeholder="氏名">
        <span id="registerNameError" class="form-error" style="display: none;">氏名を入力してください</span>
      </div>
      <div class="form-group">
        <input type="text" id="registerUsername" class="form-control" placeholder="ユーザー名">
        <span id="registerUsernameError" class="form-error" style="display: none;">ユーザー名を入力してください</span>
      </div>
      <div class="form-group">
        <input type="password" id="registerPassword" class="form-control" placeholder="パスワード">
        <span id="registerPasswordError" class="form-error" style="display: none;">パスワードを入力してください</span>
      </div>
      <div class="form-group">
        <input type="password" id="registerConfirmPassword" class="form-control" placeholder="パスワードを確認">
        <span id="registerConfirmPasswordError" class="form-error" style="display: none;">パスワードが一致しません</span>
      </div>
      <button onclick="register()" class="btn btn-primary btn-block">登録</button>
      <button onclick="showLoginForm()" class="btn btn-secondary btn-block">ログインに戻る</button>
    </div>
  </div>

  <!-- プロフィール -->
  <div id="profile" class="card w-50 mx-auto" style="display: none;">
    <div class="card-body">
      <h2 class="card-title text-center mb-4">プロフィール</h2>
      <div class="text-center mb-3">
        <img id="profileImg" class="profile-img" src="default_profile_img.jpg" alt="プロフィール画像">
      </div>
      <p class="text-center mb-2"><strong>氏名:</strong> <span id="profileName"></span></p>
      <p class="text-center mb-4"><strong>ユーザー名:</strong> <span id="profileUsername"></span></p>
      <div class="form-group">
        <input type="file" id="profileImageInput" accept="image/*" class="form-control-file">
      </div>
      <button onclick="uploadProfileImage()" class="btn btn-primary btn-block"><i class="fas fa-upload"></i> プロフィール画像をアップロード</button>
      <button onclick="logout()" class="btn btn-danger btn-block"><i class="fas fa-sign-out-alt"></i> ログアウト</button>
    </div>
  </div>

  <!-- 投稿フォーム -->
  <div id="postForm" class="card w-75 mx-auto" style="display: none;">
    <div class="card-body">
      <h2 class="card-title text-center mb-4">投稿を作成</h2>
      <div class="form-group">
        <textarea id="postContent" class="form-control" rows="3" placeholder="今何を考えていますか?"></textarea>
      </div>
      <button onclick="createPost()" class="btn btn-primary btn-block">投稿</button>
    </div>
  </div>

  <!-- FEED登録フォーム -->
  <div id="feedForm" class="card w-75 mx-auto" style="display: none;">
    <div class="card-body">
      <h2 class="card-title text-center mb-4">FEEDを登録</h2>
      <div class="form-group">
        <input type="text" id="feedUrl" class="form-control" placeholder="RSSフィードのURL">
        <span id="feedUrlError" class="form-error" style="display: none;">RSSフィードのURLを入力してください</span>
      </div>
      <button onclick="registerFeed()" class="btn btn-primary btn-block">登録</button>
      <div class="form-group mt-4">
        <label for="feedInterval">自動投稿の間隔(秒):</label>
        <input type="number" id="feedInterval" class="form-control" placeholder="例:60" min="1">
      </div>
      <button onclick="setFeedInterval()" class="btn btn-secondary btn-block">間隔を設定</button>
    </div>
  </div>

  <!-- AIBOT投稿登録フォーム -->
  <div id="aiBotForm" class="card w-75 mx-auto" style="display: none;">
    <div class="card-body">
      <h2 class="card-title text-center mb-4">BOT投稿を登録</h2>
      <div class="form-group">
        <textarea id="aiBotContent" class="form-control" rows="3" placeholder="BOTに投稿させたい内容を入力してください"></textarea>
      </div>
      <button onclick="registerAiBotPost()" class="btn btn-primary btn-block">BOT投稿を登録</button>
    </div>
  </div>

  <!-- タイムライン -->
  <div id="timeline" class="w-75 mx-auto mt-4"></div>

  <!-- 通知エリア -->
  <div id="notificationArea" class="alert alert-info" style="display: none;"></div>

</div>

<!-- リプライモーダル -->
<div class="modal fade" id="replyModal" tabindex="-1" role="dialog" aria-labelledby="replyModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <!-- モーダルの内容は後ほどJavaScriptで制御します -->
      <div class="modal-header">
        <h5 class="modal-title" id="replyModalLabel">投稿に返信</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <textarea id="replyContent" class="form-control" rows="3" placeholder="返信をここに書いてください..."></textarea>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
        <button type="button" onclick="postReply()" class="btn btn-primary">返信</button>
      </div>
    </div>
  </div>
</div>

<!-- スクリプトの読み込み -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<!-- BootstrapのJavaScript -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<!-- RiTa.jsライブラリの読み込み(既にhead内で読み込み済み) -->
<script>
  // ユーザー、投稿、フィード、チャット関連のデータ
  let currentUser = null;
  let users = [];
  let posts = [];
  let feeds = [];
  let notifications = [];
  let aiBotPosts = [];
  let feedFetchInterval = 60000; // デフォルトは60,000ミリ秒(60秒)
  let feedFetchTimer;
  let markovBotInterval = 60000; // マルコフ連鎖BOTの投稿間隔

  // ローカルストレージの読み込み・保存関連の関数
  function saveUsersToLocalStorage() {
    localStorage.setItem('users', JSON.stringify(users));
  }

  function savePostsToLocalStorage() {
    localStorage.setItem('posts', JSON.stringify(posts));
  }

  function saveFeedsToLocalStorage() {
    localStorage.setItem('feeds', JSON.stringify(feeds));
  }

  function saveAiBotPostsToLocalStorage() {
    localStorage.setItem('aiBotPosts', JSON.stringify(aiBotPosts));
  }

  function saveCurrentUserToLocalStorage() {
    if (currentUser) {
      localStorage.setItem('currentUser', JSON.stringify(currentUser));
    } else {
      localStorage.removeItem('currentUser');
    }
  }

  function loadUsersFromLocalStorage() {
    const storedUsers = localStorage.getItem('users');
    if (storedUsers) {
      users = JSON.parse(storedUsers);
    }
  }

  function loadPostsFromLocalStorage() {
    const storedPosts = localStorage.getItem('posts');
    if (storedPosts) {
      posts = JSON.parse(storedPosts);
    }
  }

  function loadFeedsFromLocalStorage() {
    const storedFeeds = localStorage.getItem('feeds');
    if (storedFeeds) {
      feeds = JSON.parse(storedFeeds);
    }
  }

  function loadAiBotPostsFromLocalStorage() {
    const storedAiBotPosts = localStorage.getItem('aiBotPosts');
    if (storedAiBotPosts) {
      aiBotPosts = JSON.parse(storedAiBotPosts);
    }
  }

  function loadCurrentUserFromLocalStorage() {
    const storedCurrentUser = localStorage.getItem('currentUser');
    if (storedCurrentUser) {
      currentUser = JSON.parse(storedCurrentUser);
    }
  }

  // フォームの表示・非表示
  function hideAll() {
    document.getElementById('loginForm').style.display = 'none';
    document.getElementById('registerForm').style.display = 'none';
    document.getElementById('profile').style.display = 'none';
    document.getElementById('postForm').style.display = 'none';
    document.getElementById('feedForm').style.display = 'none';
    document.getElementById('aiBotForm').style.display = 'none';
  }

  function showLoginForm() {
    hideAll();
    document.getElementById('loginForm').style.display = 'block';
    document.getElementById('navProfile').style.display = 'none';
    document.getElementById('navLogout').style.display = 'none';
    document.getElementById('navFeed').style.display = 'none';
  }

  function showRegisterForm() {
    hideAll();
    document.getElementById('registerForm').style.display = 'block';
  }

  function showProfile() {
    hideAll();
    document.getElementById('profile').style.display = 'block';
    document.getElementById('profileName').textContent = currentUser.name;
    document.getElementById('profileUsername').textContent = currentUser.username;
    document.getElementById('postForm').style.display = 'block';
    document.getElementById('feedForm').style.display = 'block';
    document.getElementById('aiBotForm').style.display = 'block';
    loadProfileImage(); // プロフィール画像をロード
    displayTimeline(); // タイムラインを表示
    document.getElementById('navProfile').style.display = 'block';
    document.getElementById('navLogout').style.display = 'block';
    document.getElementById('navFeed').style.display = 'block'; // RSSナビゲーションを表示
  }

  function showFeedForm() {
    hideAll();
    document.getElementById('feedForm').style.display = 'block';
  }

  // ユーザー認証関連の関数
  function validateLoginForm() {
    let valid = true;
    const username = document.getElementById('loginUsername').value;
    const password = document.getElementById('loginPassword').value;

    if (!username) {
      document.getElementById('loginUsernameError').style.display = 'block';
      valid = false;
    } else {
      document.getElementById('loginUsernameError').style.display = 'none';
    }

    if (!password) {
      document.getElementById('loginPasswordError').style.display = 'block';
      valid = false;
    } else {
      document.getElementById('loginPasswordError').style.display = 'none';
    }

    return valid;
  }

  function login() {
    if (!validateLoginForm()) {
      return;
    }

    const username = document.getElementById('loginUsername').value;
    const password = document.getElementById('loginPassword').value;
    const user = users.find(u => u.username === username && u.password === password);
    if (user) {
      currentUser = user;
      saveCurrentUserToLocalStorage(); // currentUserを保存
      showProfile();
    } else {
      alert('ユーザー名またはパスワードが間違っています。');
    }
  }

  function logout() {
    currentUser = null;
    saveCurrentUserToLocalStorage(); // currentUserを削除
    hideAll();
    showLoginForm();
  }

  function validateRegisterForm() {
    let valid = true;
    const name = document.getElementById('registerName').value;
    const username = document.getElementById('registerUsername').value;
    const password = document.getElementById('registerPassword').value;
    const confirmPassword = document.getElementById('registerConfirmPassword').value;

    if (!name) {
      document.getElementById('registerNameError').style.display = 'block';
      valid = false;
    } else {
      document.getElementById('registerNameError').style.display = 'none';
    }

    if (!username) {
      document.getElementById('registerUsernameError').style.display = 'block';
      valid = false;
    } else {
      document.getElementById('registerUsernameError').style.display = 'none';
    }

    // ユーザー名の重複チェック
    if (users.find(u => u.username === username)) {
      document.getElementById('registerUsernameError').textContent = 'このユーザー名は既に使用されています';
      document.getElementById('registerUsernameError').style.display = 'block';
      valid = false;
    } else {
      document.getElementById('registerUsernameError').style.display = 'none';
    }

    if (!password) {
      document.getElementById('registerPasswordError').style.display = 'block';
      valid = false;
    } else {
      document.getElementById('registerPasswordError').style.display = 'none';
    }

    if (password !== confirmPassword) {
      document.getElementById('registerConfirmPasswordError').style.display = 'block';
      valid = false;
    } else {
      document.getElementById('registerConfirmPasswordError').style.display = 'none';
    }

    return valid;
  }

  function register() {
    if (!validateRegisterForm()) {
      return;
    }

    const name = document.getElementById('registerName').value;
    const username = document.getElementById('registerUsername').value;
    const password = document.getElementById('registerPassword').value;

    users.push({ name, username, password, profileImage: null });
    saveUsersToLocalStorage(); // ユーザー情報を保存
    alert('登録が完了しました!ログインしてください。');
    showLoginForm();
  }

  // プロフィール画像の処理
  function loadProfileImage() {
    const profileImg = document.getElementById('profileImg');
    // プロフィール画像が設定されている場合はその画像を表示
    if (currentUser.profileImage) {
      profileImg.src = currentUser.profileImage;
    } else {
      // デフォルトのプロフィール画像を表示
      profileImg.src = 'default_profile_img.jpg';
    }
  }

  function uploadProfileImage() {
    const input = document.getElementById('profileImageInput');
    const file = input.files[0];
    if (file) {
      // FileReaderを使用して画像を読み込む
      const reader = new FileReader();
      reader.onload = function(e) {
        // 読み込んだ画像をプロフィール画像として設定
        currentUser.profileImage = e.target.result;
        // プロフィール画像を更新して表示
        loadProfileImage();
        saveUsersToLocalStorage(); // プロフィール画像を保存
        saveCurrentUserToLocalStorage(); // currentUserを更新
      }
      reader.readAsDataURL(file);
    }
  }

  // AIBOT投稿を登録
  function registerAiBotPost() {
    const content = document.getElementById('aiBotContent').value;
    if (content.trim() !== '') {
      aiBotPosts.push(content);
      saveAiBotPostsToLocalStorage();
      alert("BOTの投稿が登録されました!");
      document.getElementById('aiBotContent').value = ''; // 入力欄を空にする
    }
  }

  // AIBOTが定期的に投稿
  function postAiBotContent() {
    if (aiBotPosts.length > 0) {
      const content = aiBotPosts[Math.floor(Math.random() * aiBotPosts.length)];
      const aiUser = {
        name: 'BOT',
        username: 'bot',
        profileImage: 'default_ai_profile_img.jpg'
      };
      const post = {
        id: Date.now(),
        content: content,
        author: aiUser.name,
        authorUsername: aiUser.username,
        authorProfileImage: aiUser.profileImage,
        likes: 0,
        comments: []
      };
      posts.unshift(post);
      savePostsToLocalStorage();
      displayTimeline();
    }
  }

  setInterval(postAiBotContent, 500000); // 50,000ミリ秒 = 50秒

  // マルコフ連鎖を使用した自動投稿BOT
  function generateMarkovChainText(order = 2) {
    const allTexts = posts.map(post => post.content).join(' ');
    if (allTexts.length < 100) return null; // テキストが短すぎる場合は生成しない

    const markov = new RiTa.Markov(order);
    markov.addText(allTexts);
    const sentences = markov.generate(1);
    return sentences[0];
  }

  function postMarkovBotContent() {
    const generatedText = generateMarkovChainText(3); // 階数を3に設定
    if (generatedText) {
      const botUser = {
        name: 'MarkovBot',
        username: 'markovbot',
        profileImage: 'markov_bot_profile_img.jpg'
      };
      const post = {
        id: Date.now(),
        content: generatedText,
        author: botUser.name,
        authorUsername: botUser.username,
        authorProfileImage: botUser.profileImage,
        likes: 0,
        comments: []
      };
      posts.unshift(post);
      savePostsToLocalStorage();
      displayTimeline();
    }
  }

  setInterval(postMarkovBotContent, markovBotInterval); // マルコフ連鎖BOTの投稿間隔

  // 投稿関連の関数
  function createPost() {
    const postContent = document.getElementById('postContent').value;
    if (postContent.trim() !== '') {
      const post = {
        id: Date.now(),
        content: postContent,
        author: currentUser.name,
        authorUsername: currentUser.username,
        authorProfileImage: currentUser.profileImage,
        likes: 0,
        comments: [],
        shares: 0
      };
      posts.unshift(post); // 最新の投稿を先頭に追加
      savePostsToLocalStorage(); // 投稿を保存
      displayTimeline();
      document.getElementById('postContent').value = ''; // 投稿後、入力欄を空にする
    }
  }

  function displayTimeline() {
    const timeline = document.getElementById('timeline');
    timeline.innerHTML = '';
    posts.forEach(post => {
      const postElement = document.createElement('div');
      postElement.classList.add('card', 'mb-3');
      postElement.innerHTML = `
        <div class="card-body">
          <div class="d-flex align-items-center mb-3">
            <img src="${post.authorProfileImage || 'default_profile_img.jpg'}" class="profile-img mr-2" alt="プロフィール画像">
            <div>
              <strong>${post.author}</strong> (@${post.authorUsername})
              ${post.shared ? '<span class="badge badge-info ml-2">シェア</span>' : ''}
            </div>
          </div>
          <p class="card-text">${post.content}</p>
          ${post.link ? `<a href="${post.link}" target="_blank" class="btn btn-link">続きを読む</a>` : ''}
          <div class="d-flex justify-content-between">
            <div>
              <button onclick="likePost(${post.id})" class="btn btn-primary btn-sm"><i class="fas fa-thumbs-up"></i> いいね (${post.likes})</button>
              <button onclick="toggleComments(${post.id})" class="btn btn-secondary btn-sm"><i class="fas fa-comments"></i> コメント (${post.comments.length})</button>
              <button onclick="replyToPost(${post.id})" class="btn btn-info btn-sm"><i class="fas fa-reply"></i> 返信</button>
              <button onclick="sharePost(${post.id})" class="btn btn-share btn-sm"><i class="fas fa-share"></i> シェア (${post.shares || 0})</button>
              <button onclick="shareToTwitter(${post.id})" class="btn btn-share-twitter btn-sm"><i class="fab fa-twitter"></i> Xでシェア</button>
            </div>
            <small class="text-muted">${new Date(post.id).toLocaleString()}</small>
          </div>
          <div id="comments-${post.id}" class="comment-section mt-3" style="display: none;">
            ${post.comments.map(comment => `
              <div class="card mb-2">
                <div class="card-body">
                  <p><strong>${comment.author}</strong>: ${comment.content}</p>
                </div>
              </div>
            `).join('')}
          </div>
        </div>
      `;
      timeline.appendChild(postElement);
    });
  }

  // いいね機能
  function likePost(postId) {
    const post = posts.find(p => p.id === postId);
    post.likes++;
    savePostsToLocalStorage();
    displayTimeline();
  }

  // コメント表示切替
  function toggleComments(postId) {
    const commentSection = document.getElementById(`comments-${postId}`);
    commentSection.style.display = commentSection.style.display === 'none' ? 'block' : 'none';
  }

  // リプライ機能
  function replyToPost(postId) {
    const modal = document.getElementById('replyModal');
    modal.dataset.postId = postId;
    $('#replyModal').modal('show');
  }

  function postReply() {
    const postId = parseInt(document.getElementById('replyModal').dataset.postId);
    const post = posts.find(p => p.id === postId);
    const replyContent = document.getElementById('replyContent').value;
    if (replyContent.trim() !== '') {
      post.comments.push({ author: currentUser.name, content: replyContent });
      $('#replyModal').modal('hide');
      savePostsToLocalStorage();
      displayTimeline();
    } else {
      alert('返信を入力してください。');
    }
  }

  // 投稿のシェア機能
  function sharePost(postId) {
    const post = posts.find(p => p.id === postId);
    if (post) {
      const sharedPost = {
        ...post,
        id: Date.now(),
        author: currentUser.name,
        authorUsername: currentUser.username,
        authorProfileImage: currentUser.profileImage,
        shared: true,
        likes: 0,
        comments: [],
        shares: post.shares ? post.shares + 1 : 1
      };
      posts.unshift(sharedPost);
      savePostsToLocalStorage();
      displayTimeline();
      alert('投稿をシェアしました。');
    }
  }

  // X(旧Twitter)にシェアする機能
  function shareToTwitter(postId) {
    const post = posts.find(p => p.id === postId);
    if (post) {
      let shareText = post.content;
      if (post.link) {
        shareText += ' ' + post.link;
      }
      const shareUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}&url=${encodeURIComponent(window.location.href)}`;
      window.open(shareUrl, '_blank');
    }
  }

  // FEEDの登録と自動投稿機能
  function registerFeed() {
    const feedUrl = document.getElementById('feedUrl').value;
    if (feedUrl.trim() !== '') {
      feeds.push(feedUrl);
      saveFeedsToLocalStorage(); // フィード情報を保存
      alert('RSSフィードが登録されました!');
      document.getElementById('feedUrl').value = ''; // 登録後、入力欄を空にする
    } else {
      document.getElementById('feedUrlError').style.display = 'block';
    }
  }

  function fetchFeeds() {
    feeds.forEach(feedUrl => {
      fetch(`https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(feedUrl)}`)
        .then(response => response.json())
        .then(data => {
          data.items.forEach(item => {
            // 同じ投稿が既に存在するかチェック
            if (!posts.some(p => p.link === item.link)) {
              const post = {
                id: Date.now() + Math.random(), // 重複しないIDを生成
                content: item.title,
                link: item.link, // リンクを追加
                author: 'FEEDBOT',
                authorUsername: 'feedbot',
                authorProfileImage: 'feedbot_profile_img.jpg', // FEEDBOTのプロフィール画像を設定
                likes: 0,
                comments: []
              };
              posts.unshift(post); // 最新の投稿を先頭に追加
              savePostsToLocalStorage(); // 投稿を保存
            }
          });
          displayTimeline(); // タイムラインを表示
        })
        .catch(error => console.error('RSSフィードの取得エラー:', error));
    });
  }

  function setFeedInterval() {
    const intervalInput = document.getElementById('feedInterval').value;
    if (intervalInput && parseInt(intervalInput) > 0) {
      feedFetchInterval = parseInt(intervalInput) * 1000; // ミリ秒に変換
      clearInterval(feedFetchTimer);
      feedFetchTimer = setInterval(fetchFeeds, feedFetchInterval);
      alert(`自動投稿の間隔が${intervalInput}秒に設定されました。`);
    } else {
      alert('有効な間隔を入力してください(1以上の数字)。');
    }
  }

  // ページロード時にフィードの自動取得を開始
  function startFeedFetch() {
    feedFetchTimer = setInterval(fetchFeeds, feedFetchInterval);
  }

  // 初期化
  function init() {
    loadUsersFromLocalStorage();
    loadPostsFromLocalStorage();
    loadFeedsFromLocalStorage();
    loadAiBotPostsFromLocalStorage();
    loadCurrentUserFromLocalStorage();

    if (currentUser) {
      showProfile();
    } else {
      hideAll();
      document.getElementById('loginForm').style.display = 'block';
    }

    displayTimeline();
    startFeedFetch(); // フィードの自動取得を開始
  }

  // ページロード時に初期化
  window.onload = init;

</script>

</body>
</html>

投稿者: chosuke

趣味はゲームやアニメや漫画などです

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です