Skip to content

Commit

Permalink
Merge pull request #23 from Aki158/【実装】スレッド表示ページ#8
Browse files Browse the repository at this point in the history
Implementation using the Ratchet library
  • Loading branch information
Aki158 authored Jan 17, 2024
2 parents ece7ed0 + 4edce32 commit 070822e
Show file tree
Hide file tree
Showing 12 changed files with 2,455 additions and 162 deletions.
22 changes: 22 additions & 0 deletions Database/DataAccess/Implementations/PostDAOImpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@

class PostDAOImpl implements PostDAO
{
private ?int $post_id = null;

public function getCreateOrUpdateId(): ?int {
return $this->post_id;
}

public function setCreateOrUpdateId(int $id): void {
$this->post_id = $id;
}

public function create(Post $postData): bool
{
if($postData->getPostId() !== null) throw new \Exception('Cannot create a post with an existing ID. id: ' . $postData->getPostId());
Expand Down Expand Up @@ -69,9 +79,13 @@ public function createOrUpdate(Post $postData): bool{
// insert_id returns the last inserted ID.
if($postData->getPostId() === null){
$postData->setPostId($mysqli->insert_id);
$this->setCreateOrUpdateId($mysqli->insert_id);
$timeStamp = $postData->getTimeStamp()??new DataTimeStamp(date('Y-m-h'), date('Y-m-h'));
$postData->setTimeStamp($timeStamp);
}
else{
$this->setCreateOrUpdateId($postData->getPostId());
}

return true;
}
Expand Down Expand Up @@ -137,4 +151,12 @@ public function getThread(string $url): ?Post{
return $post === null ? null : $this->resultToPost($post);
}

public function getReply(string $postId): ?Post{
$mysqli = DatabaseManager::getMysqliConnection();

$post = $mysqli->prepareAndFetchAll("SELECT * FROM Post WHERE post_id = ?",'s',[$postId])[0]??null;

return $post === null ? null : $this->resultToPost($post);
}

}
23 changes: 8 additions & 15 deletions Public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ body {
}

#new_thread_textarea {
width: 690px;
width: 100%;
height: 200px;
}

#reply_textarea {
width: 690px;
width: 100%;
height: 100px;
}

Expand Down Expand Up @@ -116,14 +116,16 @@ body {
.fixed-reply-area {
position: fixed; /* 固定位置にする */
bottom: 8px; /* 画面の下に固定 */
background-color: #ffffff; /* 背景色を設定 */
padding: 10px; /* 必要に応じてパディングを設定 */
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.2); /* 影を追加 */
/* background-color: #ffffff; 背景色を設定 */
z-index: 1000; /* 表示順序を設定 */
max-height: 280px;
max-height: 300px;
overflow-y: auto;
}

.box-shadow {
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.2); /* 影を追加 */
}

