mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 21:15:07 +02:00
Merge remote-tracking branch 'upstream/kasen/core' into Winstall-brand
This commit is contained in:
commit
c665f101af
9 changed files with 10448 additions and 1 deletions
438
scripts/communityModules/chat/FloofChat.html
Normal file
438
scripts/communityModules/chat/FloofChat.html
Normal file
|
@ -0,0 +1,438 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head draggable="false">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Title</title>
|
||||||
|
|
||||||
|
<!--Import Google Icon Font-->
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
<!--Import materialize.css-->
|
||||||
|
<link type="text/css" rel="stylesheet" href="css/materialize.css" media="screen,projection"/>
|
||||||
|
<link type="text/css" rel="stylesheet" href="css/FloofChat.css" media="screen,projection"/>
|
||||||
|
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Raleway:300,400,600,700" rel="stylesheet">
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="Content row">
|
||||||
|
<div class="col s12 valign-wrapper" style="padding: 10px;">
|
||||||
|
<ul class="tabs tabs-fixed-width z-depth-2 col s6" id="tabs">
|
||||||
|
<li class="tab col s2"><a class="black-text active" href="#Local">Local</a></li>
|
||||||
|
<li class="tab col s2"><a class="black-text" href="#Domain">Domain</a></li>
|
||||||
|
<li class="tab col s2"><a class="black-text" href="#Grid">Grid</a></li>
|
||||||
|
</ul>
|
||||||
|
<span class="col s1">
|
||||||
|
</span>
|
||||||
|
<div class="switch muteSwitch col s2">
|
||||||
|
<label>
|
||||||
|
<span style="font-size: 20px" id="muteText">Mute</span>
|
||||||
|
<input type="checkbox" id="muteInput" onclick="muteSwitchToggle()">
|
||||||
|
<span class="lever waves-light"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="col s1">
|
||||||
|
</span>
|
||||||
|
<a class="waves-effect waves-light btn col s2" onclick="redock()">Redock</a>
|
||||||
|
</div>
|
||||||
|
<div id="Local" class="ChatLog col s12"></div>
|
||||||
|
<div id="Domain" class="col s12 ChatLog"></div>
|
||||||
|
<div id="Grid" class="col s12 ChatLog"></div>
|
||||||
|
<input type="text" class="ChatInputText col s12" id="ChatInputText" size="256" placeholder="Type here">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var muted = {"Local": false, "Domain": false, "Grid": false};
|
||||||
|
var instance;
|
||||||
|
var appUUID;
|
||||||
|
var messageData = {}; // The data that is sent along with the message.
|
||||||
|
var $ChatLog; // The scrolling chat log.
|
||||||
|
var $ChatInputText; // The text field for entering text.
|
||||||
|
var userName;
|
||||||
|
|
||||||
|
//Start George Function
|
||||||
|
//Function provided by George Deac
|
||||||
|
//linky function
|
||||||
|
(function ($) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
$.fn.linky = function (options) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $el = $(this),
|
||||||
|
linkifiedContent = _linkify($el, options);
|
||||||
|
var formattedContent = replaceFormatting(linkifiedContent);
|
||||||
|
|
||||||
|
$el.html(formattedContent);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function _linkify($el, options) {
|
||||||
|
var links = {
|
||||||
|
twitter: {
|
||||||
|
baseUrl: "https://twitter.com/",
|
||||||
|
hashtagSearchUrl: "hashtag/"
|
||||||
|
},
|
||||||
|
instagram: {
|
||||||
|
baseUrl: "http://instagram.com/",
|
||||||
|
hashtagSearchUrl: null // Doesn't look like there is one?
|
||||||
|
},
|
||||||
|
github: {
|
||||||
|
baseUrl: "https://github.com/",
|
||||||
|
hashtagSearchUrl: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultOptions = {
|
||||||
|
mentions: false,
|
||||||
|
hashtags: false,
|
||||||
|
urls: true,
|
||||||
|
linkTo: "twitter" // Let's default to Twitter
|
||||||
|
},
|
||||||
|
extendedOptions = $.extend(defaultOptions, options),
|
||||||
|
elContent = $el.html(),
|
||||||
|
// Regular expression courtesy of Matthew O'Riordan, see: http://goo.gl/3syEKK
|
||||||
|
urlRegEx = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;,:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+,~%\/\.\w\-]*)?\??(?:[\-\+=&;,:%@\.\w]*)#?(?:[\.\!\/\\\w]*))?)/g,
|
||||||
|
matches;
|
||||||
|
|
||||||
|
// Linkifying URLs
|
||||||
|
if (extendedOptions.urls) {
|
||||||
|
matches = elContent.match(urlRegEx);
|
||||||
|
if (matches) {
|
||||||
|
elContent = _linkifyUrls(matches, $el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linkifying mentions
|
||||||
|
if (extendedOptions.mentions) {
|
||||||
|
elContent = _linkifyMentions(elContent, links[extendedOptions.linkTo].baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linkifying hashtags
|
||||||
|
if (extendedOptions.hashtags) {
|
||||||
|
elContent = _linkifyHashtags(elContent, links[extendedOptions.linkTo]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For any URLs present, unless they are already identified within
|
||||||
|
// an `a` element, linkify them.
|
||||||
|
function _linkifyUrls(matches, $el) {
|
||||||
|
var elContent = $el.html();
|
||||||
|
|
||||||
|
$.each(matches, function () {
|
||||||
|
|
||||||
|
//var arr = [ "jpeg", "jpg", "gif", "png" ];
|
||||||
|
var protocol = this.split('://')[0];
|
||||||
|
var ext = this.split('.').pop();
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case ext == "png":
|
||||||
|
case ext == "jpg":
|
||||||
|
case ext == "gif":
|
||||||
|
case ext == "jpeg":
|
||||||
|
case ext == "PNG":
|
||||||
|
case ext == "JPG":
|
||||||
|
case ext == "GIF":
|
||||||
|
case ext == "JPEG":
|
||||||
|
elContent = elContent.replace(this, "<br/><img src='" + this + "'class=\"responsive z-depth-2\"><br/><a href=\"javascript:gotoClipboard('" + this + "');\" target='_blank'>" + this + "</a>");
|
||||||
|
break;
|
||||||
|
case ext == "iframe":
|
||||||
|
elContent = elContent.replace(this, "<br/><iframe class=\"z-depth-2\" src='" + this + "'width=\"440\" height=\"248\" frameborder=\"0\"></iframe>");
|
||||||
|
break;
|
||||||
|
case ext == "webm":
|
||||||
|
elContent = elContent.replace(this, "<br/><video controls class=\"z-depth-2 responsive\"><source src='" + this + "' type='video/" + ext + "'></video><br/><a href=\"javascript:gotoClipboard('" + this + "');\">" + this + "</a>");
|
||||||
|
break;
|
||||||
|
case protocol === "HIFI":
|
||||||
|
case protocol === "hifi":
|
||||||
|
elContent = elContent.replace(this, "<br/><a href=\"javascript:gotoHiFi('" + this + "');\">" + this + "</a>");
|
||||||
|
break;
|
||||||
|
case !!this.match(/^(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?(?=.*v=((\w|-){11}))(?:\S+)?$/):
|
||||||
|
var youtubeMatch = this.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/);
|
||||||
|
if (youtubeMatch && youtubeMatch[2].length == 11 && this.match(/^(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?(?=.*v=((\w|-){11}))(?:\S+)?$/)) {
|
||||||
|
elContent = "<br/><iframe class=\"z-depth-2\" width='420' height='236' src='https://www.youtube.com/embed/" + youtubeMatch[2] + "' frameborder='0'></iframe><br/><a href=\"javascript:gotoURL('" + this + "');\">" + this + "</a>";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// else fall through to default
|
||||||
|
default:
|
||||||
|
elContent = elContent.replace(this, "<br/><a href=\"javascript:gotoURL('" + this + "');\">" + this + "</a>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
return elContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find any mentions (e.g. @andrs) and turn them into links that
|
||||||
|
// refer to the appropriate social profile (e.g. twitter or instagram).
|
||||||
|
function _linkifyMentions(text, baseUrl) {
|
||||||
|
return text.replace(/(^|\s|\(|>)@(\w+)/g, "$1<a href='" + baseUrl + "$2' target='_blank'>@$2</a>");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find any hashtags (e.g. #linkyrocks) and turn them into links that refer
|
||||||
|
// to the appropriate social profile.
|
||||||
|
function _linkifyHashtags(text, links) {
|
||||||
|
// If there is no search URL for a hashtag, there isn't much we can do
|
||||||
|
if (links.hashtagSearchUrl === null) return text;
|
||||||
|
return text.replace(/(^|\s|\(|>)#((\w|[\u00A1-\uFFFF])+)/g, "$1<a href='" + links.baseUrl + links.hashtagSearchUrl + "$2' target='_blank'>#$2</a>");
|
||||||
|
}
|
||||||
|
|
||||||
|
}(jQuery));
|
||||||
|
|
||||||
|
//End George Function
|
||||||
|
|
||||||
|
function replaceFormatting(text) {
|
||||||
|
var found = false;
|
||||||
|
if (text.indexOf("**") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("**") + 2;
|
||||||
|
var secondMatch = text.indexOf("**", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 2);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 2);
|
||||||
|
text = part1 + "<i>" + part2 + "</i>" + part3;
|
||||||
|
}
|
||||||
|
} else if (text.indexOf("*") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("*") + 1;
|
||||||
|
var secondMatch = text.indexOf("*", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 1);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 1);
|
||||||
|
text = part1 + "<b>" + part2 + "</b>" + part3;
|
||||||
|
}
|
||||||
|
} else if (text.indexOf("__") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("__") + 2;
|
||||||
|
var secondMatch = text.indexOf("__", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 2);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 2);
|
||||||
|
text = part1 + "<ins>" + part2 + "</ins>" + part3;
|
||||||
|
}
|
||||||
|
} else if (text.indexOf("_") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("_") + 1;
|
||||||
|
var secondMatch = text.indexOf("_", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 1);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 1);
|
||||||
|
text = part1 + "<i>" + part2 + "</i>" + part3;
|
||||||
|
}
|
||||||
|
} else if (text.indexOf("~~") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("~~") + 2;
|
||||||
|
var secondMatch = text.indexOf("~~", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 2);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 2);
|
||||||
|
text = part1 + "<del>" + part2 + "</del>" + part3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
return replaceFormatting(text);
|
||||||
|
} else {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoHiFi(url) {
|
||||||
|
emitWebEvent({type: "CMD", cmd: "GOTO", url: url});
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoURL(url) {
|
||||||
|
emitWebEvent({type: "CMD", cmd: "URL", url: url});
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoClipboard(url) {
|
||||||
|
M.toast({html: 'Copied URL to Clipboard', classes: 'rounded pink white-text'});
|
||||||
|
emitWebEvent({type: "CMD", cmd: "COPY", url: url});
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitWebEvent(obj) {
|
||||||
|
if (window.qt) {
|
||||||
|
obj.appUUID = appUUID; // Appends the appUUID for checking that its from the correct html/qml.
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify(obj)); // So you can just send a JSON object without having to stringify.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rgbToHex(colour) {
|
||||||
|
var red = Number(colour.red).toString(16);
|
||||||
|
if (red.length < 2) {
|
||||||
|
red = "0" + red;
|
||||||
|
}
|
||||||
|
var green = Number(colour.green).toString(16);
|
||||||
|
if (green.length < 2) {
|
||||||
|
green = "0" + green;
|
||||||
|
}
|
||||||
|
var blue = Number(colour.blue).toString(16);
|
||||||
|
if (blue.length < 2) {
|
||||||
|
blue = "0" + blue;
|
||||||
|
}
|
||||||
|
return "#" + red + green + blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrTab() {
|
||||||
|
return instance.$activeTabLink.html();
|
||||||
|
}
|
||||||
|
|
||||||
|
function redock() {
|
||||||
|
emitWebEvent({type: "CMD", cmd: "REDOCK"});
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function logMessage(userName, message, logScreen, colour) {
|
||||||
|
var LogScreen = $("#" + logScreen);
|
||||||
|
var $logLine =
|
||||||
|
$('<div/>')
|
||||||
|
.addClass('LogLogLine')
|
||||||
|
.addClass('card-panel')
|
||||||
|
.addClass('blue-grey')
|
||||||
|
.addClass('darken-4')
|
||||||
|
.addClass('z-depth-2')
|
||||||
|
.data('chat-message', message).css("color", rgbToHex(colour))
|
||||||
|
.appendTo(LogScreen);
|
||||||
|
$('<b/>')
|
||||||
|
.addClass('LogLogLineMessage')
|
||||||
|
.text(userName + ": ").css("color", rgbToHex(colour))
|
||||||
|
.appendTo($logLine);
|
||||||
|
$('<span/>')
|
||||||
|
.addClass('LogLogLineMessage')
|
||||||
|
.text(message).css("color", rgbToHex(colour)).linky()
|
||||||
|
.appendTo($logLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollChatLog(chatID) {
|
||||||
|
var $chatID = $("#" + chatID);
|
||||||
|
$chatID.scrollTop($chatID.scrollTop() + 100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function time() {
|
||||||
|
var d = new Date();
|
||||||
|
var h = (d.getHours()).toString();
|
||||||
|
var m = (d.getMinutes()).toString();
|
||||||
|
var s = (d.getSeconds()).toString();
|
||||||
|
var h2 = ("0" + h).slice(-2);
|
||||||
|
var m2 = ("0" + m).slice(-2);
|
||||||
|
var s2 = ("0" + s).slice(-2);
|
||||||
|
s2 += (d.getMilliseconds() / 1000).toFixed(2).slice(1);
|
||||||
|
return h2 + ":" + m2 + ":" + s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var muteInput;
|
||||||
|
var muteText;
|
||||||
|
|
||||||
|
function muteSwitchToggle() {
|
||||||
|
muted[getCurrTab()] = muteInput.checked;
|
||||||
|
muteText.classList.add(muteInput.checked ? "red-text" : "white-text");
|
||||||
|
muteText.classList.remove(!muteInput.checked ? "red-text" : "white-text");
|
||||||
|
emitWebEvent({type: "CMD", cmd: "MUTED", muted: muted});
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
|
||||||
|
muteInput = document.getElementById("muteInput");
|
||||||
|
muteText = document.getElementById("muteText");
|
||||||
|
|
||||||
|
instance = M.Tabs.init(document.getElementById("tabs"), {
|
||||||
|
"onShow": function (e) {
|
||||||
|
scrollChatLog(getCurrTab());
|
||||||
|
muteInput.checked = muted[getCurrTab()];
|
||||||
|
muteText.classList.add(muteInput.checked ? "red-text" : "white-text");
|
||||||
|
muteText.classList.remove(!muteInput.checked ? "red-text" : "white-text");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
instance.select("Local");
|
||||||
|
|
||||||
|
$('.modal').modal();
|
||||||
|
|
||||||
|
var parsedUrl = new URL(window.location.href);
|
||||||
|
appUUID = parsedUrl.searchParams.get("appUUID");
|
||||||
|
|
||||||
|
$ChatLog = $('#Local');
|
||||||
|
$ChatInputText = $('#ChatInputText');
|
||||||
|
|
||||||
|
$ChatInputText.on('focus', function (event) {
|
||||||
|
scrollChatLog(getCurrTab());
|
||||||
|
});
|
||||||
|
|
||||||
|
$ChatInputText.on('keydown', function (event) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
var message = $ChatInputText.val().substr(0, 256);
|
||||||
|
$ChatInputText.val('');
|
||||||
|
if (message !== '') {
|
||||||
|
var tab = getCurrTab();
|
||||||
|
if (tab === "Grid") {
|
||||||
|
emitWebEvent({type: "WEBMSG", message: message, tab: tab, time: time()});
|
||||||
|
} else {
|
||||||
|
emitWebEvent({type: "MSG", message: message, tab: tab, time: time()});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("getCurrTab: ", getCurrTab());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$ChatInputText.focus();
|
||||||
|
|
||||||
|
if (window.qt) {
|
||||||
|
setTimeout(function () {
|
||||||
|
console.log("connecting to eventbridge");
|
||||||
|
EventBridge.scriptEventReceived.connect(function (message) {
|
||||||
|
var cmd = [];
|
||||||
|
try {
|
||||||
|
cmd = JSON.parse(message);
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if (cmd.type === "MSG") {
|
||||||
|
var temp = cmd.data;
|
||||||
|
if (temp.length === 1) {
|
||||||
|
var temp2 = temp[0];
|
||||||
|
logMessage("[" + temp2[0] + "] " + temp2[2], temp2[1], temp2[4], temp2[3]);
|
||||||
|
scrollChatLog(temp2[4]);
|
||||||
|
} else if (temp.length > 1) {
|
||||||
|
temp.forEach(function (msg) {
|
||||||
|
logMessage("[" + msg[0] + "] " + msg[2], msg[1], msg[4], msg[3]);
|
||||||
|
scrollChatLog(msg[4]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (cmd.type === "CMD") {
|
||||||
|
if (cmd.cmd === "MUTED") {
|
||||||
|
muted = cmd.muted;
|
||||||
|
muteInput.checked = muted[getCurrTab()];
|
||||||
|
muteText.classList.add(muteInput.checked ? "red-text" : "white-text");
|
||||||
|
muteText.classList.remove(!muteInput.checked ? "red-text" : "white-text");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 100); // Delay to allow everything to settle
|
||||||
|
}
|
||||||
|
|
||||||
|
$ChatInputText.focus();
|
||||||
|
|
||||||
|
if (window.qt) {
|
||||||
|
setTimeout(function () {
|
||||||
|
emitWebEvent({
|
||||||
|
"type": "ready"
|
||||||
|
});
|
||||||
|
}, 250); // Delay to allow everything to settle
|
||||||
|
console.log("sending ready signal!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(main);
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="js/materialize.min.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
465
scripts/communityModules/chat/FloofChat.js
Normal file
465
scripts/communityModules/chat/FloofChat.js
Normal file
|
@ -0,0 +1,465 @@
|
||||||
|
/* globals OverlayWindow */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var ROOT = Script.resolvePath('').split("FloofChat.js")[0];
|
||||||
|
var H_KEY = 72;
|
||||||
|
var ENTER_KEY = 16777220;
|
||||||
|
var ESC_KEY = 16777216;
|
||||||
|
var CONTROL_KEY = 67108864;
|
||||||
|
var SHIFT_KEY = 33554432;
|
||||||
|
var FLOOF_CHAT_CHANNEL = "Chat";
|
||||||
|
var FLOOF_NOTIFICATION_CHANNEL = "Floof-Notif";
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
shutdown();
|
||||||
|
});
|
||||||
|
|
||||||
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
var button = tablet.addButton({
|
||||||
|
icon: ROOT + "chat.png",
|
||||||
|
text: "CHAT"
|
||||||
|
});
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () { // So if anything errors out the tablet/toolbar button gets removed!
|
||||||
|
tablet.removeButton(button);
|
||||||
|
});
|
||||||
|
|
||||||
|
var appUUID = Uuid.generate();
|
||||||
|
|
||||||
|
var chatBar;
|
||||||
|
var chatHistory;
|
||||||
|
var historyLog = [];
|
||||||
|
|
||||||
|
|
||||||
|
var visible = false;
|
||||||
|
var historyVisible = false;
|
||||||
|
var settingsRoot = "FloofChat";
|
||||||
|
|
||||||
|
var muted = Settings.getValue(settingsRoot + "/muted", {"Local": false, "Domain": false, "Grid": false});
|
||||||
|
|
||||||
|
var ws;
|
||||||
|
var wsReady = false;
|
||||||
|
var WEB_SOCKET_URL = "ws://gridchat.darlingvr.club:8090"; // WebSocket for Grid chat.
|
||||||
|
var shutdownBool = false;
|
||||||
|
|
||||||
|
var defaultColour = {red: 255, green: 255, blue: 255};
|
||||||
|
var colours = {};
|
||||||
|
colours["localChatColour"] = Settings.getValue(settingsRoot + "/localChatColour", defaultColour);
|
||||||
|
colours["domainChatColour"] = Settings.getValue(settingsRoot + "/domainChatColour", defaultColour);
|
||||||
|
colours["gridChatColour"] = Settings.getValue(settingsRoot + "/gridChatColour", defaultColour);
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
Messages.subscribe(FLOOF_CHAT_CHANNEL);
|
||||||
|
historyLog = [];
|
||||||
|
try {
|
||||||
|
historyLog = JSON.parse(Settings.getValue(settingsRoot + "/HistoryLog", "[]"));
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
setupHistoryWindow(false);
|
||||||
|
|
||||||
|
chatBar = new OverlayWindow({
|
||||||
|
source: Paths.defaultScripts + '/communityModules/chat/FloofChat.qml?' + Date.now(),
|
||||||
|
width: 360,
|
||||||
|
height: 180
|
||||||
|
});
|
||||||
|
|
||||||
|
button.clicked.connect(toggleChatHistory);
|
||||||
|
chatBar.fromQml.connect(fromQml);
|
||||||
|
chatBar.sendToQml(JSON.stringify({visible: false}));
|
||||||
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
Messages.messageReceived.connect(messageReceived);
|
||||||
|
|
||||||
|
connectWebSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectWebSocket(timeout) {
|
||||||
|
ws = new WebSocket(WEB_SOCKET_URL);
|
||||||
|
ws.onmessage = function incoming(_data) {
|
||||||
|
var message = _data.data;
|
||||||
|
var cmd = {FAILED: true};
|
||||||
|
try {
|
||||||
|
cmd = JSON.parse(message);
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if (!cmd.FAILED) {
|
||||||
|
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||||
|
if (!muted["Grid"]) {
|
||||||
|
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||||
|
sender: "(G) " + cmd.displayName,
|
||||||
|
text: replaceFormatting(cmd.message),
|
||||||
|
colour: {text: cmd.colour}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onopen = function open() {
|
||||||
|
wsReady = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = function close() {
|
||||||
|
wsReady = false;
|
||||||
|
console.log('disconnected');
|
||||||
|
|
||||||
|
timeout = timeout | 0;
|
||||||
|
if (!shutdownBool && timeout < (30 * 1000)) {
|
||||||
|
Script.setTimeout(function () {
|
||||||
|
connectWebSocket(timeout);
|
||||||
|
}, timeout + 1000);
|
||||||
|
} else {
|
||||||
|
wsReady = -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function sendWS(msg, timeout) {
|
||||||
|
if (wsReady === true) {
|
||||||
|
ws.send(JSON.stringify(msg));
|
||||||
|
} else {
|
||||||
|
timeout = timeout | 0;
|
||||||
|
if (!shutdownBool && timeout < (30 * 1000)) {
|
||||||
|
Script.setTimeout(function () {
|
||||||
|
if (wsReady === -1) {
|
||||||
|
connectWebSocket();
|
||||||
|
}
|
||||||
|
sendWS(msg, timeout);
|
||||||
|
}, timeout + 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupHistoryWindow() {
|
||||||
|
chatHistory = new OverlayWebWindow({
|
||||||
|
title: 'Chat',
|
||||||
|
source: ROOT + "FloofChat.html?appUUID=" + appUUID + "&" + Date.now(),
|
||||||
|
width: 900,
|
||||||
|
height: 700,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
chatHistory.setPosition({x: 0, y: Window.innerHeight - 700});
|
||||||
|
chatHistory.webEventReceived.connect(onWebEventReceived);
|
||||||
|
chatHistory.closed.connect(toggleChatHistory);
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitScriptEvent(obj) {
|
||||||
|
obj.appUUID = appUUID;
|
||||||
|
tablet.emitScriptEvent(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleChatHistory() {
|
||||||
|
historyVisible = !historyVisible;
|
||||||
|
button.editProperties({isActive: historyVisible});
|
||||||
|
chatHistory.visible = historyVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
function chatColour(tab) {
|
||||||
|
if (tab === "Local") {
|
||||||
|
return colours["localChatColour"];
|
||||||
|
} else if (tab === "Domain") {
|
||||||
|
return colours["domainChatColour"];
|
||||||
|
} else if (tab === "Grid") {
|
||||||
|
return colours["gridChatColour"];
|
||||||
|
} else {
|
||||||
|
return defaultColour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWebEventReceived(event) {
|
||||||
|
event = JSON.parse(event);
|
||||||
|
if (event.type === "ready") {
|
||||||
|
chatHistory.emitScriptEvent(JSON.stringify({type: "MSG", data: historyLog}));
|
||||||
|
chatHistory.emitScriptEvent(JSON.stringify({type: "CMD", cmd: "MUTED", muted: muted}));
|
||||||
|
}
|
||||||
|
if (event.type === "CMD") {
|
||||||
|
if (event.cmd === "MUTED") {
|
||||||
|
muted = event.muted;
|
||||||
|
Settings.setValue(settingsRoot + "/muted", muted);
|
||||||
|
}
|
||||||
|
if (event.cmd === "COLOUR") {
|
||||||
|
Settings.setValue(settingsRoot + "/" + event.colourType + "Colour", event.colour);
|
||||||
|
colours[event.colourType] = event.colour;
|
||||||
|
}
|
||||||
|
if (event.cmd === "REDOCK") {
|
||||||
|
chatHistory.setPosition({x: 0, y: Window.innerHeight - 700});
|
||||||
|
}
|
||||||
|
if (event.cmd === "GOTO") {
|
||||||
|
var result = Window.confirm("Do you want to goto " + event.url.split("/")[2] + " ?");
|
||||||
|
if (result) {
|
||||||
|
location = event.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (event.cmd === "URL") {
|
||||||
|
new OverlayWebWindow({
|
||||||
|
title: 'Web',
|
||||||
|
source: event.url,
|
||||||
|
width: 900,
|
||||||
|
height: 700,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (event.cmd === "COPY") {
|
||||||
|
Window.copyToClipboard(event.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (event.type === "WEBMSG") {
|
||||||
|
if (event.message === "") return;
|
||||||
|
sendWS({
|
||||||
|
uuid: "",
|
||||||
|
type: "WebChat",
|
||||||
|
channel: event.tab,
|
||||||
|
colour: chatColour(event.tab),
|
||||||
|
message: event.message,
|
||||||
|
displayName: MyAvatar.displayName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (event.type === "MSG") {
|
||||||
|
if (event.message === "") return;
|
||||||
|
Messages.sendMessage("Chat", JSON.stringify({
|
||||||
|
type: "TransmitChatMessage",
|
||||||
|
position: MyAvatar.position,
|
||||||
|
channel: event.tab,
|
||||||
|
colour: chatColour(event.tab),
|
||||||
|
message: event.message,
|
||||||
|
displayName: MyAvatar.displayName
|
||||||
|
}));
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceFormatting(text) {
|
||||||
|
var found = false;
|
||||||
|
if (text.indexOf("**") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("**") + 2;
|
||||||
|
var secondMatch = text.indexOf("**", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 2);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 2);
|
||||||
|
text = part1 + "<i>" + part2 + "</i>" + part3;
|
||||||
|
}
|
||||||
|
} else if (text.indexOf("*") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("*") + 1;
|
||||||
|
var secondMatch = text.indexOf("*", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 1);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 1);
|
||||||
|
text = part1 + "<b>" + part2 + "</b>" + part3;
|
||||||
|
}
|
||||||
|
} else if (text.indexOf("__") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("__") + 2;
|
||||||
|
var secondMatch = text.indexOf("__", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 2);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 2);
|
||||||
|
text = part1 + "<u>" + part2 + "</u>" + part3;
|
||||||
|
}
|
||||||
|
} else if (text.indexOf("_") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("_") + 1;
|
||||||
|
var secondMatch = text.indexOf("_", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 1);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 1);
|
||||||
|
text = part1 + "<i>" + part2 + "</i>" + part3;
|
||||||
|
}
|
||||||
|
} else if (text.indexOf("~~") !== -1) {
|
||||||
|
var firstMatch = text.indexOf("~~") + 2;
|
||||||
|
var secondMatch = text.indexOf("~~", firstMatch);
|
||||||
|
if (firstMatch !== -1 && secondMatch !== -1) {
|
||||||
|
found = true;
|
||||||
|
var part1 = text.substring(0, firstMatch - 2);
|
||||||
|
var part2 = text.substring(firstMatch, secondMatch);
|
||||||
|
var part3 = text.substring(secondMatch + 2);
|
||||||
|
text = part1 + "<s>" + part2 + "</s>" + part3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
return replaceFormatting(text);
|
||||||
|
} else {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageReceived(channel, message) {
|
||||||
|
if (channel === "Chat") {
|
||||||
|
var cmd = {FAILED: true};
|
||||||
|
try {
|
||||||
|
cmd = JSON.parse(message);
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if (!cmd.FAILED) {
|
||||||
|
if (cmd.type === "TransmitChatMessage") {
|
||||||
|
if (!cmd.hasOwnProperty("channel")) {
|
||||||
|
cmd.channel = "Domain";
|
||||||
|
}
|
||||||
|
if (!cmd.hasOwnProperty("colour")) {
|
||||||
|
cmd.colour = {red: 222, green: 222, blue: 222};
|
||||||
|
}
|
||||||
|
if (cmd.message.indexOf("/me") === 0) {
|
||||||
|
cmd.message = cmd.message.replace("/me", cmd.displayName);
|
||||||
|
cmd.displayName = "";
|
||||||
|
}
|
||||||
|
if (cmd.channel === "Local") {
|
||||||
|
if (Vec3.withinEpsilon(MyAvatar.position, cmd.position, 20)) {
|
||||||
|
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||||
|
if (!muted["Local"]) {
|
||||||
|
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||||
|
sender: "(L) " + cmd.displayName,
|
||||||
|
text: replaceFormatting(cmd.message),
|
||||||
|
colour: {text: cmd.colour}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (cmd.channel === "Domain") {
|
||||||
|
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||||
|
if (!muted["Domain"]) {
|
||||||
|
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||||
|
sender: "(D) " + cmd.displayName,
|
||||||
|
text: replaceFormatting(cmd.message),
|
||||||
|
colour: {text: cmd.colour}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else if (cmd.channel === "Grid") {
|
||||||
|
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||||
|
if (!muted["Grid"]) {
|
||||||
|
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||||
|
sender: "(G) " + cmd.displayName,
|
||||||
|
text: replaceFormatting(cmd.message),
|
||||||
|
colour: {text: cmd.colour}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addToLog(cmd.message, cmd.displayName, cmd.colour, cmd.channel);
|
||||||
|
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||||
|
sender: cmd.displayName,
|
||||||
|
text: replaceFormatting(cmd.message),
|
||||||
|
colour: {text: cmd.colour}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function time() {
|
||||||
|
var d = new Date();
|
||||||
|
var h = (d.getHours()).toString();
|
||||||
|
var m = (d.getMinutes()).toString();
|
||||||
|
var s = (d.getSeconds()).toString();
|
||||||
|
var h2 = ("0" + h).slice(-2);
|
||||||
|
var m2 = ("0" + m).slice(-2);
|
||||||
|
var s2 = ("0" + s).slice(-2);
|
||||||
|
s2 += (d.getMilliseconds() / 1000).toFixed(2).slice(1);
|
||||||
|
return h2 + ":" + m2 + ":" + s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToLog(msg, dp, colour, tab) {
|
||||||
|
historyLog.push([time(), msg, dp, colour, tab]);
|
||||||
|
chatHistory.emitScriptEvent(JSON.stringify({type: "MSG", data: [[time(), msg, dp, colour, tab]]}));
|
||||||
|
while (historyLog.length > 500) {
|
||||||
|
historyLog.shift();
|
||||||
|
}
|
||||||
|
Settings.setValue(settingsRoot + "/HistoryLog", JSON.stringify(historyLog))
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromQml(message) {
|
||||||
|
var cmd = {FAILED: true};
|
||||||
|
try {
|
||||||
|
cmd = JSON.parse(message);
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if (!cmd.FAILED) {
|
||||||
|
if (cmd.type === "MSG") {
|
||||||
|
if (cmd.message !== "") {
|
||||||
|
if (cmd.event.modifiers === CONTROL_KEY) {
|
||||||
|
Messages.sendMessage(FLOOF_CHAT_CHANNEL, JSON.stringify({
|
||||||
|
type: "TransmitChatMessage", channel: "Domain", colour: chatColour("Domain"),
|
||||||
|
message: cmd.message,
|
||||||
|
displayName: MyAvatar.displayName
|
||||||
|
}));
|
||||||
|
} else if (cmd.event.modifiers === CONTROL_KEY + SHIFT_KEY) {
|
||||||
|
sendWS({
|
||||||
|
uuid: "",
|
||||||
|
type: "WebChat",
|
||||||
|
channel: "Grid",
|
||||||
|
colour: chatColour("Grid"),
|
||||||
|
message: cmd.message,
|
||||||
|
displayName: MyAvatar.displayName
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Messages.sendMessage(FLOOF_CHAT_CHANNEL, JSON.stringify({
|
||||||
|
type: "TransmitChatMessage",
|
||||||
|
channel: "Local",
|
||||||
|
position: MyAvatar.position,
|
||||||
|
colour: chatColour("Local"),
|
||||||
|
message: cmd.message,
|
||||||
|
displayName: MyAvatar.displayName
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setVisible(false);
|
||||||
|
} else if (cmd.type === "CMD") {
|
||||||
|
if (cmd.cmd === "Clicked") {
|
||||||
|
toggleChatHistory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setVisible(_visible) {
|
||||||
|
if (_visible) {
|
||||||
|
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||||
|
type: "options",
|
||||||
|
offset: 64
|
||||||
|
}));
|
||||||
|
chatBar.sendToQml(JSON.stringify({visible: true}));
|
||||||
|
} else {
|
||||||
|
Messages.sendLocalMessage(FLOOF_NOTIFICATION_CHANNEL, JSON.stringify({
|
||||||
|
type: "options",
|
||||||
|
offset: -1
|
||||||
|
}));
|
||||||
|
chatBar.sendToQml(JSON.stringify({visible: false}));
|
||||||
|
}
|
||||||
|
visible = _visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyPressEvent(event) {
|
||||||
|
if (event.key === H_KEY && !event.isAutoRepeat && event.isControl) {
|
||||||
|
toggleChatHistory()
|
||||||
|
}
|
||||||
|
if (event.key === ENTER_KEY && !event.isAutoRepeat && !visible) {
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
if (event.key === ESC_KEY && !event.isAutoRepeat && visible) {
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shutdown() {
|
||||||
|
try {
|
||||||
|
Messages.messageReceived.disconnect(messageReceived);
|
||||||
|
} catch (e) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Controller.keyPressEvent.disconnect(keyPressEvent);
|
||||||
|
} catch (e) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
chatBar.close();
|
||||||
|
chatHistory.close();
|
||||||
|
}
|
129
scripts/communityModules/chat/FloofChat.qml
Normal file
129
scripts/communityModules/chat/FloofChat.qml
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
//import Hifi 1.0 as Hifi
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
property var window
|
||||||
|
|
||||||
|
Binding { target: root; property:'window'; value: parent.parent; when: Boolean(parent.parent) }
|
||||||
|
|
||||||
|
Binding { target: window; property: 'shown'; value: false; when: Boolean(window) }
|
||||||
|
Component.onDestruction: thing && thing.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
signal sendToScript(var message);
|
||||||
|
color: "#00000000"
|
||||||
|
property alias thing: thing
|
||||||
|
|
||||||
|
function sendMessage(text){
|
||||||
|
sendToScript(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromScript(message) {
|
||||||
|
console.log("fromScript "+message);
|
||||||
|
var data = {failed:true};
|
||||||
|
try{
|
||||||
|
data = JSON.parse(message);
|
||||||
|
} catch(e){
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if(!data.failed){
|
||||||
|
if(data.cmd){
|
||||||
|
JSConsole.executeCommand(data.msg);
|
||||||
|
}
|
||||||
|
console.log(data.visible);
|
||||||
|
if(data.visible){
|
||||||
|
thing.visible = true;
|
||||||
|
textArea.focus = true;
|
||||||
|
} else if(!data.visible){
|
||||||
|
thing.visible = false;
|
||||||
|
textArea.focus = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: thing
|
||||||
|
parent: desktop
|
||||||
|
x: 0
|
||||||
|
y: parent.height - height
|
||||||
|
width: parent.width
|
||||||
|
height: 64
|
||||||
|
color: "#00000000"
|
||||||
|
z: 99
|
||||||
|
visible:true
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: textArea
|
||||||
|
x: 64
|
||||||
|
width: parent.width-64
|
||||||
|
height: parent.height
|
||||||
|
text:""
|
||||||
|
textColor: "#000000"
|
||||||
|
clip: false
|
||||||
|
font.pointSize: 20
|
||||||
|
|
||||||
|
function _onEnterPressed(event)
|
||||||
|
{
|
||||||
|
sendMessage(JSON.stringify({type:"MSG",message:text,event:event}));
|
||||||
|
text = "";
|
||||||
|
}
|
||||||
|
Keys.onReturnPressed: { _onEnterPressed(event) }
|
||||||
|
Keys.onEnterPressed: { _onEnterPressed(event) }
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.rightMargin: -1
|
||||||
|
anchors.bottomMargin: 0
|
||||||
|
anchors.topMargin: 0
|
||||||
|
anchors.leftMargin: 63
|
||||||
|
anchors.fill: parent
|
||||||
|
propagateComposedEvents: false
|
||||||
|
acceptedButtons: Qt.AllButtons
|
||||||
|
enabled: false
|
||||||
|
onPressed: {
|
||||||
|
thing.forceActiveFocus();
|
||||||
|
mouse.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: button
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 64
|
||||||
|
height: 64
|
||||||
|
text: qsTr("Button")
|
||||||
|
clip: false
|
||||||
|
opacity: 1
|
||||||
|
iconSource: ""
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 64
|
||||||
|
height: 64
|
||||||
|
visible: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
source: "chat.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: button
|
||||||
|
onClicked:
|
||||||
|
sendMessage(JSON.stringify({type:"CMD",cmd:"Clicked"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*##^## Designer {
|
||||||
|
D{i:0;autoSize:true;height:480;width:640}
|
||||||
|
}
|
||||||
|
##^##*/
|
BIN
scripts/communityModules/chat/chat.png
Normal file
BIN
scripts/communityModules/chat/chat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
157
scripts/communityModules/chat/css/FloofChat.css
Normal file
157
scripts/communityModules/chat/css/FloofChat.css
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
|
||||||
|
.disabledrag {
|
||||||
|
-webkit-user-drag: none !important;
|
||||||
|
-khtml-user-drag: none !important;
|
||||||
|
-moz-user-drag: none !important;
|
||||||
|
-o-user-drag: none !important;
|
||||||
|
user-drag: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dockButton {
|
||||||
|
|
||||||
|
position: absolute; /*or fixed*/
|
||||||
|
right: 10px;
|
||||||
|
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dockButton button {
|
||||||
|
background-color: inherit;
|
||||||
|
float: right;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 14px 16px;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change background color of buttons on hover */
|
||||||
|
div.dockButton button:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create an active/current tablink class */
|
||||||
|
div.dockButton button.active {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the tab content */
|
||||||
|
.TabContent {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: hidden;
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Raleway', sans-serif;
|
||||||
|
color: white;
|
||||||
|
background: linear-gradient(#2b2b2b, #0f212e);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Content {
|
||||||
|
min-height: 100vh;
|
||||||
|
font-size: 20px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ChatLog {
|
||||||
|
height: calc(100vh - 137px);
|
||||||
|
padding: 20px !important;
|
||||||
|
font-size: 20px;
|
||||||
|
color: white;
|
||||||
|
background-color: black;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: scroll;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ChatLogLine {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ChatLogLineDisplayName {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ChatLogLineMessage {
|
||||||
|
}
|
||||||
|
|
||||||
|
.LogLogLine {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LogLogLineMessage {
|
||||||
|
/*font-style: italic;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.ChatInput {
|
||||||
|
color: #252525;
|
||||||
|
background: #252525;
|
||||||
|
height: 60px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ChatInputText {
|
||||||
|
padding: 5px !important;
|
||||||
|
height: 50px !important;
|
||||||
|
width: calc(100vw - 20px) !important;
|
||||||
|
font-size: 20px !important;
|
||||||
|
background-color: white !important;
|
||||||
|
border-style: solid !important;
|
||||||
|
border-color: #232323 !important;
|
||||||
|
border-width: 5px 5px 5px 5px !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.responsive {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 420px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row .col {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch label .lever {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 36px;
|
||||||
|
height: 14px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.38);
|
||||||
|
border-radius: 15px;
|
||||||
|
margin-right: 10px;
|
||||||
|
-webkit-transition: background 0.3s ease;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.muteSwitch label input[type=checkbox]:checked + .lever:after {
|
||||||
|
background-color: #a62113 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
img, a{
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
user-drag: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
}
|
9086
scripts/communityModules/chat/css/materialize.css
vendored
Normal file
9086
scripts/communityModules/chat/css/materialize.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
6
scripts/communityModules/chat/js/materialize.min.js
vendored
Normal file
6
scripts/communityModules/chat/js/materialize.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
164
scripts/communityModules/notificationCore/notificationCore.js
Normal file
164
scripts/communityModules/notificationCore/notificationCore.js
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
"use strict";
|
||||||
|
var notificationList = [];
|
||||||
|
|
||||||
|
var sizeData = {30: {widthMul: 1.8, heightMul: 2.05, split: 35, size: 30}};
|
||||||
|
|
||||||
|
var DEFAULT_SIZE = 30;
|
||||||
|
var DEFAULT_OFFSET = 10;
|
||||||
|
var FLOOF_NOTIFICATION_CHANNEL = "Floof-Notif";
|
||||||
|
|
||||||
|
var offset = DEFAULT_OFFSET;
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
function init(){
|
||||||
|
Messages.messageReceived.connect(messageReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageReceived(channel, message, sender, local) {
|
||||||
|
if (local) {
|
||||||
|
if (channel === FLOOF_NOTIFICATION_CHANNEL) {
|
||||||
|
var cmd = {FAILED: true};
|
||||||
|
try {
|
||||||
|
cmd = JSON.parse(message);
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
if (!cmd.FAILED) {
|
||||||
|
if (cmd.type === "options") {
|
||||||
|
if (cmd.offset) {
|
||||||
|
notificationCore.setOffset(cmd.offset);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notificationCore.add(cmd.text, cmd.sender, cmd.colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var notificationCore = {
|
||||||
|
setOffset: function (offsetHeight) {
|
||||||
|
if (offsetHeight === -1) {
|
||||||
|
offset = DEFAULT_OFFSET;
|
||||||
|
} else {
|
||||||
|
offset = offsetHeight;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
add: function (text, sender, colour) {
|
||||||
|
sender = sender ? sender : "NoName";
|
||||||
|
colour = colour ? colour : {};
|
||||||
|
colour.text = colour.text ? colour.text : {red: 255, green: 255, blue: 255};
|
||||||
|
colour.bg = colour.bg ? colour.bg : {red: 10, green: 10, blue: 10};
|
||||||
|
var lines = text.split("\n");
|
||||||
|
for (var i = lines.length - 1; i >= 0; i--) {
|
||||||
|
if (i === 0) {
|
||||||
|
notif("[" + time() + "] " + sender + ": " + lines[i], colour);
|
||||||
|
} else {
|
||||||
|
notif(lines[i], colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function time() {
|
||||||
|
var d = new Date();
|
||||||
|
var h = (d.getHours()).toString();
|
||||||
|
var m = (d.getMinutes()).toString();
|
||||||
|
var s = (d.getSeconds()).toString();
|
||||||
|
var h2 = ("0" + h).slice(-2);
|
||||||
|
var m2 = ("0" + m).slice(-2);
|
||||||
|
var s2 = ("0" + s).slice(-2);
|
||||||
|
s2 += (d.getMilliseconds() / 1000).toFixed(2).slice(1);
|
||||||
|
return h2 + ":" + m2 + ":" + s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findIndex(id) {
|
||||||
|
var index = -1;
|
||||||
|
notificationList.forEach(function (noti, i) {
|
||||||
|
if (noti.id === id) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanUp() {
|
||||||
|
try {
|
||||||
|
Messages.messageReceived.disconnect(messageReceived);
|
||||||
|
} catch (e) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
notificationList.forEach(function (noti) {
|
||||||
|
Overlays.deleteOverlay(noti.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function notif(text, colour) {
|
||||||
|
|
||||||
|
var noti = {
|
||||||
|
text: " " + text + " ",
|
||||||
|
time: 10 * 1000,
|
||||||
|
timeout: null,
|
||||||
|
timer: null,
|
||||||
|
fade: null,
|
||||||
|
colour: colour,
|
||||||
|
alpha: {text: 1, bg: 0.9}
|
||||||
|
};
|
||||||
|
noti.id = Overlays.addOverlay("text", {
|
||||||
|
text: '',
|
||||||
|
font: {size: sizeData[DEFAULT_SIZE].size},
|
||||||
|
x: 0,
|
||||||
|
y: Window.innerHeight,
|
||||||
|
color: colour.text,
|
||||||
|
backgroundColor: colour.bg,
|
||||||
|
backgroundAlpha: noti.alpha.bg,
|
||||||
|
alpha: noti.alpha.text
|
||||||
|
});
|
||||||
|
|
||||||
|
var ts = Overlays.textSize(noti.id, noti.text);
|
||||||
|
ts.height *= sizeData[DEFAULT_SIZE].heightMul;
|
||||||
|
ts.width *= sizeData[DEFAULT_SIZE].widthMul;
|
||||||
|
ts.y = Window.innerHeight - (sizeData[DEFAULT_SIZE].split * (notificationList.length)) - offset;
|
||||||
|
ts.text = noti.text;
|
||||||
|
Overlays.editOverlay(noti.id, ts);
|
||||||
|
|
||||||
|
noti.update = function () {
|
||||||
|
var i = notificationList.length - findIndex(noti.id);
|
||||||
|
Overlays.editOverlay(noti.id, {
|
||||||
|
y: Window.innerHeight - (sizeData[DEFAULT_SIZE].split * (i)) - offset
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
noti.startFade = function () {
|
||||||
|
noti.fade = Script.setInterval(noti.fadeOut, 50);
|
||||||
|
};
|
||||||
|
|
||||||
|
noti.fadeOut = function () {
|
||||||
|
noti.alpha.text -= 0.1;
|
||||||
|
noti.alpha.bg -= 0.1;
|
||||||
|
Overlays.editOverlay(noti.id, {
|
||||||
|
alpha: noti.alpha.text,
|
||||||
|
backgroundAlpha: noti.alpha.bg
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Math.max(noti.alpha.text, noti.alpha.bg) <= 0) {
|
||||||
|
Script.clearInterval(noti.fade);
|
||||||
|
noti.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
noti.end = function () {
|
||||||
|
Script.clearInterval(noti.timer);
|
||||||
|
Script.clearTimeout(noti.timeout);
|
||||||
|
Overlays.deleteOverlay(noti.id);
|
||||||
|
notificationList.splice(findIndex(noti.id), 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
noti.timer = Script.setInterval(noti.update, 10);
|
||||||
|
noti.timeout = Script.setTimeout(noti.startFade, noti.time);
|
||||||
|
|
||||||
|
notificationList.push(noti);
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(cleanUp);
|
|
@ -37,7 +37,9 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
||||||
"system/keyboardShortcuts/keyboardShortcuts.js"
|
"system/keyboardShortcuts/keyboardShortcuts.js"
|
||||||
];
|
];
|
||||||
var DEFAULT_SCRIPTS_SEPARATE = [
|
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||||
"system/controllers/controllerScripts.js"
|
"system/controllers/controllerScripts.js",
|
||||||
|
"communityModules/notificationCore/notificationCore.js",
|
||||||
|
"communityModules/chat/FloofChat.js"
|
||||||
//"system/chat.js"
|
//"system/chat.js"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue