commit 64f4fcc83ec1b29449f11276d8f9030ff39d9239 Author: Tomáš Mládek Date: Wed Oct 17 13:22:43 2018 +0200 Initial commit. (all done by @madr) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac81552 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +outchat.db diff --git a/api.php b/api.php new file mode 100644 index 0000000..dd9207f --- /dev/null +++ b/api.php @@ -0,0 +1,43 @@ +escapeString(htmlspecialchars($_GET['timestamp'])); + $timestamp = ($timestamp == 0) ? strtotime('-6 hours') : $timestamp; + + $results = $database->query('SELECT * FROM messages WHERE timestamp > '.$timestamp); + + $messageArray = []; + while($row = $results->fetchArray(SQLITE3_ASSOC)) { + $row['datetime'] = date('d/m H:i', $row['timestamp']); + + $image_search = preg_match('/(http|https):\/\/[^ ]+(\.gif|\.jpg|\.jpeg|\.png)/', $row['text'], $out); + + if($image_search > 0){ + $row['text_processed'] = str_replace($out[0], '

', $row['text']); + } else { + $row['text_processed'] = $row['text']; + } + + $messageArray[] = $row; + } + echo json_encode($messageArray); +} + +if($action === 'createMessage'){ + $timestamp = time(); + $name = $database->escapeString(htmlspecialchars($_POST['name'])); + $text = $database->escapeString(htmlspecialchars($_POST['text'])); +/* + $payload = file_get_contents('php://input'); + $data = json_decode($payload); + var_dump($data); + */ + + $database->query('INSERT INTO messages (name, text, timestamp) VALUES ("'.$name.'", "'.$text.'", "'.$timestamp.'")'); +} + +?> \ No newline at end of file diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000..1252691 --- /dev/null +++ b/helpers.js @@ -0,0 +1,39 @@ +function htmlToElements(html) { + const template = document.createElement('template') + template.innerHTML = html + return template.content.childNodes +} + +function hashCode(str) { // java String#hashCode + var hash = 0; + for (var i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + return hash; +} + +function intToRGB(i){ + const c = (i & 0x00FFFFFF) + .toString(16) + .toUpperCase(); + + return "00000".substring(0, 6 - c.length) + c; +} + +function getCookie(name) { + const value = "; " + document.cookie; + const parts = value.split("; " + name + "="); + if (parts.length == 2) return parts.pop().split(";").shift(); +} + +function nl2br(str, is_xhtml){ + if (typeof str === 'undefined' || str === null) { + return ''; + } + var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '
' : '
'; + return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2'); +} + +function scrollWindowDown(){ + window.scrollTo(0, document.body.scrollHeight) +} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..ad764cb --- /dev/null +++ b/index.php @@ -0,0 +1,39 @@ + + + + + outposts + + + + + + + + + + + '; + } +?> + +
+
+ +
+ + + +
+ + + + + + \ No newline at end of file diff --git a/main.css b/main.css new file mode 100644 index 0000000..e0a1182 --- /dev/null +++ b/main.css @@ -0,0 +1,153 @@ +* { + box-sizing: border-box; +} + +html { + color: #fff; + background-color: #111; + font-family: Courier, Verdana; + font-size: 14px; +} + +body { + margin: 0; +} + +.chat { + width: 100%; + padding: 30px 30px 80px 30px; + position: relative; + overflow: auto; +} + +.message { + width: 100%; + margin-bottom: 40px; +} + +.message__info { + width: 100%; + margin-bottom: 5px; + line-height: 1; + display: flex; + align-items: flex-end; +} + +.message__info-name { + font-weight: 700; + margin-right: 15px; + font-size: 18px; + line-height: .8; +} + +.message__text { + position: relative; + white-space: pre-line; +} + +.message__text p { + margin: 0; +} + +.message__text img { + margin: 10px 0 0 0; + width: 100%; + max-width: 320px; + display: block; + height: auto; +} + +.form { + left: 15px; + bottom: 15px; + width: calc(100% - 30px); + height: 60px; + background-color: #fff; + position: fixed; + display: flex; +} + +.form__input-message { + padding: 20px; + width: calc(100% - 60px); + height: 100%; + border: 0; + outline: 0; + margin: 0; + font-size: 16px; + resize: none; + white-space: pre-line; +} + +.form__input-submit { + right: 0; + top: 0; + width: 60px; + height: 60px; + font-size: 30px; + font-weight: 700; + outline: 0; + border: 0; + cursor: pointer; + position: absolute; + background: none; +} + +.modal { + left: 0; + top: 0; + width: 100%; + height: 100%; + z-index: 100; + background-color: #000; + position: fixed; +} + +.modal__form { + width: 100%; + max-width: 600px; + height: 60px; + margin: 50px auto; + position: relative; +} + +.modal__form-input { + padding: 0 90px 0 30px; + width: 100%; + height: 100%; + border: 0; + outline: 0; + font-size: 16px; +} + +.modal__form-submit { + right: 0; + top: 0; + width: 60px; + height: 60px; + font-size: 30px; + font-weight: 700; + outline: 0; + border: 0; + cursor: pointer; + position: absolute; + background: none; +} + + + +@media (max-width: 640px) { + .chat { + padding: 10px 10px 50px 10px; + } + + .form { + left: 10px; + bottom: 10px; + width: calc(100% - 20px); + } + + .message { + margin-bottom: 25px; + } +} \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..d9cbfea --- /dev/null +++ b/main.js @@ -0,0 +1,112 @@ +// modal form handle +if(document.querySelector('.modal__form-submit')){ + document.querySelector('.modal__form-submit').addEventListener('click', function(e){ + e.preventDefault() + const value = document.querySelector('.modal__form-input').value + if(value.length >= 3){ + var date = new Date(Date.now()) + date = date.setTime(date.getTime() + (90*24*60*60*1000)) + date = new Date(date) + const expires = '; expires=' + date.toUTCString() + document.cookie = 'outchat_name=' + (value || '') + expires + '; path=/' + window.location.href = '' + } + }) +} + +document.querySelector('.form__input-message').addEventListener('keydown', function(e){ + if(e.ctrlKey && e.keyCode == 13){ + document.querySelector('.form__input-submit').click() + } +}) + +document.querySelector('.form__input-submit').addEventListener('click', function(e){ + e.preventDefault() + + const name = getCookie('outchat_name') + const text = document.querySelector('.form__input-message').value + document.querySelector('.form__input-message').value = '' + + var formData = new FormData() + formData.append(name, text) + + fetch('api.php?action=createMessage', { + method: 'post', + headers: { + "Content-Type": "application/x-www-form-urlencoded" + }, + body: 'name='+name+'&text='+text + }) + .then(function(data){ + getMessages() + }) + .catch(function(error){ + console.log(error) + }) +}) + +function getMessages(){ + const timestamp = (document.querySelector('.chat').lastElementChild) ? document.querySelector('.chat').lastElementChild.getAttribute('data-timestamp') : 0 + + fetch('api.php?action=getMessages×tamp='+timestamp) + .then(function(data){ + return data.json() + }) + .then(function(data){ + if(data.length > 0){ + if((window.scrollY + window.innerHeight) == document.body.scrollHeight){ + setTimeout(function(){ + scrollWindowDown() + }, 100) + } + for(message of data){ + createMessageNode(message.name, message.text_processed, message.timestamp, message.datetime) + } + } + }) + .catch(function(error){ + console.log(error) + }) +} + +function createMessageNode(name, text, timestamp, datetime){ + const elementMain = document.createElement('div', { class: 'message' }) + const elementText = document.createElement('div', { class: 'message__text'}) + const elementInfo = document.createElement('div', { class: 'message__info'}) + const elementName = document.createElement('div', { id: 'message__info-name'}) + const elementDatetime = document.createElement('div', { id: 'message__info-datetime'}) + const contentName = document.createTextNode(name) + const contentDatetime = document.createTextNode('['+datetime+']') + //const contentText = document.createTextNode(text) + + // element creation + elementMain.classList.add('message') + elementText.classList.add('message__text') + elementInfo.classList.add('message__info') + elementDatetime.classList.add('message__info-datetime') + elementName.classList.add('message__info-name') + + // "hash" name color + elementName.style.color = "#"+intToRGB(hashCode(name)) + + // append everything to chat + elementName.appendChild(contentName) + elementDatetime.appendChild(contentDatetime) + elementText.innerHTML = text + + elementInfo.appendChild(elementName) + elementInfo.appendChild(elementDatetime) + + elementMain.appendChild(elementInfo) + elementMain.appendChild(elementText) + elementMain.setAttribute('data-timestamp', timestamp) + + document.querySelector('.chat').appendChild(elementMain) + + return true +} + +getMessages() +setInterval(function(){ + getMessages() +}, 2000) diff --git a/outchat-ddl.sql b/outchat-ddl.sql new file mode 100644 index 0000000..45b1d49 --- /dev/null +++ b/outchat-ddl.sql @@ -0,0 +1,7 @@ +CREATE TABLE `messages` ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT, + `text` TEXT, + `timestamp` INTEGER +); +