.responsive-new-thread {
display: block;
}
Expand Down Expand Up @@ -156,13 +158,4 @@ body {
.responsive-table {
display: block;
}

#new_thread_textarea {
width: 350px;
height: 200px;
}
#reply_textarea {
width: 350px;
height: 100px;
}
}
28 changes: 13 additions & 15 deletions Public/js/app_home.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,19 @@ function renderpostList(thread, replies, postsList){
<div class="row justify-content-center">
<div class="col-md-7">
<div class="custom-border bg-white">
<div>
<div class="m-3">
<p><i class="fa-regular fa-comments"></i> ${thread.count} &nbsp;&nbsp; <i class="fa-regular fa-clock"></i> ${thread.created_at}</p>
</div>
<div class="m-3">
<h5>${thread.subject}</h5>
</div>
<div class="m-3">
<p>${thread.content}</p>
</div>
<div class="m-3">
<a href="../${thread.image_path}">
<img src="../${thread.thumbnail_path}" alt="画像を表示できませんでした" class="rounded-image">
</a>
</div>
<div class="m-3">
<p><i class="fa-regular fa-comments"></i> ${thread.count} &nbsp;&nbsp; <i class="fa-regular fa-clock"></i> ${thread.created_at}</p>
</div>
<div class="m-3">
<h5>${thread.subject}</h5>
</div>
<div class="m-3">
<p>${thread.content}</p>
</div>
<div class="m-3">
<a href="../${thread.image_path}">
<img src="../${thread.thumbnail_path}" alt="画像を表示できませんでした" class="rounded-image">
</a>
</div>
${message}
<div class="custom-border-top">
Expand Down
37 changes: 0 additions & 37 deletions Public/js/app_newThread.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,40 +56,3 @@ function threadFormDataClear(){
document.getElementById('upload_file_none').value = '';
document.getElementById('image_select_message').innerHTML = 'ファイルを選択して下さい';
}

// function threadData(idTitle, idContent, idUploadFile) {
// const title = document.getElementById('title').value;
// const content = document.getElementById('new_thread_textarea').value;
// const uploadFile = document.getElementById('upload_file_none');
// const formData = new FormData();
// formData.append('subject', title);
// formData.append('content', content);
// formData.append('file', uploadFile.files[0]);

// // fetchリクエストを送信します
// fetch('form/create/post', {
// method: 'POST',
// body: formData
// })
// .then(response => response.json()) // レスポンスからJSONを解析します
// .then(data => {
// // サーバからのレスポンスデータを処理します
// if (data.status === 'success') {
// // 成功メッセージを表示したり、リダイレクトしたり、コンソールにログを出力する可能性があります
// console.log(data.message);
// alert('ポストできました!');

// threadFormDataClear();
// } else if (data.status === 'error') {
// // ユーザーにエラーメッセージを表示します
// console.error(data.message);
// alert(data.message);
// }
// })
// .catch((error) => {
// // ネットワークエラーかJSONの解析エラー
// console.error('Error:', error);
// alert('エラーが発生しました。もう一度試してください。'+error);
// });
// }

182 changes: 156 additions & 26 deletions Public/js/app_thread.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
const repliesList = document.getElementById("replies_list");
const jumpBottom = document.getElementById('jumpBottom');
const inputFile = document.getElementById('reply_upload_file_none');
const body = document.body;
const replyLimit = 100;
var replyCount = 0;
var connStatus = false;
var replyUserFlag = false;
var conn;

// body要素のスタイルにpadding-bottomを追加
body.style.paddingBottom = '110px';

window.onload = connect;

window.addEventListener('resize', adjustWidth);

window.addEventListener('scroll', function() {
// ページの最下層に到達したら、メッセージを非表示にする
if (isAtBottom()) {
jumpBottom.style.display = "none";
}
});

window.addEventListener("load", (event) => {
// フォームの幅を設定
adjustWidth();

replyCount = Object.keys(replies).length;

// 返信数が上限(返信数:100)に到達した場合
if(replyCount >= replyLimit){
replyReachedLimit();
}

for (var i = 0; i < replyCount; i++) {
renderList(i+1, replies[i], repliesList);
}
});

document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('reply-form');

Expand All @@ -23,6 +63,7 @@ document.addEventListener('DOMContentLoaded', function () {
console.log(data.message);

replyFormDataClear();
publish(data.message);
} else if (data.status === 'error') {
// ユーザーにエラーメッセージを表示します
console.error(data.message);
Expand All @@ -37,19 +78,7 @@ document.addEventListener('DOMContentLoaded', function () {
});
});

function replyFormDataClear(){
document.getElementById('reply_comment_count').innerHTML = '0/400';
document.getElementById('reply_textarea').value = '';
document.getElementById('reply_upload_file_none').value = '';
document.getElementById('reply_image_select_message').innerHTML = '';
}

// body要素のスタイルにpadding-bottomを追加
const body = document.body;
body.style.paddingBottom = '230px';

// 画像ボタンがクリックされたら、メッセージを変更する
const inputFile = document.getElementById('reply_upload_file_none');
inputFile.addEventListener('change', function() {
const reader = new FileReader();
reader.onload = function() {
Expand All @@ -58,39 +87,140 @@ inputFile.addEventListener('change', function() {
reader.readAsDataURL(inputFile.files[0]);
});

window.addEventListener("load", (event) => {
const len = Object.keys(replies).length;
const repliesList = document.getElementById("replies_list");
for (var i = 0; i < len; i++) {
renderList(i,replies,repliesList);
}
jumpBottom.addEventListener('click', function(e) {
// デフォルトのアンカー動作を防止
e.preventDefault();
scrollToBottom();
jumpBottom.style.display = "none";
});

function renderList(index, replies, repliesList){
// WebSocketに接続する
function connect(){
// connStatusがtrueであれば、接続を切ります
if (connStatus) {
conn.close();
connStatus = false;
}

conn = new ab.Session('ws://localhost:8080',
function() {
connStatus = true;

conn.subscribe(threadId, function(topic, data) {
var scrollStatus = isAtBottom();

// dataはreplyに関係するデータです
// 引数はそれぞれ、conn.publish(threadId, data);の引数に紐付いています
// topic = threadId;
// data = data;
renderList(data.count, data, repliesList);
replyCount = data.count;

// replyしたユーザーだけ自動的にページの最下部にスクロールする
if(replyUserFlag || scrollStatus){
setTimeout(scrollToBottom, 100);
replyUserFlag = false;
}
else{
// 「新しいメッセージがあります↓」と表示したい
jumpBottom.style.display = "block";
}

if(data.count >= replyLimit){
replyReachedLimit();
}
});
},
function() {
console.warn('WebSocket connection closed');
},
{'skipSubprotocolCheck': true}
);
}

// replyデータをページにレンダリングする
function renderList(index, reply, repliesList){
repliesList.innerHTML += `
<div class="custom-border-top">
<div class="m-3">
<p><i class="fa-regular fa-comment"></i> ${index + 1}. &nbsp;&nbsp; <i class="fa-regular fa-clock"></i> ${replies[index].created_at}</p>
<p><i class="fa-regular fa-comment"></i> ${index}. &nbsp;&nbsp; <i class="fa-regular fa-clock"></i> ${reply.created_at}</p>
</div>
`;

// コメントが入力されている場合
if(replies[index].content !== null) {
if(reply.content !== null) {
repliesList.innerHTML += `
<div class="m-3">
<p>${replies[index].content}</p>
<p>${reply.content}</p>
</div>
`;
}

// 画像がアップロードされている場合
if(replies[index].image_path !== null) {
if(reply.image_path !== null) {
repliesList.innerHTML += `
<div class="m-3">
<a href="../${replies[index].image_path}">
<img src="../${replies[index].thumbnail_path}" alt="画像を表示できませんでした" class="rounded-image">
<a href="../${reply.image_path}">
<img src="../${reply.thumbnail_path}" alt="画像を表示できませんでした" class="rounded-image">
</a>
</div>
`;
}
}
}

// 返信数が上限(返信数:100)に到達した場合
function replyReachedLimit(){
// 画面のトップにメッセージを表示する
const lastMessage = document.getElementById("lastMessage");
lastMessage.innerHTML = "スレッドの返信数が上限に到達しました。<br>これ以上返信はできません。";

// 入力を禁止したいので、フォームを非表示に設定する
const replyForm = document.getElementById("reply-form");
replyForm.style.display = 'none';

// フォーム用に確保していた領域をなくします
body.style.paddingBottom = '0px';

// ページの最下部にスクロールします
scrollToBottom();
}

// ページの最下部にスクロールする
function scrollToBottom() {
window.scrollTo(0, document.body.scrollHeight);
}

// dataを公開するために送信する
function publish(data){
replyCount += 1;
data.count = replyCount;
replyUserFlag = true;

if(replyCount >= replyLimit){
replyReachedLimit();
}
conn.publish(threadId, data);
}

// ページの最下層にいるか確認する
function isAtBottom() {
return window.innerHeight + window.scrollY >= document.body.offsetHeight;
}

// 次のデータ送信のために、フォームデータをクリアする
function replyFormDataClear(){
document.getElementById('reply_comment_count').innerHTML = '0/400';
document.getElementById('reply_textarea').value = '';
document.getElementById('reply_upload_file_none').value = '';
document.getElementById('reply_image_select_message').innerHTML = '';
}

function adjustWidth() {
var parent = document.querySelector('.col-md-7'); // 親要素を選択
var parentStyle = window.getComputedStyle(parent);
var parentWidth = parent.offsetWidth;
var parentPadding = parseFloat(parentStyle.paddingLeft) + parseFloat(parentStyle.paddingRight);

var newWidth = parentWidth - parentPadding; // 親のパディングを差し引いた幅を計算
document.querySelector('.fixed-reply-area').style.width = newWidth + 'px';
}
Loading

0 comments on commit 070822e

Please sign in to comment.