Browse Source

增加静态文件资源

master
453530270@qq.com 1 year ago
parent
commit
0af2ce3277
  1. 4
      src/main/java/app/bcms/jchat/websocket/WebSocketServer.java
  2. 248
      src/main/resources/public/chat.html
  3. 234
      src/main/resources/public/kefu.html
  4. 52
      src/main/resources/static/chat/css/chat.css
  5. 1
      src/main/resources/static/chat/css/jquery-sina-emotion.min.css
  6. BIN
      src/main/resources/static/chat/img/0.jpg
  7. BIN
      src/main/resources/static/chat/img/btcex.png
  8. 296
      src/main/resources/static/chat/js/jquery-sina-emotion.js
  9. 4
      src/main/resources/static/chat/js/jquery.min.js
  10. 4
      src/main/resources/static/chat/js/swfobject.js
  11. 398
      src/main/resources/static/chat/js/web_socket.js
  12. BIN
      src/main/resources/static/chat/swf/WebSocketMain.swf

4
src/main/java/app/bcms/jchat/websocket/WebSocketServer.java

@ -2,9 +2,13 @@ package app.bcms.jchat.websocket;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*; import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
@Component
@ServerEndpoint("/chat")
public class WebSocketServer { public class WebSocketServer {
private final static Log log = LogFactory.getLog(WebSocketServer.class); private final static Log log = LogFactory.getLog(WebSocketServer.class);
private Session session; private Session session;

248
src/main/resources/public/chat.html

@ -0,0 +1,248 @@
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<title></title>
<script type="text/javascript" src="/chat/js/jquery.min.js"></script>
<link href="/chat/css/jquery-sina-emotion.min.css" rel="stylesheet">
<link href="/chat/css/chat.css?v=0915" rel="stylesheet">
<script type="text/javascript" src="/chat/js/jquery-sina-emotion.js"></script>
<script type="text/javascript" src="/chat/js/swfobject.js"></script>
<script type="text/javascript" src="/chat/js/web_socket.js"></script>
<style>
.offtips {
color: #e8e8e8;
padding: 10px;
}
</style>
<body onload="connect();">
<div class="newWindow ">
<div class="window-header">
<img src="/chat/img/btcex.png" width="40px" height="40px"
style="margin-right:10px;float:left;margin-top:4px;border-radius:2px;" alt="avatar">
<p class="company-name font16">BTCEXCOIN </p>
<p class="autograph font12" title="Provide you with online pre-sales answers">Provide you with online pre-sales answers</p>
</div>
<div class="window-content">
<div class="content-left">
<div class="chat-content">
<div style="display:none">
</div>
</div>
<div class="pc-visitor-footer">
<form>
<div class="function-bar">
<div class="talk-function-bar">
<div class="svgWrap">
<?xml version="1.0" encoding="UTF-8"?>
<label class="changeColor-wrap">
<svg data-title="emote" class="function-icon icon-face face" width="24px"
height="24px" viewBox="0 0 24 24" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"><!-- emjoy -->
<g id="Page-1" stroke="none" stroke-width="1" fill="none"
fill-rule="evenodd">
<g id="Imported-Layers-Copy-7">
<rect id="Rectangle-3" x="0" y="0" width="24" height="24"></rect>
<path class="svgColor"
d="M5,12 C5,15.8656805 8.1343195,19 12,19 C15.8656805,19 19,15.8656805 19,12 C19,8.1343195 15.8656805,5 12,5 C8.1343195,5 5,8.1343195 5,12 Z M3,12 C3,7.02975 7.02975,3 12,3 C16.97025,3 21,7.02975 21,12 C21,16.97025 16.97025,21 12,21 C7.02975,21 3,16.97025 3,12 Z"
id="Combined-Shape" fill="#8FA1B3" fill-rule="nonzero"></path>
<path class="svgColor"
d="M9,8 C8.172,8 7.5,8.672 7.5,9.5 C7.5,10.328 8.172,11 9,11 C9.828,11 10.5,10.328 10.5,9.5 C10.5,8.672 9.828,8 9,8"
id="Fill-2" fill="#8FA1B3"></path>
<path class="svgColor"
d="M15,8 C14.172,8 13.5,8.672 13.5,9.5 C13.5,10.328 14.172,11 15,11 C15.828,11 16.5,10.328 16.5,9.5 C16.5,8.672 15.828,8 15,8"
id="Fill-2-Copy" fill="#8FA1B3"></path>
<path class="svgColor"
d="M9.55730755,18.9802954 C12.5582692,18.9802954 15.0860829,16.7646048 15.4989445,13.8196019 C15.5756198,13.2726656 15.1943979,12.7671285 14.6474616,12.6904532 C14.1005252,12.6137779 13.5949881,12.9949998 13.5183128,13.5419361 C13.2434436,15.5026194 11.5576081,16.9802954 9.55730755,16.9802954 C9.0050228,16.9802954 8.55730755,17.4280106 8.55730755,17.9802954 C8.55730755,18.5325801 9.0050228,18.9802954 9.55730755,18.9802954 Z"
id="Oval-26" fill="#8FA1B3" fill-rule="nonzero"
transform="translate(12.033030, 15.830470) rotate(39.000000) translate(-12.033030, -15.830470) ">
</path>
</g>
</g>
</svg>
</label>
</div>
</div>
</div>
<div class="inputArea">
<textarea class="textarea" id="textarea" name="content"
placeholder="enter your message here"></textarea>
</div>
</form>
<span class="send-btn submit-btn-wrap">Send</span>
</div>
</div>
<div class="content-right">
<div class="content-right-top font14">About BTCEXCOIN</div>
<div class="company-content font12">
<!-- site infomation -->
<p><br/></p>
</div>
</div>
</div>
</div>
<script type="text/javascript">
if (typeof console == "undefined") {
this.console = {
log: function (msg) {
}
};
}
var ws;
function connect() {
//ws = new WebSocket("ws://{$sysconfig['gateway']}");
ws = new WebSocket("wss://cs.btcaholic.com/ct");
ws.onmessage = onmessage;
// ws.onopen = function(){
// if (ws.readyState===1) {
// ws.send();
// }
// }
ws.onclose = function () {
console.log("reconnct timer.");
// setTimeout(function(){
// connect();
// },1000);
connect();
};
ws.onerror = function (e) {
console.log("An error occurred", e);
// setTimeout(function(){
// ws.close();
// },3000);
};
// ws.onclose = function(e){
// console.log(e)
// }
}
function onmessage(e) {
// console.log(e)
console.log("Msg From Server:" + e.data);
var data = JSON.parse(e.data);
switch (data['type']) {
case 'login':
var bild = '{"type":"bild","room_id":"{$room_id}","cuid":"{$cuid}"}';
ws.send(bild);
break;
case 'bild':
var id = data.room_id;
// if (!id) {
// alert('Ops,An error occurred!');
// }
break;
case "say":
$(".chat-content").append('<div class="heisay"><img class="portrait" src="/chat/img/0.jpg"><div class="say_content"><p>Customer Service' + data.time.substr(10, 9) + '</p><span>' + data.content + '</span></div></div>').parseEmotion();
$(".chat-content").scrollTop(3000);
return;
case "save":
if (data['isonline'] == 0) {
$(".chat-content").append('<div class="heisay"><div class="say_content"><p class="offtips">Customer service is temporarily away for a while. If there is anything I can do for you, please leave me a message and I will reply to you as soon as possible.~</div></div>').parseEmotion();
$(".chat-content").scrollTop(3000);
}
// console.log("msgdata")
save_message(data);
return;
}
}
//
$(".send-btn").click(function () {
var text = $(".textarea").val();
//解析新浪微博图片
text.replace(/(http|https):\/\/[\w]+.sinaimg.cn[\S]+(jpg|png|gif)/gi, function (img) {
return "<a target='_blank' href='" + img + "'>" + "<img src='" + img + "'>" + "</a>";
}
);
//解析url
text.replace(/(http|https):\/\/[\S]+/gi, function (url) {
if (url.indexOf(".sinaimg.cn/") < 0)
return "<a target='_blank' href='" + url + "'>" + url + "</a>";
else
return url;
}
);
if (text == '') {
return;
}
var time = getNowFormatDate();
var message = '{"content":"' + text + '","type":"say","room_id":"{$room_id}","toid":"{$chat_user}","cuid":"{$cuid}" }';
$(".chat-content").append('<div class="mysay"><p>Me&nbsp;' + time + '</p><span>' + text + '</span></div>').parseEmotion();
$(".chat-content").scrollTop(3000);
//
// if (ws.readyState===1) {
ws.send(message);
// }
$(".textarea").val("");
})
//
$('.face').click(function (event) {
$(this).sinaEmotion();
event.stopPropagation();
});
document.write('<meta name="viewport" content="width=device-width,initial-scale=1">');
$("textarea").on("keydown", function (e) {
// 按enter键自动提交
if (e.keyCode === 13 && !e.ctrlKey) {
e.preventDefault();
$(".send-btn").click();
return false;
}
// 按ctrl+enter组合键换行
if (e.keyCode === 13 && e.ctrlKey) {
$(this).val(function (i, val) {
return val + "\n";
});
}
});
function getNowFormatDate() {
var date = new Date();
var currentdate = date.toLocaleTimeString();
return currentdate;
}
//
function save_message(data) {
$.post("{:url('Index/save_message')}", data, function (data) {
//do nothing
});
}
$(function () {
$.post("{:url('Index/chat_record')}", "foid={$chat_user}&room_id={$room_id}", function (data) {
for (var i = 0; i < data.length; i++) {
if (data[i].fid !== '{$room_id}') {
$(".chat-content").append('<div class="heisay"><img class="portrait" src="/static/css/chat/img/0.jpg"><div class="say_content"><p>Customer Service' + data[i].time.substr(10, 9) + '</p><span>' + data[i].content + '</span></div></div>').parseEmotion();
} else {
$(".chat-content").append('<div class="mysay"><p>Me&nbsp;' + data[i].time.substr(10, 9) + '</p><span>' + data[i].content + '</span></div>').parseEmotion();
}
}
$(".chat-content").append('<div class="mysay">&nbsp;</div>');
$(".chat-content").scrollTop(3000);
});
})
</script>
<script type="text/javascript">
// document.addEventListener('dblclick', function(e) {
// e.preventDefault();
// }, { passive: false });
</script>
</script>

234
src/main/resources/public/kefu.html

@ -0,0 +1,234 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>聊天室</title>
<script type="text/javascript" src="__CSS__/kefu/js/jquery.min.js"></script>
<link href="__CSS__/kefu/css/jquery-sina-emotion.min.css" rel="stylesheet">
<link href="__CSS__/kefu/css/chat.css" rel="stylesheet">
<script type="text/javascript" src="__CSS__/kefu/js/jquery-sina-emotion.js"></script>
<script type="text/javascript" src="__CSS__/kefu/js/swfobject.js"></script>
<script type="text/javascript" src="__CSS__/kefu/js/web_socket.js"></script>
<body onload="connect();">
<div class="newWindow ">
<div class="window-header">
<img src="/static/css/kefu/img/btcex.png" width="40px" height="40px"
style="margin-right:10px;float:left;margin-top:4px;border-radius:2px;" alt="头像">
<p class="company-name font16">BTCEXCOIN</p>
<p class="autograph font12" title="">BTCEXCOIN</p>
</div>
<div class="window-content">
<div class="content-left">
<div class="chat-content">
</div>
<div class="pc-visitor-footer">
<form>
<div class="function-bar">
<div class="talk-function-bar">
<div class="svgWrap">
<?xml version="1.0" encoding="UTF-8"?>
<label class="changeColor-wrap">
<svg data-title="表情" class="function-icon icon-face face" width="24px"
height="24px" viewBox="0 0 24 24" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"><!-- 表情 -->
<g id="Page-1" stroke="none" stroke-width="1" fill="none"
fill-rule="evenodd">
<g id="Imported-Layers-Copy-7">
<rect id="Rectangle-3" x="0" y="0" width="24" height="24"></rect>
<path class="svgColor"
d="M5,12 C5,15.8656805 8.1343195,19 12,19 C15.8656805,19 19,15.8656805 19,12 C19,8.1343195 15.8656805,5 12,5 C8.1343195,5 5,8.1343195 5,12 Z M3,12 C3,7.02975 7.02975,3 12,3 C16.97025,3 21,7.02975 21,12 C21,16.97025 16.97025,21 12,21 C7.02975,21 3,16.97025 3,12 Z"
id="Combined-Shape" fill="#8FA1B3" fill-rule="nonzero"></path>
<path class="svgColor"
d="M9,8 C8.172,8 7.5,8.672 7.5,9.5 C7.5,10.328 8.172,11 9,11 C9.828,11 10.5,10.328 10.5,9.5 C10.5,8.672 9.828,8 9,8"
id="Fill-2" fill="#8FA1B3"></path>
<path class="svgColor"
d="M15,8 C14.172,8 13.5,8.672 13.5,9.5 C13.5,10.328 14.172,11 15,11 C15.828,11 16.5,10.328 16.5,9.5 C16.5,8.672 15.828,8 15,8"
id="Fill-2-Copy" fill="#8FA1B3"></path>
<path class="svgColor"
d="M9.55730755,18.9802954 C12.5582692,18.9802954 15.0860829,16.7646048 15.4989445,13.8196019 C15.5756198,13.2726656 15.1943979,12.7671285 14.6474616,12.6904532 C14.1005252,12.6137779 13.5949881,12.9949998 13.5183128,13.5419361 C13.2434436,15.5026194 11.5576081,16.9802954 9.55730755,16.9802954 C9.0050228,16.9802954 8.55730755,17.4280106 8.55730755,17.9802954 C8.55730755,18.5325801 9.0050228,18.9802954 9.55730755,18.9802954 Z"
id="Oval-26" fill="#8FA1B3" fill-rule="nonzero"
transform="translate(12.033030, 15.830470) rotate(39.000000) translate(-12.033030, -15.830470) ">
</path>
</g>
</g>
</svg>
</label>
</div>
</div>
</div>
<div class="inputArea">
<textarea class="textarea" id="textarea" name="content" placeholder="请输入文字"></textarea>
</div>
</form>
<span class="send-btn submit-btn-wrap">发送</span>
</div>
</div>
<div class="content-right">
<div class="content-right-top font14">关于我们</div>
<div class="company-content font12">
</div>
</div>
</div>
</div>
<script type="text/javascript">
if (typeof console == "undefined") { this.console = { log: function (msg) { } }; }
var ws, name, client_list = {};
function connect() {
ws = new WebSocket("wss://cs.btcaholic.com/ct");
ws.onmessage = onmessage;
ws.onclose = function () {
console.log("连接关闭,定时重连");
connect();
};
ws.onerror = function () {
console.log("出现错误");
};
}
function onmessage(e) {
var data = JSON.parse(e.data);
console.log(data)
switch (data['type']) {
case 'login':
var bild = '{"type":"bild","room_id":"{:session('kefu')}"}';
ws.send(bild);
break;
case 'bild':
var id = data.room_id;
if (!id) {
alert('房间出错!');
}
break;
case "say":
if (data.group == '{:session('kefu')}<?php echo $_GET['toid']?>')
{
$(".chat-content").append('<div class="heisay"><div class="say_content"><p>游客' + data.time.substr(10, 9) + '</p><span>' + data.content + '</span></div></div>').parseEmotion();
$(".chat-content").scrollTop(3000);
}
return;
case "save":
save_message(data);
return;
}
}
$(".send-btn").click(function () {
var text = $(".textarea").val();
//解析新浪微博图片
text.replace(/(http|https):\/\/[\w]+.sinaimg.cn[\S]+(jpg|png|gif)/gi, function (img) {
return "<a target='_blank' href='" + img + "'>" + "<img src='" + img + "'>" + "</a>";
}
);
//解析url
text.replace(/(http|https):\/\/[\S]+/gi, function (url) {
if (url.indexOf(".sinaimg.cn/") < 0)
return "<a target='_blank' href='" + url + "'>" + url + "</a>";
else
return url;
}
);
if (text == '') {
return;
}
var time = getNowFormatDate();
var message = '{"content":"' + text + '","type":"say","room_id":"{:session('kefu')}","toid":"<?php echo $_GET['toid']?>","group":"{:session('kefu')}<?php echo $_GET['toid']?>"}';
$(".chat-content").append('<div class="mysay"><p>&nbsp;' + time + '</p><span>' + text + '</span></div>').parseEmotion();
$(".chat-content").scrollTop(3000);
console.log(11111);
ws.send(message);
$(".textarea").val("");
})
$('.face').click(function (event) {
$(this).sinaEmotion();
event.stopPropagation();
});
document.write('<meta name="viewport" content="width=device-width,initial-scale=1">');
$("textarea").on("keydown", function (e) {
// 按enter键自动提交
if (e.keyCode === 13 && !e.ctrlKey) {
e.preventDefault();
$(".send-btn").click();
return false;
}
// 按ctrl+enter组合键换行
if (e.keyCode === 13 && e.ctrlKey) {
$(this).val(function (i, val) {
return val + "\n";
});
}
});
function getNowFormatDate() {
var date = new Date();
var currentdate = date.toLocaleTimeString();
return currentdate;
}
function save_message(data) {
$.post("{:url('Index/save_message')}", data, function (e) {
//
});
}
$(function () {
$.post("{:url('Index/chat_record')}", "fid=<?php echo $_GET['toid']?>", function (data) {
for (var i = 0; i < data.length; i++) {
if (data[i].fid !== '{:session('kefu')}'){
$(".chat-content").append('<div class="heisay"><div class="say_content"><p>' + data[i].fid + '' + data[i].time.substr(10, 9) + '</p><span>' + data[i].content + '</span></div></div>').parseEmotion();
}
else {
$(".chat-content").append('<div class="mysay"><p>&nbsp;' + data[i].time.substr(10, 9) + '</p><span>' + data[i].content + '</span></div>').parseEmotion();
}
}
$(".chat-content").append('<div class="mysay">&nbsp;</div>');
$(".chat-content").scrollTop(3000);
});
})
</script>
<script>
document.addEventListener('visibilitychange', function () {
var isHidden = document.hidden;
if (isHidden) {
console.log('暂停');
} else {
console.log('开始');
}
});
/*
window.onfocus = function() {
console.log('开始');
};
//当前窗口失去焦点
window.onblur = function() {
console.log('暂停');
};
*/
</script>

52
src/main/resources/static/chat/css/chat.css

@ -0,0 +1,52 @@
@media only screen and (max-width: 750px) {
.newWindow {width:100%;background: #FFF !important;box-shadow: 0 0 20px 0 rgba(0,0,0,.15);-moz-box-shadow: 0 0 20px 0 rgba(0,0,0,.15);-webkit-box-shadow: 0 0 20px 0 rgba(0,0,0,.15);border-radius: 2px;overflow: hidden;box-sizing: content-box;}
}
@media (min-width:750px) {
.newWindow {left:50%;top:50%;width:800px;margin-left:-400px;margin-top: -300px;position: absolute;background: #FFF !important;box-shadow: 0 0 20px 0 rgba(0,0,0,.15);-moz-box-shadow: 0 0 20px 0 rgba(0,0,0,.15);-webkit-box-shadow: 0 0 20px 0 rgba(0,0,0,.15);border-radius: 2px;overflow: hidden;box-sizing: content-box;}
}
.toDeveloper {height: 40px !important;width: 66% !important;background: #FFF !important;bottom: 0 !important;z-index: 66;}
p,ul,li,h1,h2,h3,h4,h5,h6{margin:0;padding:0;}
li,ul{list-style: none;}
* {margin:0;padding:0;tap-highlight-color: rgba(0,0,0,0);-webkit-tap-highlight-color: rgba(0,0,0,0);line-height: 1.5;box-sizing: border-box;}
body {margin:0;background-color: #fafafa;overflow: auto;font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,"Helvetica Neue", Helvetica, "PingFang SC", SimSun, sans-serif;}
html,body {height:100%;}
input {outline: none;border:none;}
::-moz-placeholder {font-size: 13px;color: #8DA2B5;letter-spacing: 0.73px;}
::-webkit-input-placeholder {font-size: 13px;color: #8DA2B5;letter-spacing: 0.73px;}
:-ms-input-placeholder {font-size: 13px;color: #8DA2B5;letter-spacing: 0.73px;}
::selection {background:#FC4B4B!important;}
::-moz-selection {background:#FC4B4B!important;}
::-webkit-selection {background:#FC4B4B!important;}
.font12 {font-size: 12px;letter-spacing: 0.6px;}
.font14 {font-size: 14px;letter-spacing: 1px;}
.font16 {font-size: 16px;letter-spacing: 1px;}
.color-grey-deep {color: #28334B;}
.talk {display:block;position:relative;}
.pc-visitor-footer {height:160px;width: 100%;}
.pc-visitor-footer .function-bar {position:relative;background: #F8FAFC;height:40px;border-top:1px solid #E9EEF2;border-bottom:1px solid #E9EEF2;padding-left: 10px;}
.pc-visitor-footer .function-bar .svgWrap ,.pc-visitor-footer .function-bar .svgWrap svg ,.pc-visitor-footer .function-bar .svgWrap svg:hover .svgColor {fill:#1F8CEB;}
.pc-visitor-footer .function-bar label.active .svgColor {fill:#1F8CEB;}
.pc-visitor-footer .function-bar .talk-function-bar {height:100%;width:100%;padding-top: 8px;}
.pc-visitor-footer .inputArea textarea { width: 100%;height: 75px;padding:8px 5px;font-size: 14px;color: #28334B;letter-spacing: 0.28px;line-height: 19px;border: none;outline: none;resize: none;}
.submit-btn-wrap{float:right;margin-right:10px;width:80px;height:30px;background-color:#1e89e6;border-radius:2px;color:#fff;cursor:pointer;display:inline-block;text-align:center;line-height:30px;vertical-align: middle;}
.toDeveloperP {width:460px;font-size: 12px;height: 40px;background: #FFF;padding-top: 10px;line-height: 30px;padding-left: 5px;float:left}
.toDeveloper{color: #62778C;letter-spacing: 0.6px;text-decoration: none;}
.toDeveloper:hover{color:#218BFC;text-decoration: underline;}
.window-header {width: 100%;background: #1F8CEB;height:60px;display:block;padding-left: 15px;padding-top: 6px;}
.company-name {height:24px;line-height: 24px; color: #FFFFFF; letter-spacing: 0;}
.autograph {height:24px;line-height:24px;color: #FFFFFF;letter-spacing: 0;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;padding-right: 20px; }
.newWindow .window-content {height: 100%;width: 100%; }
.content-left{width:560px;float:left;height:540px}
.chat-content{overflow-y:auto;width:560px;height:377px}
.content-right {float:left;width:239px;vertical-align: top;height:540px;border-left:1px solid #DDE5ED;}
.content-right-top {border-bottom:1px solid #DDE5ED;width:100%;font-size: 14px;height:40px;color: #28334B;text-align:center;line-height:40px;letter-spacing: 0;}
.company-content {word-wrap:break-word;width:97%;padding-top:10px;padding-left:10px;overflow-y:auto;height:335px;}
.mysay{width:98%;margin:0;color:#3A3C4C;font-size:13px;float:right;margin-right:10px}
.heisay{width:98%;margin:0;color:#3A3C4C;font-size:13px;float:left;margin-left:10px}
.mysay p{text-align:right}
.heisay p{text-align:left;height:40px;display:table-cell;vertical-align:bottom;}
.mysay span{max-width:98%;padding-left:10px;padding-right:5px;padding-top:5px;padding-bottom:5px;float:right;background-color:rgb(31, 140, 232);color:fff;border-radius: 2px;}
.heisay span{max-width:98%;padding-left:5px;padding-right:10px;padding-top:5px;padding-bottom:5px;float:left;background-color:#EFF3F6;border-radius: 2px;}
.portrait{width:40px;height:40px;float:left}
.say_content{float:left}

1
src/main/resources/static/chat/css/jquery-sina-emotion.min.css

@ -0,0 +1 @@
#sina-emotion{z-index:999;width:373px;padding:10px;display:none;font-size:12px;background:#fff;position:absolute;border-radius:3px;border:1px solid #ccc;box-shadow:0 4px 20px 1px rgba(0,0,0,.2)}#sina-emotion .switch{float:right}#sina-emotion .next,#sina-emotion .prev{float:left;color:#555;width:22px;height:22px;font-size:20px;margin-left:5px;line-height:22px;text-align:center;background:#f8f8f8;text-decoration:none}#sina-emotion .item{float:left;list-style:none}#sina-emotion .categories,#sina-emotion .faces,#sina-emotion .pages{margin:0;padding:0;overflow:hidden}#sina-emotion .category{float:left;color:#0a8cd2;cursor:pointer;padding:0 8px;line-height:22px;border-radius:4px;white-space:nowrap}#sina-emotion .category:hover{text-decoration:underline}#sina-emotion .categories .current,#sina-emotion .categories .current:hover{color:#333;cursor:default;background:#e6e6e6;text-decoration:none}#sina-emotion .faces{width:372px;padding:11px 0 0 1px}#sina-emotion .face{z-index:1;float:left;width:26px;height:26px;cursor:pointer;overflow:hidden;padding:4px 2px;position:relative;text-align:center;margin:-1px 0 0 -1px;border:1px solid #e8e8e8}#sina-emotion .face:hover{z-index:2;border:1px solid #0095cd}#sina-emotion .pages{float:right;margin-top:8px}#sina-emotion .page{float:left;height:22px;padding:0 8px;color:#0a8cd2;margin-left:5px;line-height:22px;border-radius:1px;background:#f2f2f2;text-decoration:none}#sina-emotion .pages .current{color:#333;cursor:default;background:#fff}.sina-emotion{border:0;width:22px;height:22px;vertical-align:text-bottom}

BIN
src/main/resources/static/chat/img/0.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
src/main/resources/static/chat/img/btcex.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

296
src/main/resources/static/chat/js/jquery-sina-emotion.js

@ -0,0 +1,296 @@
/**
* jQuery Sina Emotion
* @author [Jealous](http://www.clanfei.com/)
* @license MIT
*/
(function (global, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
factory(require('jquery'));
} else {
factory(global.jQuery);
}
}(this, function ($) {
'use strict';
var STATE_UNINITIALIZED = 0;
var STATE_LOADING = 1;
var STATE_LOADED = 2;
var $target;
var options;
var callbacks = [];
var emotions = {};
var categories = [];
var emotionsMap = {};
var defCategory = '默认';
var state = STATE_UNINITIALIZED;
function initEvents() {
var $sinaEmotion = $('#sina-emotion');
$('body').bind({
click: function () {
$sinaEmotion.hide();
}
});
$sinaEmotion.bind({
click: function (event) {
event.stopPropagation();
}
}).delegate('.prev', {
click: function (event) {
var page = $sinaEmotion.find('.categories').data('page');
showCatPage(page - 1);
event.preventDefault();
}
}).delegate('.next', {
click: function (event) {
var page = $sinaEmotion.find('.categories').data('page');
showCatPage(page + 1);
event.preventDefault();
}
}).delegate('.category', {
click: function (event) {
$sinaEmotion.find('.categories .current').removeClass('current');
showCategory($.trim($(this).addClass('current').text()));
event.preventDefault();
}
}).delegate('.page', {
click: function (event) {
$sinaEmotion.find('.pages .current').removeClass('current');
var page = parseInt($(this).addClass('current').text(), 10) - 1;
showFacePage(page);
event.preventDefault();
}
}).delegate('.face', {
click: function (event) {
$sinaEmotion.hide();
$target.insertText($(this).children('img').prop('alt')).focus();
event.preventDefault();
}
});
}
function loadEmotions(callback) {
if (state === STATE_LOADED) {
callback && callback();
return;
} else if (state === STATE_LOADING) {
callback && callbacks.push(callback);
return;
} else {
callback && callbacks.push(callback);
}
state = STATE_LOADING;
options = options || $.fn.sinaEmotion.options;
var $sinaEmotion = $('<div id="sina-emotion">正在加载,请稍后...</div>');
$('body').append($sinaEmotion);
initEvents();
$.getJSON('https://api.weibo.com/2/emotions.json?callback=?', {
source: options.appKey,
language: options.language
}, function (res) {
var item;
var category;
var data = res.data;
$('#sina-emotion').html('<div class="switch">' +
'<a href="#" class="prev">&laquo;</a>' +
'<a href="#" class="next">&raquo;</a>' +
'</div>' +
'<ul class="categories"></ul>' +
'<ul class="faces"></ul>' +
'<ul class="pages"></ul>'
);
for (var i = 0, l = data.length; i < l; ++i) {
item = data[i];
category = item['category'] || defCategory;
if (!emotions[category]) {
emotions[category] = [];
categories.push(category);
}
emotions[category].push({
icon: item['icon'],
phrase: item['phrase']
});
emotionsMap[item['phrase']] = item.icon;
}
for (var j = 0, m = callbacks.length; j < m; ++j) {
callbacks[j]();
}
if (categories.length <= 5) {
$sinaEmotion.children('.switch').remove();
}
state = STATE_LOADED;
});
}
function showCatPage(page) {
var html = '';
var length = categories.length;
var maxPage = Math.ceil(length / 5);
var $categories = $('#sina-emotion').find('.categories');
var category = $categories.data('category') || defCategory;
page = (page + maxPage) % maxPage;
for (var i = page * 5; i < length && i < (page + 1) * 5; ++i) {
html += '<li class="item">' +
'<a href="#" class="category' + (category === categories[i] ? ' current' : '') + '">' + categories[i] + '</a>' +
'</li>';
}
$categories.data('page', page).html(html);
}
function showCategory(category) {
$('#sina-emotion').find('.categories').data('category', category);
showFacePage(0);
showPages();
}
function showFacePage(page) {
var face;
var html = '';
var rows = options.rows;
var $sinaEmotion = $('#sina-emotion');
var category = $sinaEmotion.find('.categories').data('category');
var faces = emotions[category];
page = page || 0;
for (var i = page * rows, l = faces.length; i < l && i < (page + 1) * rows; ++i) {
face = faces[i];
html += '<li class="item">' +
'<a href="#" class="face">' +
'<img class="sina-emotion" src="' + face['icon'] + '" alt="' + face['phrase'] + '" />' +
'</a>' +
'</li>';
}
$sinaEmotion.find('.faces').html(html);
}
function showPages() {
var html = '';
var rows = options.rows;
var $sinaEmotion = $('#sina-emotion');
var category = $sinaEmotion.find('.categories').data('category');
var faces = emotions[category];
var length = faces.length;
if (length > rows) {
for (var i = 0, l = Math.ceil(length / rows); i < l; ++i) {
html += '<li class="item">' +
'<a href="#" class="page' + (i === 0 ? ' current' : '') + '">' + (i + 1) + '</a>' +
'</li>';
}
$sinaEmotion.find('.pages').html(html).show();
} else {
$sinaEmotion.find('.pages').hide();
}
}
/**
* 为某个元素设置点击事件点击弹出表情选择窗口
* @param {String|function} target 用于插入表情文本框选择器或返回文本框 jQuery 对象的方法
*/
$.fn.sinaEmotion = function (target) {
var $this = $(this).last();
var offset = $this.offset();
target = target || function () {
return $this.parents('form').find('textarea, input[type=text]').eq(0);
};
if ($this.is(':visible')) {
if (typeof target === 'function') {
$target = target.call($this);
} else {
$target = $(target);
}
loadEmotions(function () {
showCategory(defCategory);
showCatPage(0);
});
$('#sina-emotion').css({
top: offset.top + $this.outerHeight() + 5,
left: offset.left
}).show();
}
return this;
};
$.fn.parseEmotion = function () {
var $this = $(this);
loadEmotions(function () {
$this.each(function () {
var $this = $(this);
var html = $this.html();
html = html.replace(/<.*?>/g, function ($1) {
$1 = $1.replace('[', '&#91;');
$1 = $1.replace(']', '&#93;');
return $1;
}).replace(/\[[^\[\]]*?]/g, function ($1) {
var url = emotionsMap[$1];
if (url) {
return '<img class="sina-emotion" src="' + url + '" alt="' + $1 + '" />';
}
return $1;
});
$this.html(html);
});
});
return this;
};
$.fn.insertText = function (text) {
this.each(function () {
if (this.tagName !== 'INPUT' && this.tagName !== 'TEXTAREA') {
return;
}
if (document.selection) {
this.focus();
var cr = document.selection.createRange();
cr.text = text;
cr.collapse();
cr.select();
} else if (this.selectionStart !== undefined) {
var start = this.selectionStart;
var end = this.selectionEnd;
this.value = this.value.substring(0, start) + text + this.value.substring(end, this.value.length);
this.selectionStart = this.selectionEnd = start + text.length;
} else {
this.value += text;
}
});
return this;
};
$.fn.sinaEmotion.options = {
rows: 72, // 每页显示的表情数
language: 'cnname', // 简体(cnname)、繁体(twname)
appKey: '1362404091' // 新浪微博开放平台的应用ID
};
}));

4
src/main/resources/static/chat/js/jquery.min.js

File diff suppressed because one or more lines are too long

4
src/main/resources/static/chat/js/swfobject.js

File diff suppressed because one or more lines are too long

398
src/main/resources/static/chat/js/web_socket.js

@ -0,0 +1,398 @@
// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
// License: New BSD License
// Reference: http://dev.w3.org/html5/websockets/
// Reference: http://tools.ietf.org/html/rfc6455
(function() {
if (window.WEB_SOCKET_FORCE_FLASH) {
// Keeps going.
} else if (window.WebSocket) {
return;
} else if (window.MozWebSocket) {
// Firefox.
window.WebSocket = MozWebSocket;
return;
}
var logger;
if (window.WEB_SOCKET_LOGGER) {
logger = WEB_SOCKET_LOGGER;
} else if (window.console && window.console.log && window.console.error) {
// In some environment, console is defined but console.log or console.error is missing.
logger = window.console;
} else {
logger = {log: function(){ }, error: function(){ }};
}
// swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash.
if (swfobject.getFlashPlayerVersion().major < 10) {
logger.error("Flash Player >= 10.0.0 is required.");
return;
}
if (location.protocol == "file:") {
logger.error(
"WARNING: web-socket-js doesn't work in file:///... URL " +
"unless you set Flash Security Settings properly. " +
"Open the page via Web server i.e. http://...");
}
/**
* Our own implementation of WebSocket class using Flash.
* @param {string} url
* @param {array or string} protocols
* @param {string} proxyHost
* @param {int} proxyPort
* @param {string} headers
*/
window.WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
var self = this;
self.__id = WebSocket.__nextId++;
WebSocket.__instances[self.__id] = self;
self.readyState = WebSocket.CONNECTING;
self.bufferedAmount = 0;
self.__events = {};
if (!protocols) {
protocols = [];
} else if (typeof protocols == "string") {
protocols = [protocols];
}
// Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
// Otherwise, when onopen fires immediately, onopen is called before it is set.
self.__createTask = setTimeout(function() {
WebSocket.__addTask(function() {
self.__createTask = null;
WebSocket.__flash.create(
self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
});
}, 0);
};
/**
* Send data to the web socket.
* @param {string} data The data to send to the socket.
* @return {boolean} True for success, false for failure.
*/
WebSocket.prototype.send = function(data) {
if (this.readyState == WebSocket.CONNECTING) {
throw "INVALID_STATE_ERR: Web Socket connection has not been established";
}
// We use encodeURIComponent() here, because FABridge doesn't work if
// the argument includes some characters. We don't use escape() here
// because of this:
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
// But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
// preserve all Unicode characters either e.g. "\uffff" in Firefox.
// Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
// additional testing.
var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
if (result < 0) { // success
return true;
} else {
this.bufferedAmount += result;
return false;
}
};
/**
* Close this web socket gracefully.
*/
WebSocket.prototype.close = function() {
if (this.__createTask) {
clearTimeout(this.__createTask);
this.__createTask = null;
this.readyState = WebSocket.CLOSED;
return;
}
if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
return;
}
this.readyState = WebSocket.CLOSING;
WebSocket.__flash.close(this.__id);
};
/**
* Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
*
* @param {string} type
* @param {function} listener
* @param {boolean} useCapture
* @return void
*/
WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
if (!(type in this.__events)) {
this.__events[type] = [];
}
this.__events[type].push(listener);
};
/**
* Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
*
* @param {string} type
* @param {function} listener
* @param {boolean} useCapture
* @return void
*/
WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
if (!(type in this.__events)) return;
var events = this.__events[type];
for (var i = events.length - 1; i >= 0; --i) {
if (events[i] === listener) {
events.splice(i, 1);
break;
}
}
};
/**
* Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
*
* @param {Event} event
* @return void
*/
WebSocket.prototype.dispatchEvent = function(event) {
var events = this.__events[event.type] || [];
for (var i = 0; i < events.length; ++i) {
events[i](event);
}
var handler = this["on" + event.type];
if (handler) handler.apply(this, [event]);
};
/**
* Handles an event from Flash.
* @param {Object} flashEvent
*/
WebSocket.prototype.__handleEvent = function(flashEvent) {
if ("readyState" in flashEvent) {
this.readyState = flashEvent.readyState;
}
if ("protocol" in flashEvent) {
this.protocol = flashEvent.protocol;
}
var jsEvent;
if (flashEvent.type == "open" || flashEvent.type == "error") {
jsEvent = this.__createSimpleEvent(flashEvent.type);
} else if (flashEvent.type == "close") {
jsEvent = this.__createSimpleEvent("close");
jsEvent.wasClean = flashEvent.wasClean ? true : false;
jsEvent.code = flashEvent.code;
jsEvent.reason = flashEvent.reason;
} else if (flashEvent.type == "message") {
var data = decodeURIComponent(flashEvent.message);
jsEvent = this.__createMessageEvent("message", data);
} else {
throw "unknown event type: " + flashEvent.type;
}
this.dispatchEvent(jsEvent);
};
WebSocket.prototype.__createSimpleEvent = function(type) {
if (document.createEvent && window.Event) {
var event = document.createEvent("Event");
event.initEvent(type, false, false);
return event;
} else {
return {type: type, bubbles: false, cancelable: false};
}
};
WebSocket.prototype.__createMessageEvent = function(type, data) {
if (window.MessageEvent && typeof(MessageEvent) == "function" && !window.opera) {
return new MessageEvent("message", {
"view": window,
"bubbles": false,
"cancelable": false,
"data": data
});
} else if (document.createEvent && window.MessageEvent && !window.opera) {
var event = document.createEvent("MessageEvent");
event.initMessageEvent("message", false, false, data, null, null, window, null);
return event;
} else {
// Old IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
return {type: type, data: data, bubbles: false, cancelable: false};
}
};
/**
* Define the WebSocket readyState enumeration.
*/
WebSocket.CONNECTING = 0;
WebSocket.OPEN = 1;
WebSocket.CLOSING = 2;
WebSocket.CLOSED = 3;
// Field to check implementation of WebSocket.
WebSocket.__isFlashImplementation = true;
WebSocket.__initialized = false;
WebSocket.__flash = null;
WebSocket.__instances = {};
WebSocket.__tasks = [];
WebSocket.__nextId = 0;
/**
* Load a new flash security policy file.
* @param {string} url
*/
WebSocket.loadFlashPolicyFile = function(url){
WebSocket.__addTask(function() {
WebSocket.__flash.loadManualPolicyFile(url);
});
};
/**
* Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
*/
WebSocket.__initialize = function() {
if (WebSocket.__initialized) return;
WebSocket.__initialized = true;
if (WebSocket.__swfLocation) {
// For backword compatibility.
window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
}
if (!window.WEB_SOCKET_SWF_LOCATION) {
logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
return;
}
if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR &&
!WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) &&
WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) {
var swfHost = RegExp.$1;
if (location.host != swfHost) {
logger.error(
"[WebSocket] You must host HTML and WebSocketMain.swf in the same host " +
"('" + location.host + "' != '" + swfHost + "'). " +
"See also 'How to host HTML file and SWF file in different domains' section " +
"in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " +
"by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;");
}
}
var container = document.createElement("div");
container.id = "webSocketContainer";
// Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
// Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
// But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
// Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
// the best we can do as far as we know now.
container.style.position = "absolute";
if (WebSocket.__isFlashLite()) {
container.style.left = "0px";
container.style.top = "0px";
} else {
container.style.left = "-100px";
container.style.top = "-100px";
}
var holder = document.createElement("div");
holder.id = "webSocketFlash";
container.appendChild(holder);
document.body.appendChild(container);
// See this article for hasPriority:
// http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
swfobject.embedSWF(
WEB_SOCKET_SWF_LOCATION,
"webSocketFlash",
"1" /* width */,
"1" /* height */,
"10.0.0" /* SWF version */,
null,
null,
{hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
null,
function(e) {
if (!e.success) {
logger.error("[WebSocket] swfobject.embedSWF failed");
}
}
);
};
/**
* Called by Flash to notify JS that it's fully loaded and ready
* for communication.
*/
WebSocket.__onFlashInitialized = function() {
// We need to set a timeout here to avoid round-trip calls
// to flash during the initialization process.
setTimeout(function() {
WebSocket.__flash = document.getElementById("webSocketFlash");
WebSocket.__flash.setCallerUrl(location.href);
WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
for (var i = 0; i < WebSocket.__tasks.length; ++i) {
WebSocket.__tasks[i]();
}
WebSocket.__tasks = [];
}, 0);
};
/**
* Called by Flash to notify WebSockets events are fired.
*/
WebSocket.__onFlashEvent = function() {
setTimeout(function() {
try {
// Gets events using receiveEvents() instead of getting it from event object
// of Flash event. This is to make sure to keep message order.
// It seems sometimes Flash events don't arrive in the same order as they are sent.
var events = WebSocket.__flash.receiveEvents();
for (var i = 0; i < events.length; ++i) {
WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
}
} catch (e) {
logger.error(e);
}
}, 0);
return true;
};
// Called by Flash.
WebSocket.__log = function(message) {
logger.log(decodeURIComponent(message));
};
// Called by Flash.
WebSocket.__error = function(message) {
logger.error(decodeURIComponent(message));
};
WebSocket.__addTask = function(task) {
if (WebSocket.__flash) {
task();
} else {
WebSocket.__tasks.push(task);
}
};
/**
* Test if the browser is running flash lite.
* @return {boolean} True if flash lite is running, false otherwise.
*/
WebSocket.__isFlashLite = function() {
if (!window.navigator || !window.navigator.mimeTypes) {
return false;
}
var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
return false;
}
return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
};
if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
// NOTE:
// This fires immediately if web_socket.js is dynamically loaded after
// the document is loaded.
swfobject.addDomLoadEvent(function() {
WebSocket.__initialize();
});
}
})();

BIN
src/main/resources/static/chat/swf/WebSocketMain.swf

Binary file not shown.
Loading…
Cancel
Save