<?php
include_once('../life.php');
$life = new life();
// if(!file_exists('chat.txt')) {
// $put_result = file_put_contents('chat.txt', 'chat');
// if(!$put_result) {
// chmod('..', 0777);
// $put_result = file_put_contents('chat.txt', 'chat');
// }
// if(!$put_result) {
// $life->fatal_error('permissions problem; solve on the webserver manually');
// }
// }
$source = $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$to = urlencode($_REQUEST['to']);
$to_local = false;
if($to == false) {
$to_local = true;
} else {
$fileless_source = $life->fileless($life->absolutize($life->scheme . '://' . $source));
$fileless_to = $life->fileless($life->absolutize($to));
//print('$fileless_source, $fileless_to: ');var_dump($fileless_source, $fileless_to);exit(0);
if($fileless_source === $fileless_to) {
$to_local = true;
}
}
if($to_local && !file_exists($to . '.xml')) { // only write files locally!
file_put_contents($to . '.xml', '');
}
$recipients = array();
$handle = opendir('.');
while(($entry = readdir($handle)) !== false) {
if($entry === '.' || $entry === '..') {
// ignore it
} elseif(is_dir($entry)) {
// ignore it
} else {
$file_extension = file_extension($entry);
//if($file_extension === '.xml') {
if($file_extension === 'xml') {
// assume it's a chat log
$recipients[] = substr($entry, 0, strpos_last($entry, $file_extension) - 1);
}
}
}
closedir($handle);
asort($recipients);
$random = rand(0, 9001);
function file_extension($string) {
return pathinfo($string)['extension'];
print('what about basename constant, there may be an extension constant');exit(0);
if(strpos($string, '://') !== false && substr_count($string, '/') < 3 /* (=2) */) { // it's a naked domain so don't grab .com or .org or whatever as the extension
return false;
}
// anchor # always comes after query string ?
//$last_hash_position = life::strpos_last($string, '#'); // would like to use life's function... which would mean chat would become an action in the contructor
$last_hash_position = strpos_last($string, '#');
if($last_hash_position !== false) {
$string = substr($string, 0, $last_hash_position);
}
$string = str_replace('\\', '/', $string);
$last_slash_position = strpos_last($string, '/');
$last_question_position = strpos_last($string, '?');
if($last_question_position === false) {
$last_question_position = strpos_last($string, '9o9quest9o9');
}
if($last_question_position == false) {
$last_dot_position = strpos_last($string, '.');
} else {
$last_dot_position = strpos_last(substr($string, 0, $last_question_position), '.');
}
if($last_dot_position === false || $last_dot_position < $last_slash_position/* || $last_dot_position < strpos_last($string, '\\')*/) {
//if($last_question_position === false) {
return false;
/*} else {
return '.' . substr($string, $last_slash_position + 1, $last_question_position - $last_slash_position - 1);
}*/
} elseif($last_question_position === false) {
if($last_dot_position === false) {
return false;
} else {
return substr($string, $last_dot_position);
}
} elseif($last_question_position < $last_dot_position) { // this is pretty wacky
$last_dot_between_slash_and_question_position = strpos_last(substr($string, 0, $last_question_position), '.', $last_slash_position);
if($last_question_position < $last_dot_between_slash_and_question_position) {
print('$string, $last_question_position, $last_dot_position: ');var_dump($string, $last_question_position, $last_dot_position);
fatal_error('not sure how to calculate file_extension from these');
return false;
} else {
return substr($string, $last_dot_between_slash_and_question_position, $last_question_position - $last_dot_between_slash_and_question_position);
}
} else {
return substr($string, $last_dot_position, $last_question_position - $last_dot_position);
}
return false; // should never get here if there are enough conditions above to handle everything
}
function strpos_last($haystack, $needle, $offset = 0) {
//print('$haystack, $needle: ');var_dump($haystack, $needle);
return strrpos($haystack, $needle, -1 * $offset);
if(strlen($needle) === 0) {
return false;
}
$len_haystack = strlen($haystack);
$len_needle = strlen($needle);
$pos = strpos(strrev($haystack), strrev($needle), $offset);
if($pos === false) {
return false;
}
return $len_haystack - $pos - $len_needle;
}
//print('$source, $recipients: ');var_dump($source, $recipients);
$title = 'live_browser chat';
?>
<!-- <!DOCTYPE html> -->
<html>
<head>
<title><?php print($title); ?></title>
<script src="jquery-3.6.0.min.js"></script>
<!--script src="twemoji.min.js"></script-->
<script src="DisMojiPicker.js"></script>
<link rel="stylesheet" href="emojis.css" />
<script src="correctingInterval.js"></script>
<script>
$(document).ready(function(){
//refreshing = false;
//updating = false;
emojis_picker_open = false;
random = <?php print($random); ?>;
debug_counter = 0;
refresh_interval = 100; // in milliseconds; every 0.1 seconds; should be interactive enough for chat while not overstraining server resources
//var intervalID = window.setInterval(live, 10000); // every 10 seconds
activity_factor = 0;
//last_action_time = 9652210734000; // random number; something like the year 2411, in milliseconds whoops! past 2039?!?
//alert('initial refresh_interval, activity_factor, last_action_time, millitime(): ' + refresh_interval + ', ' + activity_factor + ', ' + last_action_time + ', ' + millitime());
last_action_time = millitime();
//alert('initial refresh_interval, activity_factor, last_action_time, millitime(): ' + refresh_interval + ', ' + activity_factor + ', ' + last_action_time + ', ' + millitime());
//var livingID = window.setInterval(test1(), refresh_interval); // don't use brackets because reasons
//var livingID = window.setInterval(live, refresh_interval);
//var livingID = setInterval(live, refresh_interval);
//var interval = interval(live, get_refresh_interval(), 86400);
//var livingID = setCorrectingInterval(live, get_refresh_interval());
var intervals = [];
//intervals.push(setCorrectingInterval(live, get_refresh_interval()));
intervals.push(setCorrectingInterval(refresh, get_refresh_interval()));
//initial_time = millitime();
reset_user_activity();
to = '<?php print($to); ?>';
if(to != false) {
set_recipient(to);
}
/*$("#emojis").disMojiPicker();
twemoji.parse(document.body);
$("#emojis").picker(
emoji => console.log(emoji)
);*/
$("#emojis").disMojiPicker();
//$("#emojis").picker(emoji => console.log(emoji));
//$("#emojis").picker(console.log('uh test'));
$("#emojis").picker();
//$("#emojis").disMojiPicker(emoji => console.log(emoji));
//$("#emojis").picker(emoji => $('#message').append(emoji));
//$("#emojis").disMojiPicker(emoji => $('#message').append(emoji));
//twemoji.parse(document.body); // time consuming... what does it do?
// $('body').click(function() {
// alert('clicked body; emojis_picker_open: ' + emojis_picker_open);
// if(emojis_picker_open) {
// close_emojis_picker();
// }
// });
$('#toggle_picker').click(function() {
//alert('toggle_picker clicked; display attribute is: ' + $("#emojis").css('display'));
if(emojis_picker_open) {
close_emojis_picker();
} else {
open_emojis_picker();
}
});
function open_emojis_picker() {
//alert('opening emojis picker');
$("#emojis").css('display', 'block');
//$("#toggle_picker").css('top', '-100px');
// $("#toggle_picker").css('left', '-502px');
emojis_picker_open = true;
}
function close_emojis_picker() {
//alert('closing emojis picker');
$("#emojis").css('display', 'none');
//$("#toggle_picker").css('top', '-150px');
// $("#toggle_picker").css('left', '-100px');
emojis_picker_open = false;
}
$counter = 0; // is used for sound, and...?
function new_chat_recieved() {
chat_integer = Math.floor(Math.random() * 3) + 1; // pick random keyboard sound effect
new_audio(1, 'chat-' + chat_integer + '.ogg');
}
function new_audio(volume, source = false) {
if(source == false) {
sound = 'expand.wav';
}
//id = id + $counter;
setTimeout(function(){
$('<audio id="sound' + ($counter + 1) + '" class="sound-player" autoplay="autoplay" style="display:none;">'
+ '<source src="' + source + '" />'
+ '<embed src="' + source + '" hidden="true" autostart="true" loop="false"/>'
+ '</audio>'
).appendTo('body');
//$('audio').volume = 1/10;
document.getElementById('sound' + ($counter + 1)).volume = volume;
});
$counter++;
// could use class sound-player to play the sound again, for instance. e.g.:
// stopSound: function () {
// $(".sound-player").remove();
// }
}
function reset_user_activity() {
//alert('reset user activity');
//last_user_activity = millitime();
unseen_chats = 0;
}
$('html').keyup(function(e){
reset_user_activity();
});
$('html').click(function(e){
reset_user_activity();
});
$('#message').bind("enterKey",function(e){
//alert("Enter");
send_message(true);
});
$('#message').keyup(function(e){
if(e.keyCode == 13) {
$(this).trigger("enterKey");
}
});
$('#send_message').click(function() {
send_message();
});
// $('#other_recipient').bind("otherenterKey",function(e){
// //alert("Enter");
// set_recipient();
// });
// $('#other_recipient').keyup(function(e){
// if(e.keyCode == 13) {
// $(this).trigger("otherenterKey");
// }
// });
// $('#set_other_recipient').click(function() {
// set_recipient();
// });
$('#local_recipients').click(function() {
update_all_local_recipients_activity();
});
$('#local_recipients').change(function() {
//$('#local_recipients').mouseup(function() {
die();
$('#chat_log').empty();
$('#other_recipient').val('');
refresh();
//live();
//update();
});
$('#other_recipient').keyup(function() {
die();
$('#chat_log').empty();
set_recipient($(this).val());
refresh();
//live();
//update();
});
function get_refresh_interval() {
return refresh_interval * Math.pow(2, activity_factor);
}
function test1() {
console.log(test1);
}
function live() {
//debug_counter++;
//if(debug_counter > 200) {
// return;
//}
//alert('last_action_time in live(): ' + last_action_time);
elapsed_time = millitime() - last_action_time;
//elapsed_interval = millitime() - last_action_time; // why does javascript need this syntactically..?
//alert('last_action_time, millitime(), get_refresh_interval(), elapsed_time, 10 * get_refresh_interval(), elapsed_time > 10 * get_refresh_interval(): ' + last_action_time + ', ' + millitime() + ', ' + get_refresh_interval() + ', ' + elapsed_time + ', ' + 10 * get_refresh_interval() + ', ' + (elapsed_time > 10 * get_refresh_interval()));
if(activity_factor > 9) {
// console.log('greatest activity factor (standby mode)');
//var timeoutID = window.setTimeout(refresh(), get_refresh_interval());
} else if(elapsed_time > 10 * get_refresh_interval()) { // then ratchet it up
//} else if(last_action_time - millitime() > 0.01 * get_refresh_interval()) { // then ratchet it up (since it's in milliseconds; multiplying by 0.01 = dividing by 1000 then multiplying by 10)
//last_action_time = millitime();
activity_factor++;
// console.log('increased activity factor by one to: ' + activity_factor);
//alert('activity_factor, get_refresh_interval(): ' + activity_factor + ', ' + get_refresh_interval());
relive();
}// else {
// console.log('living');
// clearInterval(livingID);
// var livingID = window.setTimeout(live(), get_refresh_interval());
// //sleep(get_refresh_interval());
// //live2();
// refresh();
//}
// console.log('living');
update();
}
function relive() {
//alert('livingID before clear: ' + livingID);
//alert('interval before clear: ' + interval);
//clearInterval(livingID);
//interval.clear();
// Later in your script...
//clearCorrectingInterval(livingID);
clear_all_intervals(); // shouldn't be necessary if we had a handle on the IDs but works...!
//alert('livingID after clear: ' + livingID);
//alert('interval after clear: ' + interval);
//var livingID = window.setInterval(live, get_refresh_interval()); // can comment out for debug after first activity factor
//var livingID = setInterval(live, get_refresh_interval()); // can comment out for debug after first activity factor
//var livingID = setCorrectingInterval(live, get_refresh_interval());
intervals.push(setCorrectingInterval(live, get_refresh_interval()));
//var interval = interval(live, get_refresh_interval(), 86400);
//alert('livingID after reset: ' + livingID);
//alert('interval after reset: ' + interval);
}
function die() {
clear_all_intervals();
last_action_time = millitime();
activity_factor = 10;
}
function update_local_recipients_activity() { // alias
return update_all_local_recipients_activity();
}
function update_all_local_recipients_activity() {
$('#local_recipients option').each(function(){
//alert('$(this).val() in update_all_local_recipients_activity(): ' + $(this).val());
if($(this).val() == random) {
// leave it
} else {
update_local_recipient_activity($(this).val());
}
});
}
function update_local_recipient_activity(local_recipient) {
//alert('update_local_recipient_activity()');
if(local_recipient == random) {
return false;
}
$.ajax({
type: 'GET',
url: 'last_active.php',
data: { to: local_recipient },
success: function(data) {
//last_active = Math.floor(data - last_action_time);
//alert('data, last_active in update_local_recipient_activity(): ' + data + ', ' + last_active);
//alert('data in update_local_recipient_activity(): ' + data);
dec_local_recipient = $('#local_recipients option[value="' + local_recipient + '"]').attr('dec');
updated_contents = dec_local_recipient + ' (last active ' + data + ' ago)';
$('#local_recipients option[value="' + local_recipient + '"]').html(updated_contents);
//$('option').html(updated_contents);
//$('option[value="' + local_recipient + '"]').html(updated_contents);
//$('#testdiv').html(updated_contents);
}
});
}
function update_title() {
//$('#link1').click(function(){
//milliseconds_passed = Math.floor(millitime() - initial_time);
//seconds_passed = Math.floor((millitime() - initial_time) / 1000);
//$('head title', window.parent.document).text('(' + seconds_passed + ') new');
//});
// what about blinking?
// what about favicon?
if(unseen_chats > 0) {
$('head title', window.parent.document).text('(' + unseen_chats + ') <?php print($title); ?>');
} else {
$('head title', window.parent.document).text('<?php print($title); ?>');
}
}
function clear_all_intervals() {
// pretty hacky
// notice it may not work if we send more than 100 messages in a session! the proper solution would be to keep track of the interval IDs such as in an array
//counter = 0;
//while(counter < 100) {
// clearCorrectingInterval(counter);
// counter++;
//}
for(let index = 0; index < intervals.length; ++index) {
const element = intervals[index];
// ...use `element`...
clearCorrectingInterval(element);
}
}
function interval(func, wait, times){
var interv = function(w, t){
return function(){
if(typeof t === "undefined" || t-- > 0){
setTimeout(interv, w);
try{
func.call(null);
}
catch(e){
t = 0;
throw e.toString();
}
}
};
}(wait, times);
setTimeout(interv, wait);
return { clear: function() { t = 0 } };
};
// interval(function(){
// // Code block goes here
// }, 1000, 10);
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
//function refresh(force = false) {
function refresh() {
// if(refreshing) {
// return false;
// }
// refreshing = true;
// refresh the chat
//local_recipients other_recipient
to = get_recipient();
if(to === random) { // blank it <-- hackers
to = '';
}
//alert('to in refresh: ' + to);
//if(force) {
// $('#chat_log').empty();
//}
//chat_log_html = $('#chat_log').html();
//if(chat_log_html.trim() === '') {
// time = 0; // so that all the messages are gotten
//} else {
// time = last_action_time;
//}
$.ajax({
type: 'GET',
url: 'refresh.php',
//data: {person_id:getUserID},
data: { to: to, source: '<?php print($source) ?>' },
headers: {
// Header_Name_One: 'Header Value One', //If your header name has spaces or any other char not appropriate
// "Header Name Two": 'Header Value Two' //for object property name, use quoted notation shown in second
// 'Accept': 'blah',
// 'Sec-Fetch-Site': 'cross-origin',
// 'Sec-Fetch-Mode': 'no-cors',
},
success: function(data) {
//alert('data from refresh.php: ' + data);
// would like to only get new but that's more complicated
//$("#processing").hide();
//$("#person-data").html(data);
// if there's a change (hack, instead of only returning changed content from the .xml)
//alert('data, $(\'#chat_log\').html(): ' + data + ', ' + $('#chat_log').html());
//alert('last_action_time, time: ' + last_action_time + ', ' + time);
//if(data.length > 0) {
//if(data.length > 0 && last_action_time == time) {
if(data.length > 0) {
$('#chat_log ').empty(); // because of async...
$('#chat_log').append(data);
//alert('reset action by refresh!');
last_action_time = millitime();
activity_factor = 0;
relive();
//refresh();
} // otherwise assume it was refreshed asynchronously already
}
});
update_all_local_recipients_activity();
// refreshing = false;
}
function update() {
// if(updating) {
// return false;
// }
// updating = true;
// update the chat
//local_recipients other_recipient
to = get_recipient();
//if(force) {
// $('#chat_log').empty();
//}
chat_log_html = $('#chat_log').html();
if(chat_log_html.trim() === '') {
time = 0; // so that all the messages are gotten
} else {
time = last_action_time;
}
//console.log('updating, time: ' + to + ', ' + time);
//alert('updating; to, time: ' + to + ', ' + time);
$.ajax({
type: 'GET',
url: 'update.php',
//data: {person_id:getUserID},
data: { to: to, time: time },
headers: {
// Header_Name_One: 'Header Value One', //If your header name has spaces or any other char not appropriate
// "Header Name Two": 'Header Value Two' //for object property name, use quoted notation shown in second
// 'Accept': 'blah',
// 'Sec-Fetch-Site': 'cross-origin',
// 'Sec-Fetch-Mode': 'no-cors',
},
success: function(data) {
//alert('data from update.php: ' + data);
// would like to only get new but that's more complicated
//$("#processing").hide();
//$("#person-data").html(data);
// if there's a change (hack, instead of only returning changed content from the .xml)
//alert('data, $(\'#chat_log\').html(): ' + data + ', ' + $('#chat_log').html());
//alert('last_action_time, time: ' + last_action_time + ', ' + time);
//if(data.length > 0) {
//if(data.length > 0 && last_action_time == time) {
if(data === chat_log_html) { // avoid duplication; intended for <code like NO COMMUNICATIONS and HTTP but also affects duplicated messages (which should be impossible)
} else if(typeof data !== 'undefined' && data.length > 0 && (time == 0 || last_action_time == time)) {
//$('#chat_log ').empty();
$('#chat_log').append(data);
//alert('reset action by update!');
last_action_time = millitime();
activity_factor = 0;
if(data.IndexOf('<code') === 0) {
} else {
new_chat_recieved();
unseen_chats++;
relive();
//update();
}
} // otherwise assume it was refreshed asynchronously already
}
});
update_local_recipient_activity($('#local_recipients option:selected').val());
update_title();
// updating = false;
}
function set_recipient(recipient) {
//alert('set_recipient recipient: ' + recipient);
//$("#local_recipients select").val('');
//$('#local_recipients option[value=""]').attr('selected','selected'); // first blank it
$.ajax({
type: 'GET',
url: 'urlencode.php',
data: { string: recipient },
success: function(data) {
recipient = data;
}
});
$('#local_recipients option').removeAttr('selected');
if($('#local_recipients option[value="' + recipient + '"]').length) { // bit wierd, but an existing element has a length so this functions as a check for whether the element exists
$('#local_recipients option[value="' + recipient + '"]').attr('selected','selected'); // then set to an existing one (if possible)
} else {
$('#local_recipients option[value="' + random + '"]').attr('selected','selected'); // blank it
}
// would like to add recipient to the list...
}
function get_recipient() {
local_recipient = $('#local_recipients option:selected').val();
//local_recipient = $('#local_recipients option:selected').attr('dec'); // this may be different from val
other_recipient = $('#other_recipient').val();
// alert('local_recipient, other_recipient, random in get_recipient: ' + local_recipient + ', ' + other_recipient + ', ' + random);
//if(local_recipient.length > 0) { // <-- hackers
if(local_recipient == random) {
recipient = other_recipient;
} else if(other_recipient.length === 0) {
recipient = local_recipient;
} else {
if(other_recipient.length > 0) {
recipient = other_recipient;
} else {
recipient = '';
}
}
return recipient;
}
// $.post('testajax.php', { }, function( data ) {
// alert('data from testajax.php: ' + data);
// }); // works
// $.ajax({
// type: 'GET',
// url: 'testajax.php',
// data: { },
// success: function(data) {
// alert('data from testajax.php: ' + data);
// }
// }); // works
function send_message(enter_sent = false) {
//alert('send message');
// local
source = '<?php print($source) ?>';
from = $('#user').val();
to = get_recipient();
divider_string = '?to=';
question_position = to.indexOf(divider_string);
//alert('divider_string, question_position: ' + divider_string + ', ' + question_position);return;
if(question_position != -1) {
//alert('cross site message!');
temp_to = to;
url = temp_to.substr(0, question_position);
to = temp_to.substr(question_position + divider_string.length, temp_to.length - question_position - divider_string.length);
} else {
url = 'new_message.php';
}
time = millitime() / 1000;
message = $('#message').val();
//message = message.trim(); // sending the message with enter also adds newline to the end of the message
if(enter_sent) {
message = message.substr(0, message.length - 1);
}
// don't do .val without brackets! breaks things; could be exploited
//alert('url, source, from, to, time, message: ' + url + ', ' + source + ', ' + from + ', ' + to + ', ' + time + ', ' + message);
// $.post('new_message.php', { source: source, from: from, time: time, message: message }, function( data ) {
// alert('data from new_message.php: ' + data);
// $('#chat_log').append(data);
// });
//alert('source, from, to, time, message in send_message(): ' + source + ', ' + from + ', ' + to + ', ' + time + ', ' + message);
$.ajax({
type: 'GET',
url: url,
//data: {person_id:getUserID},
data: { source: source, from: from, to: to, time: time, message: message },
headers: {
// Header_Name_One: 'Header Value One', //If your header name has spaces or any other char not appropriate
// "Header Name Two": 'Header Value Two' //for object property name, use quoted notation shown in second
// 'Accept': 'blah',
// 'Sec-Fetch-Site': 'cross-origin',
// 'Sec-Fetch-Mode': 'no-cors',
},
success: function(data) {
//alert(data);
//alert('data from new_message.php: ' + data);
//$("#processing").hide();
//$("#person-data").html(data);
$('#chat_log').append(data);
scroll_chat_log();
//setTimeout(scroll_chat_log(), refresh_interval * 20);
//alert('reset action by send_message!');
last_action_time = millitime();
activity_factor = 0;
relive();
//refresh();
}
});
$('#message').val(''); // empty the message box
// remote
// scroll the message box to the bottom
//setTimeout(scroll_chat_log(), refresh_interval / 2);
//$('#chat_log').scrollIntoView();
//$('#chat_log').scrollTop(this.offsetHeight);
close_emojis_picker();
//$("#emojis").disMojiPicker();
//$("#emojis").picker();
}
function millitime() {
//return millitime();
d = new Date();
return d.getTime();
//time = d.getTime();
//return time;
}
function scroll_chat_log() {
var chat_log = document.getElementById('chat_log');
chat_log.scrollTop = chat_log.scrollHeight; // no idea why this mostly does not work (on time?)
}
function dropHandler(ev) {
console.log('File(s) dropped');
// Prevent default behavior (Prevent file from being opened)
ev.preventDefault();
if (ev.dataTransfer.items) {
// Use DataTransferItemList interface to access the file(s)
for (let i = 0; i < ev.dataTransfer.items.length; i++) {
// If dropped items aren't files, reject them
if (ev.dataTransfer.items[i].kind === 'file') {
const file = ev.dataTransfer.items[i].getAsFile();
console.log('? file[' + i + '].name = ' + file.name);
}
}
} else {
// Use DataTransfer interface to access the file(s)
for (let i = 0; i < ev.dataTransfer.files.length; i++) {
console.log('? file[' + i + '].name = ' + ev.dataTransfer.files[i].name);
}
}
}
function dragOverHandler(ev) {
alert('drag over event');
}
$('#message').focus();
});
</script>
<style>
/*
consciousness parameters orange yellow red
space () -> black
sky (words) -> light blue
trees (forest) -> green
water (buttons) -> blue (transparent)
earth (bottom) -> (dark) brown
*/
body { background-color: #223322; }
body { background: url(back4.jpg); }
#chat { /*height: 99%; border: 1px solid red;*/ /*background: url(back3.jpg);*/ }
#participants { height: 10%; overflow-y: scroll; }
#chat_log { /*border: 1px solid black;*/ /*overflow: scroll;*/ height: 80%; overflow-y: scroll; overflow-x: hidden; }
#input { width: 100%; position: fixed; top: 90%; height: 10%; vertical-align: top; }
#send_message { /*height: 90%; margin-top: -80px; why */ }
button { }
#participants { color: #DDCCAA; color: #000000; }
#chat_log { color: #CCCCDD; color: #000000; /*background-color: #223322;*/ /*border: 4px inset blue;*/ }
#input { color: #CCCCDD; color: #000000; /*background-color: #223322;*/ }
#root { float: right; margin-right: 10px; }
#message { min-height: 20px; height: 100%; }
#send_message { min-height: 20px; height: 100%; }
#toggle_picker { position: fixed; /*bottom: -30px; left: -30px;*/ min-height: 20px; height: 10%; }
#emojis { z-index: 105; min-height: 20px; height: 10%; }
#drop_zone { z-index: 105; min-height: 20px; height: 10%; }
#send_message { width: 50px; }
#message, #send_message, #toggle_picker, #emojis, #drop_zone { float: left; }
code { text-transform: uppercase; }
#drop_zone {
border: 5px solid blue;
width: 200px;
height: 100px;
display: none;
}
</style>
</head>
<body>
<div id="chat">
<div id="participants">
<label for="user"><img src="merkaba_small.jpg" alt="Merkaba" /> Me: </label><input type="text" id="user" name="user" /><br />
<label for="local_recipients"><img src="fractal_destination_small.jpg" alt="Fractal Destination" /> To: </label>
<select id="local_recipients" name="local_recipients">
<?php
//print('<option value="" title="title on an option (for )"> (open)</option>' . PHP_EOL);
print('<option value="' . $random . '"></option>' . PHP_EOL); // you, who are looking at this code, are welcome to play around ;p
foreach($recipients as $recipient) {
// could do all the fancy stuff like blocking access, keeping track of friends, avoiding spoofing
/*print('<option value="' . $destination . '?to=' . $recipient . '">' . $recipient . ' (last activity an unknown time ago)</option>
');*/
// local for now
//print('<option value="' . $recipient . '" title="title on an option (for ' . $recipient . ')">' . $recipient . ' (last activity an unknown time ago)</option>' . PHP_EOL);
if($recipient === '') {
print('<option value="' . $recipient . '" dec="' . urldecode($recipient) . '" selected="selected">' . urldecode($recipient) . ' (last activity an unknown time ago)</option>' . PHP_EOL);
} else {
print('<option value="' . $recipient . '" dec="' . urldecode($recipient) . '">' . urldecode($recipient) . ' (last activity an unknown time ago)</option>' . PHP_EOL);
}
// live, last activity
}
// - expand new chat column (+). no need; just open multiple tabs for now and generalize into live_browser functionality
// - green + ?? morph to red X ?
// + enter to send message
// - delete own messages? there are not accounts!
// + load previous messages
// + remove all hard-coded
// + only refresh since last check (use <time>)
// - autoscroll excludes last line; not sure why
// + autofocus to chat (which allows everybody to chat to everyone and see all messages by default; not really scalable (to the universe!))
// x emojis and twitch emotes... ;p better twitch tv
// / figure out why can't add emotes sometimes, why chat doubles content sometimes, typing the recipient causes MULTIPLE chat log duplication, emojis sometimes do not work after sending a message... are these related?
// x int clear_all_intervals() { // pretty hacky
// + get chat to show on chat2, reduce resources used
// x int http return codes; don't need a list and interpretation when they are being shown directly unfiltered to the user!
// x message if "connection" is not made; if user meh
// x should be able to type ../chat2 or ../chat2/index.php or ../chat2/new_message.php or ../chat2/new_message.php?to=myfriend into other recipient
// + last activity an unknown time ago ... number new messages
// - takes super long since basic local recipients are causing NO COMMUNICATIONS
// - online indicator... ? make it more interesting than green circle
// - 3D message box(es)
// update title tab when new message (1) blinking
// unseen chats not working
// drag and drop content into chat (emojis, images, videos?)
// sound effects. Autoplay is only allowed when approved by the user, the site is activated by the user, or media is muted. ... sound sometimes works
// dark green (text) trees on pale blue sky (background)
// computer digital stuff on glass surface in front of natural imagery like church windows separating inside from out
// wind sound instead of keyboard ... chatting up a storm
// have to think about chat logs not being saved as typed because of, for instance, spaces creating bad HTTP requests when chatting with a remote getting turned into pluses in the filename... and maybe more characters... urlencode() and have to deal with recipients with + in their name etc.
// emojis sometimes don't work; why?
// emojis stop working after chatting
// x emojis ugly
// write test
// test
// wadlof
// backups of remote chats
// bugs:
// memory leak
// have to shift-refresh page to get emojis to work after other input...
?>
</select>
or <label for="other_recipient">other: </label><input type="text" id="other_recipient" name="other_recipient" size="60" placeholder="www.google.com/live_browser/chat/new_message.php?to=myfriend123" /><!--button id="set_other_recipient" name="set_other_recipient">Set</button-->
</div>
<div id="emojis"></div>
<div id="chat_log">
</div>
<div id="input">
<textarea id="message" name="message" cols="42" rows="3"></textarea>
<button id="send_message" name="send_message">Send</button>
<button id="toggle_picker">?</button>
<div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
<p>Drag one or more files to this <i>drop zone</i>.</p>
</div>
<div id="root"><a href="https://github.com/freementls/live_browser"><img src="root.png" width="32" height="32" /></a></div>
<!--div id="testdiv"><a href="https://github.com/freementls/live_browser"><img src="root.png" width="32" height="32" /></a></div-->
</div>
</div>
</body>
</html>
|