layim.js 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873
  1. /**
  2. @Name:layim v3.9.1 Pro 商用版
  3. @Author:贤心
  4. @Site:http://layim.layui.com
  5. @License:LGPL
  6. */
  7. layui.define(['layer', 'laytpl', 'upload'], function(exports){
  8. var v = '3.9.1';
  9. var $ = layui.$;
  10. var layer = layui.layer;
  11. var laytpl = layui.laytpl;
  12. var device = layui.device();
  13. var SHOW = 'layui-show', THIS = 'layim-this', MAX_ITEM = 20;
  14. //回调
  15. var call = {};
  16. //对外API
  17. var LAYIM = function(){
  18. this.v = v;
  19. $('body').on('click', '*[layim-event]', function(e){
  20. var othis = $(this), methid = othis.attr('layim-event');
  21. events[methid] ? events[methid].call(this, othis, e) : '';
  22. });
  23. };
  24. //基础配置
  25. LAYIM.prototype.config = function(options){
  26. var skin = [];
  27. layui.each(Array(5), function(index){
  28. skin.push(layui.cache.dir+'css/modules/layim/skin/'+ (index+1) +'.jpg')
  29. });
  30. options = options || {};
  31. options.skin = options.skin || [];
  32. layui.each(options.skin, function(index, item){
  33. skin.unshift(item);
  34. });
  35. options.skin = skin;
  36. options = $.extend({
  37. isfriend: !0
  38. ,isgroup: !0
  39. ,voice: 'default.mp3'
  40. }, options);
  41. if(!window.JSON || !window.JSON.parse) return;
  42. init(options);
  43. return this;
  44. };
  45. //监听事件
  46. LAYIM.prototype.on = function(events, callback){
  47. if(typeof callback === 'function'){
  48. call[events] ? call[events].push(callback) : call[events] = [callback];
  49. }
  50. return this;
  51. };
  52. //获取所有缓存数据
  53. LAYIM.prototype.cache = function(){
  54. return cache;
  55. };
  56. //打开一个自定义的会话界面
  57. LAYIM.prototype.chat = function(data){
  58. if(!window.JSON || !window.JSON.parse) return;
  59. return popchat(data), this;
  60. };
  61. //设置聊天界面最小化
  62. LAYIM.prototype.setChatMin = function(){
  63. return setChatMin(), this;
  64. };
  65. //设置当前会话状态
  66. LAYIM.prototype.setChatStatus = function(str){
  67. var thatChat = thisChat();
  68. if(!thatChat) return;
  69. var status = thatChat.elem.find('.layim-chat-status');
  70. return status.html(str), this;
  71. };
  72. //接受消息
  73. LAYIM.prototype.getMessage = function(data){
  74. return getMessage(data), this;
  75. };
  76. //桌面消息通知
  77. LAYIM.prototype.notice = function(data){
  78. return notice(data), this;
  79. };
  80. //打开添加好友/群组面板
  81. LAYIM.prototype.add = function(data){
  82. return popAdd(data), this;
  83. };
  84. //好友分组面板
  85. LAYIM.prototype.setFriendGroup = function(data){
  86. return popAdd(data, 'setGroup'), this;
  87. };
  88. //消息盒子的提醒
  89. LAYIM.prototype.msgbox = function(nums){
  90. return msgbox(nums), this;
  91. };
  92. //添加好友/群
  93. LAYIM.prototype.addList = function(data){
  94. return addList(data), this;
  95. };
  96. //删除好友/群
  97. LAYIM.prototype.removeList = function(data){
  98. return removeList(data), this;
  99. };
  100. //设置好友在线/离线状态
  101. LAYIM.prototype.setFriendStatus = function(id, type){
  102. var list = $('.layim-friend'+ id);
  103. list[type === 'online' ? 'removeClass' : 'addClass']('layim-list-gray');
  104. };
  105. //解析聊天内容
  106. LAYIM.prototype.content = function(content){
  107. return layui.data.content(content);
  108. };
  109. //主模板
  110. var listTpl = function(options){
  111. var nodata = {
  112. friend: "该分组下暂无好友"
  113. ,group: "暂无群组"
  114. ,history: "暂无历史会话"
  115. };
  116. options = options || {};
  117. options.item = options.item || ('d.' + options.type);
  118. return ['{{# var length = 0; layui.each('+ options.item +', function(i, data){ length++; }}'
  119. ,'<li layim-event="chat" data-type="'+ options.type +'" data-index="{{ '+ (options.index||'i') +' }}" class="layim-'+ (options.type === 'history' ? '{{i}}' : options.type + '{{data.id}}') +' {{ data.status === "offline" ? "layim-list-gray" : "" }}"><img src="{{ data.avatar }}"><span>{{ data.username||data.groupname||data.name||"佚名" }}</span><p>{{ data.remark||data.sign||"" }}</p><span class="layim-msg-status">new</span></li>'
  120. ,'{{# }); if(length === 0){ }}'
  121. ,'<li class="layim-null">'+ (nodata[options.type] || "暂无数据") +'</li>'
  122. ,'{{# } }}'].join('');
  123. };
  124. var elemTpl = ['<div class="layui-layim-main">'
  125. ,'<div class="layui-layim-info">'
  126. ,'<div class="layui-layim-user">{{ d.mine.username }}</div>'
  127. ,'<div class="layui-layim-status">'
  128. ,'{{# if(d.mine.status === "online"){ }}'
  129. ,'<span class="layui-icon layim-status-online" layim-event="status" lay-type="show">&#xe617;</span>'
  130. ,'{{# } else if(d.mine.status === "hide") { }}'
  131. ,'<span class="layui-icon layim-status-hide" layim-event="status" lay-type="show">&#xe60f;</span>'
  132. ,'{{# } }}'
  133. ,'<ul class="layui-anim layim-menu-box">'
  134. ,'<li {{d.mine.status === "online" ? "class=layim-this" : ""}} layim-event="status" lay-type="online"><i class="layui-icon">&#xe605;</i><cite class="layui-icon layim-status-online">&#xe617;</cite>在线</li>'
  135. ,'<li {{d.mine.status === "hide" ? "class=layim-this" : ""}} layim-event="status" lay-type="hide"><i class="layui-icon">&#xe605;</i><cite class="layui-icon layim-status-hide">&#xe60f;</cite>隐身</li>'
  136. ,'</ul>'
  137. ,'</div>'
  138. ,'<input class="layui-layim-remark" placeholder="编辑签名" value="{{ d.mine.remark||d.mine.sign||"" }}">'
  139. ,'</div>'
  140. ,'<ul class="layui-unselect layui-layim-tab{{# if(!d.base.isfriend || !d.base.isgroup){ }}'
  141. ,' layim-tab-two'
  142. ,'{{# } }}">'
  143. ,'<li class="layui-icon'
  144. ,'{{# if(!d.base.isfriend){ }}'
  145. ,' layim-hide'
  146. ,'{{# } else { }}'
  147. ,' layim-this'
  148. ,'{{# } }}'
  149. ,'" title="联系人" layim-event="tab" lay-type="friend">&#xe612;</li>'
  150. ,'<li class="layui-icon'
  151. ,'{{# if(!d.base.isgroup){ }}'
  152. ,' layim-hide'
  153. ,'{{# } else if(!d.base.isfriend) { }}'
  154. ,' layim-this'
  155. ,'{{# } }}'
  156. ,'" title="群组" layim-event="tab" lay-type="group">&#xe613;</li>'
  157. ,'<li class="layui-icon" title="历史会话" layim-event="tab" lay-type="history">&#xe611;</li>'
  158. ,'</ul>'
  159. ,'<ul class="layui-unselect layim-tab-content {{# if(d.base.isfriend){ }}layui-show{{# } }} layim-list-friend">'
  160. ,'{{# layui.each(d.friend, function(index, item){ var spread = d.local["spread"+index]; }}'
  161. ,'<li>'
  162. ,'<h5 layim-event="spread" lay-type="{{ spread }}"><i class="layui-icon">{{# if(spread === "true"){ }}&#xe61a;{{# } else { }}&#xe602;{{# } }}</i><span>{{ item.groupname||"未命名分组"+index }}</span><em>(<cite class="layim-count"> {{ (item.list||[]).length }}</cite>)</em></h5>'
  163. ,'<ul class="layui-layim-list {{# if(spread === "true"){ }}'
  164. ,' layui-show'
  165. ,'{{# } }}">'
  166. ,listTpl({
  167. type: "friend"
  168. ,item: "item.list"
  169. ,index: "index"
  170. })
  171. ,'</ul>'
  172. ,'</li>'
  173. ,'{{# }); if(d.friend.length === 0){ }}'
  174. ,'<li><ul class="layui-layim-list layui-show"><li class="layim-null">暂无联系人</li></ul>'
  175. ,'{{# } }}'
  176. ,'</ul>'
  177. ,'<ul class="layui-unselect layim-tab-content {{# if(!d.base.isfriend && d.base.isgroup){ }}layui-show{{# } }}">'
  178. ,'<li>'
  179. ,'<ul class="layui-layim-list layui-show layim-list-group">'
  180. ,listTpl({
  181. type: 'group'
  182. })
  183. ,'</ul>'
  184. ,'</li>'
  185. ,'</ul>'
  186. ,'<ul class="layui-unselect layim-tab-content {{# if(!d.base.isfriend && !d.base.isgroup){ }}layui-show{{# } }}">'
  187. ,'<li>'
  188. ,'<ul class="layui-layim-list layui-show layim-list-history">'
  189. ,listTpl({
  190. type: 'history'
  191. })
  192. ,'</ul>'
  193. ,'</li>'
  194. ,'</ul>'
  195. ,'<ul class="layui-unselect layim-tab-content">'
  196. ,'<li>'
  197. ,'<ul class="layui-layim-list layui-show" id="layui-layim-search"></ul>'
  198. ,'</li>'
  199. ,'</ul>'
  200. ,'<ul class="layui-unselect layui-layim-tool">'
  201. ,'<li class="layui-icon layim-tool-search" layim-event="search" title="搜索">&#xe615;</li>'
  202. ,'{{# if(d.base.msgbox){ }}'
  203. ,'<li class="layui-icon layim-tool-msgbox" layim-event="msgbox" title="消息盒子">&#xe645;<span class="layui-anim"></span></li>'
  204. ,'{{# } }}'
  205. ,'{{# if(d.base.find){ }}'
  206. ,'<li class="layui-icon layim-tool-find" layim-event="find" title="查找">&#xe608;</li>'
  207. ,'{{# } }}'
  208. ,'<li class="layui-icon layim-tool-skin" layim-event="skin" title="更换背景">&#xe61b;</li>'
  209. ,'{{# if(!d.base.copyright){ }}'
  210. ,'<li class="layui-icon layim-tool-about" layim-event="about" title="关于">&#xe60b;</li>'
  211. ,'{{# } }}'
  212. ,'</ul>'
  213. ,'<div class="layui-layim-search"><input><label class="layui-icon" layim-event="closeSearch">&#x1007;</label></div>'
  214. ,'</div>'].join('');
  215. //换肤模版
  216. var elemSkinTpl = ['<ul class="layui-layim-skin">'
  217. ,'{{# layui.each(d.skin, function(index, item){ }}'
  218. ,'<li><img layim-event="setSkin" src="{{ item }}"></li>'
  219. ,'{{# }); }}'
  220. ,'<li layim-event="setSkin"><cite>简约</cite></li>'
  221. ,'</ul>'].join('');
  222. //聊天主模板
  223. var elemChatTpl = ['<div class="layim-chat layim-chat-{{d.data.type}}{{d.first ? " layui-show" : ""}}">'
  224. ,'<div class="layui-unselect layim-chat-title">'
  225. ,'<div class="layim-chat-other">'
  226. ,'<img class="layim-{{ d.data.type }}{{ d.data.id }}" src="{{ d.data.avatar }}"><span class="layim-chat-username" layim-event="{{ d.data.type==="group" ? \"groupMembers\" : \"\" }}">{{ d.data.name||"佚名" }} {{d.data.temporary ? "<cite>临时会话</cite>" : ""}} {{# if(d.data.type==="group"){ }} <em class="layim-chat-members"></em><i class="layui-icon">&#xe61a;</i> {{# } }}</span>'
  227. ,'<p class="layim-chat-status"></p>'
  228. ,'</div>'
  229. ,'</div>'
  230. ,'<div class="layim-chat-main">'
  231. ,'<ul></ul>'
  232. ,'</div>'
  233. ,'<div class="layim-chat-footer">'
  234. ,'<div class="layui-unselect layim-chat-tool" data-json="{{encodeURIComponent(JSON.stringify(d.data))}}">'
  235. ,'<span class="layui-icon layim-tool-face" title="选择表情" layim-event="face">&#xe60c;</span>'
  236. ,'{{# if(d.base && d.base.uploadImage){ }}'
  237. ,'<span class="layui-icon layim-tool-image" title="上传图片" layim-event="image">&#xe60d;<input type="file" name="file"></span>'
  238. ,'{{# }; }}'
  239. ,'{{# if(d.base && d.base.uploadFile){ }}'
  240. ,'<span class="layui-icon layim-tool-image" title="发送文件" layim-event="image" data-type="file">&#xe61d;<input type="file" name="file"></span>'
  241. ,'{{# }; }}'
  242. ,'{{# if(d.base && d.base.isAudio){ }}'
  243. ,'<span class="layui-icon layim-tool-audio" title="发送网络音频" layim-event="media" data-type="audio">&#xe6fc;</span>'
  244. ,'{{# }; }}'
  245. ,'{{# if(d.base && d.base.isVideo){ }}'
  246. ,'<span class="layui-icon layim-tool-video" title="发送网络视频" layim-event="media" data-type="video">&#xe6ed;</span>'
  247. ,'{{# }; }}'
  248. ,'{{# layui.each(d.base.tool, function(index, item){ }}'
  249. ,'<span class="layui-icon layim-tool-{{item.alias}}" title="{{item.title}}" layim-event="extend" lay-filter="{{ item.alias }}">{{item.icon}}</span>'
  250. ,'{{# }); }}'
  251. ,'{{# if(d.base && d.base.chatLog){ }}'
  252. ,'<span class="layim-tool-log" layim-event="chatLog"><i class="layui-icon">&#xe60e;</i>聊天记录</span>'
  253. ,'{{# }; }}'
  254. ,'</div>'
  255. ,'<div class="layim-chat-textarea"><textarea></textarea></div>'
  256. ,'<div class="layim-chat-bottom">'
  257. ,'<div class="layim-chat-send">'
  258. ,'{{# if(!d.base.brief){ }}'
  259. ,'<span class="layim-send-close" layim-event="closeThisChat">关闭</span>'
  260. ,'{{# } }}'
  261. ,'<span class="layim-send-btn" layim-event="send">发送</span>'
  262. ,'<span class="layim-send-set" layim-event="setSend" lay-type="show"><em class="layui-edge"></em></span>'
  263. ,'<ul class="layui-anim layim-menu-box">'
  264. ,'<li {{d.local.sendHotKey !== "Ctrl+Enter" ? "class=layim-this" : ""}} layim-event="setSend" lay-type="Enter"><i class="layui-icon">&#xe605;</i>按Enter键发送消息</li>'
  265. ,'<li {{d.local.sendHotKey === "Ctrl+Enter" ? "class=layim-this" : ""}} layim-event="setSend" lay-type="Ctrl+Enter"><i class="layui-icon">&#xe605;</i>按Ctrl+Enter键发送消息</li>'
  266. ,'</ul>'
  267. ,'</div>'
  268. ,'</div>'
  269. ,'</div>'
  270. ,'</div>'].join('');
  271. //添加好友群组模版
  272. var elemAddTpl = ['<div class="layim-add-box">'
  273. ,'<div class="layim-add-img"><img class="layui-circle" src="{{ d.data.avatar }}"><p>{{ d.data.name||"" }}</p></div>'
  274. ,'<div class="layim-add-remark">'
  275. ,'{{# if(d.data.type === "friend" && d.type === "setGroup"){ }}'
  276. ,'<p>选择分组</p>'
  277. ,'{{# } if(d.data.type === "friend"){ }}'
  278. ,'<select class="layui-select" id="LAY_layimGroup">'
  279. ,'{{# layui.each(d.data.group, function(index, item){ }}'
  280. ,'<option value="{{ item.id }}">{{ item.groupname }}</option>'
  281. ,'{{# }); }}'
  282. ,'</select>'
  283. ,'{{# } }}'
  284. ,'{{# if(d.data.type === "group"){ }}'
  285. ,'<p>请输入验证信息</p>'
  286. ,'{{# } if(d.type !== "setGroup"){ }}'
  287. ,'<textarea id="LAY_layimRemark" placeholder="验证信息" class="layui-textarea"></textarea>'
  288. ,'{{# } }}'
  289. ,'</div>'
  290. ,'</div>'].join('');
  291. //聊天内容列表模版
  292. var elemChatMain = ['<li {{ d.mine ? "class=layim-chat-mine" : "" }} {{# if(d.cid){ }}data-cid="{{d.cid}}"{{# } }}>'
  293. ,'<div class="layim-chat-user"><img src="{{ d.avatar }}"><cite>'
  294. ,'{{# if(d.mine){ }}'
  295. ,'<i>{{ layui.data.date(d.timestamp) }}</i>{{ d.username||"佚名" }}'
  296. ,'{{# } else { }}'
  297. ,'{{ d.username||"佚名" }}<i>{{ layui.data.date(d.timestamp) }}</i>'
  298. ,'{{# } }}'
  299. ,'</cite></div>'
  300. ,'<div class="layim-chat-text">{{ layui.data.content(d.content||"&nbsp") }}</div>'
  301. ,'</li>'].join('');
  302. var elemChatList = '<li class="layim-{{ d.data.type }}{{ d.data.id }} layim-chatlist-{{ d.data.type }}{{ d.data.id }} layim-this" layim-event="tabChat"><img src="{{ d.data.avatar }}"><span>{{ d.data.name||"佚名" }}</span>{{# if(!d.base.brief){ }}<i class="layui-icon" layim-event="closeChat">&#x1007;</i>{{# } }}</li>';
  303. //补齐数位
  304. var digit = function(num){
  305. return num < 10 ? '0' + (num|0) : num;
  306. };
  307. //转换时间
  308. layui.data.date = function(timestamp){
  309. var d = new Date(timestamp||new Date());
  310. return d.getFullYear() + '-' + digit(d.getMonth() + 1) + '-' + digit(d.getDate())
  311. + ' ' + digit(d.getHours()) + ':' + digit(d.getMinutes()) + ':' + digit(d.getSeconds());
  312. };
  313. //转换内容
  314. layui.data.content = function(content){
  315. //支持的html标签
  316. var html = function(end){
  317. return new RegExp('\\n*\\['+ (end||'') +'(code|pre|div|span|p|table|thead|th|tbody|tr|td|ul|li|ol|li|dl|dt|dd|h2|h3|h4|h5)([\\s\\S]*?)\\]\\n*', 'g');
  318. };
  319. content = (content||'').replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
  320. .replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/'/g, '&#39;').replace(/"/g, '&quot;') //XSS
  321. .replace(/@(\S+)(\s+?|$)/g, '@<a href="javascript:;">$1</a>$2') //转义@
  322. .replace(/face\[([^\s\[\]]+?)\]/g, function(face){ //转义表情
  323. var alt = face.replace(/^face/g, '');
  324. return '<img alt="'+ alt +'" title="'+ alt +'" src="' + faces[alt] + '">';
  325. })
  326. .replace(/img\[([^\s]+?)\]/g, function(img){ //转义图片
  327. return '<img class="layui-layim-photos" src="' + img.replace(/(^img\[)|(\]$)/g, '') + '">';
  328. })
  329. .replace(/file\([\s\S]+?\)\[[\s\S]*?\]/g, function(str){ //转义文件
  330. var href = (str.match(/file\(([\s\S]+?)\)\[/)||[])[1];
  331. var text = (str.match(/\)\[([\s\S]*?)\]/)||[])[1];
  332. if(!href) return str;
  333. return '<a class="layui-layim-file" href="'+ href +'" download target="_blank"><i class="layui-icon">&#xe61e;</i><cite>'+ (text||href) +'</cite></a>';
  334. })
  335. .replace(/audio\[([^\s]+?)\]/g, function(audio){ //转义音频
  336. return '<div class="layui-unselect layui-layim-audio" layim-event="playAudio" data-src="' + audio.replace(/(^audio\[)|(\]$)/g, '') + '"><i class="layui-icon">&#xe652;</i><p>音频消息</p></div>';
  337. })
  338. .replace(/video\[([^\s]+?)\]/g, function(video){ //转义音频
  339. return '<div class="layui-unselect layui-layim-video" layim-event="playVideo" data-src="' + video.replace(/(^video\[)|(\]$)/g, '') + '"><i class="layui-icon">&#xe652;</i></div>';
  340. })
  341. .replace(/a\([\s\S]+?\)\[[\s\S]*?\]/g, function(str){ //转义链接
  342. var href = (str.match(/a\(([\s\S]+?)\)\[/)||[])[1];
  343. var text = (str.match(/\)\[([\s\S]*?)\]/)||[])[1];
  344. if(!href) return str;
  345. return '<a href="'+ href +'" target="_blank">'+ (text||href) +'</a>';
  346. }).replace(html(), '\<$1 $2\>').replace(html('/'), '\</$1\>') //转移HTML代码
  347. .replace(/\n/g, '<br>') //转义换行
  348. return content;
  349. };
  350. //Ajax
  351. var post = function(options, callback, tips){
  352. options = options || {};
  353. return $.ajax({
  354. url: options.url
  355. ,type: options.type || 'get'
  356. ,data: options.data
  357. ,dataType: options.dataType || 'json'
  358. ,cache: false
  359. ,success: function(res){
  360. res.code == 0
  361. ? callback && callback(res.data||{})
  362. : layer.msg(res.msg || ((tips||'Error') + ': LAYIM_NOT_GET_DATA'), {
  363. time: 5000
  364. });
  365. },error: function(err, msg){
  366. window.console && console.log && console.error('LAYIM_DATE_ERROR:' + msg);
  367. }
  368. });
  369. };
  370. //处理初始化信息
  371. var cache = {message: {}, chat: []}, init = function(options){
  372. var init = options.init || {}
  373. mine = init.mine || {}
  374. ,local = layui.data('layim')[mine.id] || {}
  375. ,obj = {
  376. base: options
  377. ,local: local
  378. ,mine: mine
  379. ,history: local.history || {}
  380. }, create = function(data){
  381. var mine = data.mine || {};
  382. var local = layui.data('layim')[mine.id] || {}, obj = {
  383. base: options //基础配置信息
  384. ,local: local //本地数据
  385. ,mine: mine //我的用户信息
  386. ,friend: data.friend || [] //联系人信息
  387. ,group: data.group || [] //群组信息
  388. ,history: local.history || {} //历史会话信息
  389. };
  390. cache = $.extend(cache, obj);
  391. popim(laytpl(elemTpl).render(obj));
  392. if(local.close || options.min){
  393. popmin();
  394. }
  395. layui.each(call.ready, function(index, item){
  396. item && item(obj);
  397. });
  398. };
  399. cache = $.extend(cache, obj);
  400. if(options.brief){
  401. return layui.each(call.ready, function(index, item){
  402. item && item(obj);
  403. });
  404. };
  405. init.url ? post(init, create, 'INIT') : create(init);
  406. };
  407. //显示主面板
  408. var layimMain, popim = function(content){
  409. return layer.open({
  410. type: 1
  411. ,area: ['260px', '520px']
  412. ,skin: 'layui-box layui-layim'
  413. ,title: '&#8203;'
  414. ,offset: 'rb'
  415. ,id: 'layui-layim'
  416. ,shade: false
  417. ,anim: 2
  418. ,resize: false
  419. ,content: content
  420. ,success: function(layero){
  421. layimMain = layero;
  422. setSkin(layero);
  423. if(cache.base.right){
  424. layero.css('margin-left', '-' + cache.base.right);
  425. }
  426. if(layimClose){
  427. layer.close(layimClose.attr('times'));
  428. }
  429. //按最新会话重新排列
  430. var arr = [], historyElem = layero.find('.layim-list-history');
  431. historyElem.find('li').each(function(){
  432. arr.push($(this).prop('outerHTML'))
  433. });
  434. if(arr.length > 0){
  435. arr.reverse();
  436. historyElem.html(arr.join(''));
  437. }
  438. banRightMenu();
  439. events.sign();
  440. }
  441. ,cancel: function(index){
  442. popmin();
  443. var local = layui.data('layim')[cache.mine.id] || {};
  444. local.close = true;
  445. layui.data('layim', {
  446. key: cache.mine.id
  447. ,value: local
  448. });
  449. return false;
  450. }
  451. });
  452. };
  453. //屏蔽主面板右键菜单
  454. var banRightMenu = function(){
  455. layimMain.on('contextmenu', function(event){
  456. event.cancelBubble = true
  457. event.returnValue = false;
  458. return false;
  459. });
  460. var hide = function(){
  461. layer.closeAll('tips');
  462. };
  463. //自定义历史会话右键菜单
  464. layimMain.find('.layim-list-history').on('contextmenu', 'li', function(e){
  465. var othis = $(this);
  466. var html = '<ul data-id="'+ othis[0].id +'" data-index="'+ othis.data('index') +'"><li layim-event="menuHistory" data-type="one">移除该会话</li><li layim-event="menuHistory" data-type="all">清空全部会话列表</li></ul>';
  467. if(othis.hasClass('layim-null')) return;
  468. layer.tips(html, this, {
  469. tips: 1
  470. ,time: 0
  471. ,anim: 5
  472. ,fixed: true
  473. ,skin: 'layui-box layui-layim-contextmenu'
  474. ,success: function(layero){
  475. var stopmp = function(e){ stope(e); };
  476. layero.off('mousedown', stopmp).on('mousedown', stopmp);
  477. }
  478. });
  479. $(document).off('mousedown', hide).on('mousedown', hide);
  480. $(window).off('resize', hide).on('resize', hide);
  481. });
  482. }
  483. //主面板最小化状态
  484. var layimClose, popmin = function(content){
  485. if(layimClose){
  486. layer.close(layimClose.attr('times'));
  487. }
  488. if(layimMain){
  489. layimMain.hide();
  490. }
  491. cache.mine = cache.mine || {};
  492. return layer.open({
  493. type: 1
  494. ,title: false
  495. ,id: 'layui-layim-close'
  496. ,skin: 'layui-box layui-layim-min layui-layim-close'
  497. ,shade: false
  498. ,closeBtn: false
  499. ,anim: 2
  500. ,offset: 'rb'
  501. ,resize: false
  502. ,content: '<img src="'+ (cache.mine.avatar||(layui.cache.dir+'css/pc/layim/skin/logo.jpg')) +'"><span>'+ (content||cache.base.title||'我的LayIM') +'</span>'
  503. ,move: '#layui-layim-close img'
  504. ,success: function(layero, index){
  505. layimClose = layero;
  506. if(cache.base.right){
  507. layero.css('margin-left', '-' + cache.base.right);
  508. }
  509. layero.on('click', function(){
  510. layer.close(index);
  511. layimMain.show();
  512. var local = layui.data('layim')[cache.mine.id] || {};
  513. delete local.close;
  514. layui.data('layim', {
  515. key: cache.mine.id
  516. ,value: local
  517. });
  518. });
  519. }
  520. });
  521. };
  522. //显示聊天面板
  523. var layimChat, layimMin, chatIndex, To = {}, popchat = function(data){
  524. data = data || {};
  525. var chat = $('#layui-layim-chat'), render = {
  526. data: data
  527. ,base: cache.base
  528. ,local: cache.local
  529. };
  530. if(!data.id){
  531. return layer.msg('非法用户');
  532. }
  533. if(chat[0]){
  534. var list = layimChat.find('.layim-chat-list');
  535. var listThat = list.find('.layim-chatlist-'+ data.type + data.id);
  536. var hasFull = layimChat.find('.layui-layer-max').hasClass('layui-layer-maxmin');
  537. var chatBox = chat.children('.layim-chat-box');
  538. //如果是最小化,则还原窗口
  539. if(layimChat.css('display') === 'none'){
  540. layimChat.show();
  541. }
  542. if(layimMin){
  543. layer.close(layimMin.attr('times'));
  544. }
  545. //如果出现多个聊天面板
  546. if(list.find('li').length === 1 && !listThat[0]){
  547. hasFull || layimChat.css('width', 800);
  548. list.css({
  549. height: layimChat.height()
  550. }).show();
  551. chatBox.css('margin-left', '200px');
  552. }
  553. //打开的是非当前聊天面板,则新增面板
  554. if(!listThat[0]){
  555. list.append(laytpl(elemChatList).render(render));
  556. chatBox.append(laytpl(elemChatTpl).render(render));
  557. syncGray(data);
  558. resizeChat();
  559. }
  560. changeChat(list.find('.layim-chatlist-'+ data.type + data.id));
  561. listThat[0] || viewChatlog();
  562. setHistory(data);
  563. hotkeySend();
  564. return chatIndex;
  565. }
  566. render.first = !0;
  567. var index = chatIndex = layer.open({
  568. type: 1
  569. ,area: '600px'
  570. ,skin: 'layui-box layui-layim-chat'
  571. ,id: 'layui-layim-chat'
  572. ,title: '&#8203;'
  573. ,shade: false
  574. ,maxmin: true
  575. ,offset: data.offset || 'auto'
  576. ,anim: data.anim || 0
  577. ,closeBtn: cache.base.brief ? false : 1
  578. ,content: laytpl('<ul class="layui-unselect layim-chat-list">'+ elemChatList +'</ul><div class="layim-chat-box">' + elemChatTpl + '</div>').render(render)
  579. ,success: function(layero){
  580. layimChat = layero;
  581. layero.css({
  582. 'min-width': '500px'
  583. ,'min-height': '420px'
  584. });
  585. syncGray(data);
  586. typeof data.success === 'function' && data.success(layero);
  587. hotkeySend();
  588. setSkin(layero);
  589. setHistory(data);
  590. viewChatlog();
  591. showOffMessage();
  592. //聊天窗口的切换监听
  593. layui.each(call.chatChange, function(index, item){
  594. item && item(thisChat());
  595. });
  596. //查看大图
  597. layero.on('dblclick', '.layui-layim-photos', function(){
  598. var src = this.src;
  599. layer.close(popchat.photosIndex);
  600. layer.photos({
  601. photos: {
  602. data: [{
  603. "alt": "大图模式",
  604. "src": src
  605. }]
  606. }
  607. ,shade: 0.01
  608. ,closeBtn: 2
  609. ,anim: 0
  610. ,resize: false
  611. ,success: function(layero, index){
  612. popchat.photosIndex = index;
  613. }
  614. });
  615. });
  616. }
  617. ,full: function(layero){
  618. layer.style(index, {
  619. width: '100%'
  620. ,height: '100%'
  621. }, true);
  622. resizeChat();
  623. }
  624. ,resizing: resizeChat
  625. ,restore: resizeChat
  626. ,min: function(){
  627. setChatMin();
  628. return false;
  629. }
  630. ,end: function(){
  631. layer.closeAll('tips');
  632. layimChat = null;
  633. }
  634. });
  635. return index;
  636. };
  637. //同步置灰状态
  638. var syncGray = function(data){
  639. $('.layim-'+data.type+data.id).each(function(){
  640. if($(this).hasClass('layim-list-gray')){
  641. layui.layim.setFriendStatus(data.id, 'offline');
  642. }
  643. });
  644. };
  645. //重置聊天窗口大小
  646. var resizeChat = function(){
  647. var list = layimChat.find('.layim-chat-list')
  648. ,chatMain = layimChat.find('.layim-chat-main')
  649. ,chatHeight = layimChat.height();
  650. list.css({
  651. height: chatHeight
  652. });
  653. chatMain.css({
  654. height: chatHeight - 20 - 80 - 158
  655. })
  656. };
  657. //设置聊天窗口最小化 & 新消息提醒
  658. var setChatMin = function(newMsg){
  659. var thatChat = newMsg || thisChat().data, base = layui.layim.cache().base;
  660. if(layimChat && !newMsg){
  661. layimChat.hide();
  662. }
  663. layer.close(setChatMin.index);
  664. setChatMin.index = layer.open({
  665. type: 1
  666. ,title: false
  667. ,skin: 'layui-box layui-layim-min'
  668. ,shade: false
  669. ,closeBtn: false
  670. ,anim: thatChat.anim || 2
  671. ,offset: 'b'
  672. ,move: '#layui-layim-min'
  673. ,resize: false
  674. ,area: ['182px', '50px']
  675. ,content: '<img id="layui-layim-min" src="'+ thatChat.avatar +'"><span>'+ thatChat.name +'</span>'
  676. ,success: function(layero, index){
  677. if(!newMsg) layimMin = layero;
  678. if(base.minRight){
  679. layer.style(index, {
  680. left: $(window).width() - layero.outerWidth() - parseFloat(base.minRight)
  681. });
  682. }
  683. layero.find('.layui-layer-content span').on('click', function(){
  684. layer.close(index);
  685. newMsg ? layui.each(cache.chat, function(i, item){
  686. popchat(item);
  687. }) : layimChat.show();
  688. if(newMsg){
  689. cache.chat = [];
  690. chatListMore();
  691. }
  692. });
  693. layero.find('.layui-layer-content img').on('click', function(e){
  694. stope(e);
  695. });
  696. }
  697. });
  698. };
  699. //打开添加好友、群组面板、好友分组面板
  700. var popAdd = function(data, type){
  701. data = data || {};
  702. layer.close(popAdd.index);
  703. return popAdd.index = layer.open({
  704. type: 1
  705. ,area: '430px'
  706. ,title: {
  707. friend: '添加好友'
  708. ,group: '加入群组'
  709. }[data.type] || ''
  710. ,shade: false
  711. ,resize: false
  712. ,btn: type ? ['确认', '取消'] : ['发送申请', '关闭']
  713. ,content: laytpl(elemAddTpl).render({
  714. data: {
  715. name: data.username || data.groupname
  716. ,avatar: data.avatar
  717. ,group: data.group || parent.layui.layim.cache().friend || []
  718. ,type: data.type
  719. }
  720. ,type: type
  721. })
  722. ,yes: function(index, layero){
  723. var groupElem = layero.find('#LAY_layimGroup')
  724. ,remarkElem = layero.find('#LAY_layimRemark')
  725. if(type){
  726. data.submit && data.submit(groupElem.val(), index);
  727. } else {
  728. data.submit && data.submit(groupElem.val(), remarkElem.val(), index);
  729. }
  730. }
  731. });
  732. };
  733. //切换聊天
  734. var changeChat = function(elem, del){
  735. elem = elem || $('.layim-chat-list .' + THIS);
  736. var index = elem.index() === -1 ? 0 : elem.index();
  737. var str = '.layim-chat', cont = layimChat.find(str).eq(index);
  738. var hasFull = layimChat.find('.layui-layer-max').hasClass('layui-layer-maxmin');
  739. if(del){
  740. //如果关闭的是当前聊天,则切换聊天焦点
  741. if(elem.hasClass(THIS)){
  742. changeChat(index === 0 ? elem.next() : elem.prev());
  743. }
  744. var length = layimChat.find(str).length;
  745. //关闭聊天界面
  746. if(length === 1){
  747. return layer.close(chatIndex);
  748. }
  749. elem.remove();
  750. cont.remove();
  751. //只剩下1个列表,隐藏左侧区块
  752. if(length === 2){
  753. layimChat.find('.layim-chat-list').hide();
  754. if(!hasFull){
  755. layimChat.css('width', '600px');
  756. }
  757. layimChat.find('.layim-chat-box').css('margin-left', 0);
  758. }
  759. return false;
  760. }
  761. elem.addClass(THIS).siblings().removeClass(THIS);
  762. cont.addClass(SHOW).siblings(str).removeClass(SHOW);
  763. cont.find('textarea').focus();
  764. //聊天窗口的切换监听
  765. layui.each(call.chatChange, function(index, item){
  766. item && item(thisChat());
  767. });
  768. showOffMessage();
  769. };
  770. //展示存在队列中的消息
  771. var showOffMessage = function(){
  772. var thatChat = thisChat();
  773. var message = cache.message[thatChat.data.type + thatChat.data.id];
  774. if(message){
  775. //展现后,删除队列中消息
  776. delete cache.message[thatChat.data.type + thatChat.data.id];
  777. }
  778. };
  779. //获取当前聊天面板
  780. var thisChat = LAYIM.prototype.thisChat = function(){
  781. if(!layimChat) return;
  782. var index = $('.layim-chat-list .' + THIS).index();
  783. var cont = layimChat.find('.layim-chat').eq(index);
  784. var to = JSON.parse(decodeURIComponent(cont.find('.layim-chat-tool').data('json')));
  785. return {
  786. elem: cont
  787. ,data: to
  788. ,textarea: cont.find('textarea')
  789. };
  790. };
  791. //记录初始背景
  792. var setSkin = function(layero){
  793. var local = layui.data('layim')[cache.mine.id] || {}
  794. ,skin = local.skin;
  795. layero.css({
  796. 'background-image': skin ? 'url('+ skin +')' : function(){
  797. return cache.base.initSkin
  798. ? 'url('+ (layui.cache.dir+'css/modules/layim/skin/'+ cache.base.initSkin) +')'
  799. : 'none';
  800. }()
  801. });
  802. };
  803. //记录历史会话
  804. var setHistory = function(data){
  805. var local = layui.data('layim')[cache.mine.id] || {};
  806. var obj = {}, history = local.history || {};
  807. var is = history[data.type + data.id];
  808. if(!layimMain) return;
  809. var historyElem = layimMain.find('.layim-list-history');
  810. data.historyTime = new Date().getTime();
  811. history[data.type + data.id] = data;
  812. local.history = history;
  813. layui.data('layim', {
  814. key: cache.mine.id
  815. ,value: local
  816. });
  817. if(is) return;
  818. obj[data.type + data.id] = data;
  819. var historyList = laytpl(listTpl({
  820. type: 'history'
  821. ,item: 'd.data'
  822. })).render({data: obj});
  823. historyElem.prepend(historyList);
  824. historyElem.find('.layim-null').remove();
  825. };
  826. //发送消息
  827. var sendMessage = function(){
  828. var data = {
  829. username: cache.mine ? cache.mine.username : '访客'
  830. ,avatar: cache.mine ? cache.mine.avatar : (layui.cache.dir+'css/pc/layim/skin/logo.jpg')
  831. ,id: cache.mine ? cache.mine.id : null
  832. ,mine: true
  833. };
  834. var thatChat = thisChat(), ul = thatChat.elem.find('.layim-chat-main ul');
  835. var maxLength = cache.base.maxLength || 3000;
  836. data.content = thatChat.textarea.val();
  837. if(data.content.replace(/\s/g, '') !== ''){
  838. if(data.content.length > maxLength){
  839. return layer.msg('内容最长不能超过'+ maxLength +'个字符')
  840. }
  841. ul.append(laytpl(elemChatMain).render(data));
  842. var param = {
  843. mine: data
  844. ,to: thatChat.data
  845. }, message = {
  846. username: param.mine.username
  847. ,avatar: param.mine.avatar
  848. ,id: param.to.id
  849. ,type: param.to.type
  850. ,content: param.mine.content
  851. ,timestamp: new Date().getTime()
  852. ,mine: true
  853. };
  854. pushChatlog(message);
  855. layui.each(call.sendMessage, function(index, item){
  856. item && item(param);
  857. });
  858. }
  859. chatListMore();
  860. thatChat.textarea.val('').focus();
  861. };
  862. //桌面消息提醒
  863. var notice = function(data){
  864. data = data || {};
  865. if (window.Notification){
  866. if(Notification.permission === 'granted'){
  867. var notification = new Notification(data.title||'', {
  868. body: data.content||''
  869. ,icon: data.avatar||'http://tp2.sinaimg.cn/5488749285/50/5719808192/1'
  870. });
  871. }else {
  872. Notification.requestPermission();
  873. };
  874. }
  875. };
  876. //消息声音提醒
  877. var voice = function() {
  878. if(device.ie && device.ie < 9) return;
  879. var audio = document.createElement("audio");
  880. audio.src = layui.cache.dir+'css/modules/layim/voice/'+ cache.base.voice;
  881. audio.play();
  882. };
  883. //接受消息
  884. var messageNew = {}, getMessage = function(data){
  885. data = data || {};
  886. var elem = $('.layim-chatlist-'+ data.type + data.id);
  887. var group = {}, index = elem.index();
  888. data.timestamp = data.timestamp || new Date().getTime();
  889. if(data.fromid == cache.mine.id){
  890. data.mine = true;
  891. }
  892. data.system || pushChatlog(data);
  893. messageNew = JSON.parse(JSON.stringify(data));
  894. if(cache.base.voice){
  895. voice();
  896. }
  897. if((!layimChat && data.content) || index === -1){
  898. if(cache.message[data.type + data.id]){
  899. cache.message[data.type + data.id].push(data)
  900. } else {
  901. cache.message[data.type + data.id] = [data];
  902. //记录聊天面板队列
  903. if(data.type === 'friend'){
  904. var friend;
  905. layui.each(cache.friend, function(index1, item1){
  906. layui.each(item1.list, function(index, item){
  907. if(item.id == data.id){
  908. item.type = 'friend';
  909. item.name = item.username;
  910. cache.chat.push(item);
  911. return friend = true;
  912. }
  913. });
  914. if(friend) return true;
  915. });
  916. if(!friend){
  917. data.name = data.username;
  918. data.temporary = true; //临时会话
  919. cache.chat.push(data);
  920. }
  921. } else if(data.type === 'group'){
  922. var isgroup;
  923. layui.each(cache.group, function(index, item){
  924. if(item.id == data.id){
  925. item.type = 'group';
  926. item.name = item.groupname;
  927. cache.chat.push(item);
  928. return isgroup = true;
  929. }
  930. });
  931. if(!isgroup){
  932. data.name = data.groupname;
  933. cache.chat.push(data);
  934. }
  935. } else {
  936. data.name = data.name || data.username || data.groupname;
  937. cache.chat.push(data);
  938. }
  939. }
  940. if(data.type === 'group'){
  941. layui.each(cache.group, function(index, item){
  942. if(item.id == data.id){
  943. group.avatar = item.avatar;
  944. return true;
  945. }
  946. });
  947. }
  948. if(!data.system){
  949. if(cache.base.notice){
  950. notice({
  951. title: '来自 '+ data.username +' 的消息'
  952. ,content: data.content
  953. ,avatar: group.avatar || data.avatar
  954. });
  955. }
  956. return setChatMin({
  957. name: '收到新消息'
  958. ,avatar: group.avatar || data.avatar
  959. ,anim: 6
  960. });
  961. }
  962. }
  963. if(!layimChat) return;
  964. //接受到的消息不在当前Tab
  965. var thatChat = thisChat();
  966. if(thatChat.data.type + thatChat.data.id !== data.type + data.id){
  967. elem.addClass('layui-anim layer-anim-06');
  968. setTimeout(function(){
  969. elem.removeClass('layui-anim layer-anim-06')
  970. }, 300);
  971. }
  972. var cont = layimChat.find('.layim-chat').eq(index);
  973. var ul = cont.find('.layim-chat-main ul');
  974. //系统消息
  975. if(data.system){
  976. if(index !== -1){
  977. ul.append('<li class="layim-chat-system"><span>'+ data.content +'</span></li>');
  978. }
  979. } else if(data.content.replace(/\s/g, '') !== ''){
  980. ul.append(laytpl(elemChatMain).render(data));
  981. }
  982. chatListMore();
  983. };
  984. //消息盒子的提醒
  985. var ANIM_MSG = 'layui-anim-loop layer-anim-05', msgbox = function(num){
  986. var msgboxElem = layimMain.find('.layim-tool-msgbox');
  987. msgboxElem.find('span').addClass(ANIM_MSG).html(num);
  988. };
  989. //存储最近MAX_ITEM条聊天记录到本地
  990. var pushChatlog = function(message){
  991. var local = layui.data('layim')[cache.mine.id] || {};
  992. local.chatlog = local.chatlog || {};
  993. var thisChatlog = local.chatlog[message.type + message.id];
  994. if(thisChatlog){
  995. //避免浏览器多窗口时聊天记录重复保存
  996. var nosame;
  997. layui.each(thisChatlog, function(index, item){
  998. if((item.timestamp === message.timestamp
  999. && item.type === message.type
  1000. && item.id === message.id
  1001. && item.content === message.content)){
  1002. nosame = true;
  1003. }
  1004. });
  1005. if(!(nosame || message.fromid == cache.mine.id)){
  1006. thisChatlog.push(message);
  1007. }
  1008. if(thisChatlog.length > MAX_ITEM){
  1009. thisChatlog.shift();
  1010. }
  1011. } else {
  1012. local.chatlog[message.type + message.id] = [message];
  1013. }
  1014. layui.data('layim', {
  1015. key: cache.mine.id
  1016. ,value: local
  1017. });
  1018. };
  1019. //渲染本地最新聊天记录到相应面板
  1020. var viewChatlog = function(){
  1021. var local = layui.data('layim')[cache.mine.id] || {}
  1022. ,thatChat = thisChat(), chatlog = local.chatlog || {}
  1023. ,ul = thatChat.elem.find('.layim-chat-main ul');
  1024. layui.each(chatlog[thatChat.data.type + thatChat.data.id], function(index, item){
  1025. ul.append(laytpl(elemChatMain).render(item));
  1026. });
  1027. chatListMore();
  1028. };
  1029. //添加好友或群
  1030. var addList = function(data){
  1031. var obj = {}, has, listElem = layimMain.find('.layim-list-'+ data.type);
  1032. if(cache[data.type]){
  1033. if(data.type === 'friend'){
  1034. layui.each(cache.friend, function(index, item){
  1035. if(data.groupid == item.id){
  1036. //检查好友是否已经在列表中
  1037. layui.each(cache.friend[index].list, function(idx, itm){
  1038. if(itm.id == data.id){
  1039. return has = true
  1040. }
  1041. });
  1042. if(has) return layer.msg('好友 ['+ (data.username||'') +'] 已经存在列表中',{anim: 6});
  1043. cache.friend[index].list = cache.friend[index].list || [];
  1044. obj[cache.friend[index].list.length] = data;
  1045. data.groupIndex = index;
  1046. cache.friend[index].list.push(data); //在cache的friend里面也增加好友
  1047. return true;
  1048. }
  1049. });
  1050. } else if(data.type === 'group'){
  1051. //检查群组是否已经在列表中
  1052. layui.each(cache.group, function(idx, itm){
  1053. if(itm.id == data.id){
  1054. return has = true
  1055. }
  1056. });
  1057. if(has) return layer.msg('您已是 ['+ (data.groupname||'') +'] 的群成员',{anim: 6});
  1058. obj[cache.group.length] = data;
  1059. cache.group.push(data);
  1060. }
  1061. }
  1062. if(has) return;
  1063. var list = laytpl(listTpl({
  1064. type: data.type
  1065. ,item: 'd.data'
  1066. ,index: data.type === 'friend' ? 'data.groupIndex' : null
  1067. })).render({data: obj});
  1068. if(data.type === 'friend'){
  1069. var li = listElem.find('>li').eq(data.groupIndex);
  1070. li.find('.layui-layim-list').append(list);
  1071. li.find('.layim-count').html(cache.friend[data.groupIndex].list.length); //刷新好友数量
  1072. //如果初始没有好友
  1073. if(li.find('.layim-null')[0]){
  1074. li.find('.layim-null').remove();
  1075. }
  1076. } else if(data.type === 'group'){
  1077. listElem.append(list);
  1078. //如果初始没有群组
  1079. if(listElem.find('.layim-null')[0]){
  1080. listElem.find('.layim-null').remove();
  1081. }
  1082. }
  1083. };
  1084. //移出好友或群
  1085. var removeList = function(data){
  1086. var listElem = layimMain.find('.layim-list-'+ data.type);
  1087. var obj = {};
  1088. if(cache[data.type]){
  1089. if(data.type === 'friend'){
  1090. layui.each(cache.friend, function(index1, item1){
  1091. layui.each(item1.list, function(index, item){
  1092. if(data.id == item.id){
  1093. var li = listElem.find('>li').eq(index1);
  1094. var list = li.find('.layui-layim-list>li');
  1095. li.find('.layui-layim-list>li').eq(index).remove();
  1096. cache.friend[index1].list.splice(index, 1); //从cache的friend里面也删除掉好友
  1097. li.find('.layim-count').html(cache.friend[index1].list.length); //刷新好友数量
  1098. //如果一个好友都没了
  1099. if(cache.friend[index1].list.length === 0){
  1100. li.find('.layui-layim-list').html('<li class="layim-null">该分组下已无好友了</li>');
  1101. }
  1102. return true;
  1103. }
  1104. });
  1105. });
  1106. } else if(data.type === 'group'){
  1107. layui.each(cache.group, function(index, item){
  1108. if(data.id == item.id){
  1109. listElem.find('>li').eq(index).remove();
  1110. cache.group.splice(index, 1); //从cache的group里面也删除掉数据
  1111. //如果一个群组都没了
  1112. if(cache.group.length === 0){
  1113. listElem.html('<li class="layim-null">暂无群组</li>');
  1114. }
  1115. return true;
  1116. }
  1117. });
  1118. }
  1119. }
  1120. };
  1121. //查看更多记录
  1122. var chatListMore = function(){
  1123. var thatChat = thisChat(), chatMain = thatChat.elem.find('.layim-chat-main');
  1124. var ul = chatMain.find('ul');
  1125. var length = ul.find('li').length;
  1126. if(length >= MAX_ITEM){
  1127. var first = ul.find('li').eq(0);
  1128. if(!ul.prev().hasClass('layim-chat-system')){
  1129. ul.before('<div class="layim-chat-system"><span layim-event="chatLog">查看更多记录</span></div>');
  1130. }
  1131. if(length > MAX_ITEM){
  1132. first.remove();
  1133. }
  1134. }
  1135. chatMain.scrollTop(chatMain[0].scrollHeight + 1000);
  1136. chatMain.find('ul li:last').find('img').load(function(){
  1137. chatMain.scrollTop(chatMain[0].scrollHeight+1000);
  1138. });
  1139. };
  1140. //快捷键发送
  1141. var hotkeySend = function(){
  1142. var thatChat = thisChat(), textarea = thatChat.textarea;
  1143. textarea.focus();
  1144. textarea.off('keydown').on('keydown', function(e){
  1145. var local = layui.data('layim')[cache.mine.id] || {};
  1146. var keyCode = e.keyCode;
  1147. if(local.sendHotKey === 'Ctrl+Enter'){
  1148. if(e.ctrlKey && keyCode === 13){
  1149. sendMessage();
  1150. }
  1151. return;
  1152. }
  1153. if(keyCode === 13){
  1154. if(e.ctrlKey){
  1155. return textarea.val(textarea.val()+'\n');
  1156. }
  1157. if(e.shiftKey) return;
  1158. e.preventDefault();
  1159. sendMessage();
  1160. }
  1161. });
  1162. };
  1163. //表情库
  1164. var faces = function(){
  1165. var alt = ["[微笑]", "[嘻嘻]", "[哈哈]", "[可爱]", "[可怜]", "[挖鼻]", "[吃惊]", "[害羞]", "[挤眼]", "[闭嘴]", "[鄙视]", "[爱你]", "[泪]", "[偷笑]", "[亲亲]", "[生病]", "[太开心]", "[白眼]", "[右哼哼]", "[左哼哼]", "[嘘]", "[衰]", "[委屈]", "[吐]", "[哈欠]", "[抱抱]", "[怒]", "[疑问]", "[馋嘴]", "[拜拜]", "[思考]", "[汗]", "[困]", "[睡]", "[钱]", "[失望]", "[酷]", "[色]", "[哼]", "[鼓掌]", "[晕]", "[悲伤]", "[抓狂]", "[黑线]", "[阴险]", "[怒骂]", "[互粉]", "[心]", "[伤心]", "[猪头]", "[熊猫]", "[兔子]", "[ok]", "[耶]", "[good]", "[NO]", "[赞]", "[来]", "[弱]", "[草泥马]", "[神马]", "[囧]", "[浮云]", "[给力]", "[围观]", "[威武]", "[奥特曼]", "[礼物]", "[钟]", "[话筒]", "[蜡烛]", "[蛋糕]"], arr = {};
  1166. layui.each(alt, function(index, item){
  1167. arr[item] = layui.cache.dir + 'images/face/'+ index + '.gif';
  1168. });
  1169. return arr;
  1170. }();
  1171. var stope = layui.stope; //组件事件冒泡
  1172. //在焦点处插入内容
  1173. var focusInsert = function(obj, str){
  1174. var result, val = obj.value;
  1175. obj.focus();
  1176. if(document.selection){ //ie
  1177. result = document.selection.createRange();
  1178. document.selection.empty();
  1179. result.text = str;
  1180. } else {
  1181. result = [val.substring(0, obj.selectionStart), str, val.substr(obj.selectionEnd)];
  1182. obj.focus();
  1183. obj.value = result.join('');
  1184. }
  1185. };
  1186. //事件
  1187. var anim = 'layui-anim-upbit', events = {
  1188. //在线状态
  1189. status: function(othis, e){
  1190. var hide = function(){
  1191. othis.next().hide().removeClass(anim);
  1192. };
  1193. var type = othis.attr('lay-type');
  1194. if(type === 'show'){
  1195. stope(e);
  1196. othis.next().show().addClass(anim);
  1197. $(document).off('click', hide).on('click', hide);
  1198. } else {
  1199. var prev = othis.parent().prev();
  1200. othis.addClass(THIS).siblings().removeClass(THIS);
  1201. prev.html(othis.find('cite').html());
  1202. prev.removeClass('layim-status-'+(type === 'online' ? 'hide' : 'online'))
  1203. .addClass('layim-status-'+type);
  1204. layui.each(call.online, function(index, item){
  1205. item && item(type);
  1206. });
  1207. }
  1208. }
  1209. //编辑签名
  1210. ,sign: function(){
  1211. var input = layimMain.find('.layui-layim-remark');
  1212. input.on('change', function(){
  1213. var value = this.value;
  1214. layui.each(call.sign, function(index, item){
  1215. item && item(value);
  1216. });
  1217. });
  1218. input.on('keyup', function(e){
  1219. var keyCode = e.keyCode;
  1220. if(keyCode === 13){
  1221. this.blur();
  1222. }
  1223. });
  1224. }
  1225. //大分组切换
  1226. ,tab: function(othis){
  1227. var index, main = '.layim-tab-content';
  1228. var tabs = layimMain.find('.layui-layim-tab>li');
  1229. typeof othis === 'number' ? (
  1230. index = othis
  1231. ,othis = tabs.eq(index)
  1232. ) : (
  1233. index = othis.index()
  1234. );
  1235. index > 2 ? tabs.removeClass(THIS) : (
  1236. events.tab.index = index
  1237. ,othis.addClass(THIS).siblings().removeClass(THIS)
  1238. )
  1239. layimMain.find(main).eq(index).addClass(SHOW).siblings(main).removeClass(SHOW);
  1240. }
  1241. //展开联系人分组
  1242. ,spread: function(othis){
  1243. var type = othis.attr('lay-type');
  1244. var spread = type === 'true' ? 'false' : 'true';
  1245. var local = layui.data('layim')[cache.mine.id] || {};
  1246. othis.next()[type === 'true' ? 'removeClass' : 'addClass'](SHOW);
  1247. local['spread' + othis.parent().index()] = spread;
  1248. layui.data('layim', {
  1249. key: cache.mine.id
  1250. ,value: local
  1251. });
  1252. othis.attr('lay-type', spread);
  1253. othis.find('.layui-icon').html(spread === 'true' ? '&#xe61a;' : '&#xe602;');
  1254. }
  1255. //搜索
  1256. ,search: function(othis){
  1257. var search = layimMain.find('.layui-layim-search');
  1258. var main = layimMain.find('#layui-layim-search');
  1259. var input = search.find('input'), find = function(e){
  1260. var val = input.val().replace(/\s/);
  1261. if(val === ''){
  1262. events.tab(events.tab.index|0);
  1263. } else {
  1264. var data = [], friend = cache.friend || [];
  1265. var group = cache.group || [], html = '';
  1266. for(var i = 0; i < friend.length; i++){
  1267. for(var k = 0; k < (friend[i].list||[]).length; k++){
  1268. if(friend[i].list[k].username.indexOf(val) !== -1){
  1269. friend[i].list[k].type = 'friend';
  1270. friend[i].list[k].index = i;
  1271. friend[i].list[k].list = k;
  1272. data.push(friend[i].list[k]);
  1273. }
  1274. }
  1275. }
  1276. for(var j = 0; j < group.length; j++){
  1277. if(group[j].groupname.indexOf(val) !== -1){
  1278. group[j].type = 'group';
  1279. group[j].index = j;
  1280. group[j].list = j;
  1281. data.push(group[j]);
  1282. }
  1283. }
  1284. if(data.length > 0){
  1285. for(var l = 0; l < data.length; l++){
  1286. html += '<li layim-event="chat" data-type="'+ data[l].type +'" data-index="'+ data[l].index +'" data-list="'+ data[l].list +'"><img src="'+ data[l].avatar +'"><span>'+ (data[l].username || data[l].groupname || '佚名') +'</span><p>'+ (data[l].remark||data[l].sign||'') +'</p></li>';
  1287. }
  1288. } else {
  1289. html = '<li class="layim-null">无搜索结果</li>';
  1290. }
  1291. main.html(html);
  1292. events.tab(3);
  1293. }
  1294. };
  1295. if(!cache.base.isfriend && cache.base.isgroup){
  1296. events.tab.index = 1;
  1297. } else if(!cache.base.isfriend && !cache.base.isgroup){
  1298. events.tab.index = 2;
  1299. }
  1300. search.show();
  1301. input.focus();
  1302. input.off('keyup', find).on('keyup', find);
  1303. }
  1304. //关闭搜索
  1305. ,closeSearch: function(othis){
  1306. othis.parent().hide();
  1307. events.tab(events.tab.index|0);
  1308. }
  1309. //消息盒子
  1310. ,msgbox: function(){
  1311. var msgboxElem = layimMain.find('.layim-tool-msgbox');
  1312. layer.close(events.msgbox.index);
  1313. msgboxElem.find('span').removeClass(ANIM_MSG).html('');
  1314. return events.msgbox.index = layer.open({
  1315. type: 2
  1316. ,title: '消息盒子'
  1317. ,shade: false
  1318. ,maxmin: true
  1319. ,area: ['600px', '520px']
  1320. ,skin: 'layui-box layui-layer-border'
  1321. ,resize: false
  1322. ,content: cache.base.msgbox
  1323. });
  1324. }
  1325. //弹出查找页面
  1326. ,find: function(){
  1327. layer.close(events.find.index);
  1328. return events.find.index = layer.open({
  1329. type: 2
  1330. ,title: '查找'
  1331. ,shade: false
  1332. ,maxmin: true
  1333. ,area: ['1000px', '520px']
  1334. ,skin: 'layui-box layui-layer-border'
  1335. ,resize: false
  1336. ,content: cache.base.find
  1337. });
  1338. }
  1339. //弹出更换背景
  1340. ,skin: function(){
  1341. layer.open({
  1342. type: 1
  1343. ,title: '更换背景'
  1344. ,shade: false
  1345. ,area: '300px'
  1346. ,skin: 'layui-box layui-layer-border'
  1347. ,id: 'layui-layim-skin'
  1348. ,zIndex: 66666666
  1349. ,resize: false
  1350. ,content: laytpl(elemSkinTpl).render({
  1351. skin: cache.base.skin
  1352. })
  1353. });
  1354. }
  1355. //关于
  1356. ,about: function(){
  1357. layer.alert('版本: '+ v + '<br>版权所有:<a href="http://layim.layui.com" target="_blank">layim.layui.com</a>', {
  1358. title: '关于 LayIM'
  1359. ,shade: false
  1360. });
  1361. }
  1362. //生成换肤
  1363. ,setSkin: function(othis){
  1364. var src = othis.attr('src');
  1365. var local = layui.data('layim')[cache.mine.id] || {};
  1366. local.skin = src;
  1367. if(!src) delete local.skin;
  1368. layui.data('layim', {
  1369. key: cache.mine.id
  1370. ,value: local
  1371. });
  1372. try{
  1373. layimMain.css({
  1374. 'background-image': src ? 'url('+ src +')' : 'none'
  1375. });
  1376. layimChat.css({
  1377. 'background-image': src ? 'url('+ src +')' : 'none'
  1378. });
  1379. } catch(e) {}
  1380. layui.each(call.setSkin, function(index, item){
  1381. var filename = (src||'').replace(layui.cache.dir+'css/modules/layim/skin/', '');
  1382. item && item(filename, src);
  1383. });
  1384. }
  1385. //弹出聊天面板
  1386. ,chat: function(othis){
  1387. var local = layui.data('layim')[cache.mine.id] || {};
  1388. var type = othis.data('type'), index = othis.data('index');
  1389. var list = othis.attr('data-list') || othis.index(), data = {};
  1390. if(type === 'friend'){
  1391. data = cache[type][index].list[list];
  1392. } else if(type === 'group'){
  1393. data = cache[type][list];
  1394. } else if(type === 'history'){
  1395. data = (local.history || {})[index] || {};
  1396. }
  1397. data.name = data.name || data.username || data.groupname;
  1398. if(type !== 'history'){
  1399. data.type = type;
  1400. }
  1401. popchat(data);
  1402. }
  1403. //切换聊天
  1404. ,tabChat: function(othis){
  1405. changeChat(othis);
  1406. }
  1407. //关闭聊天列表
  1408. ,closeChat: function(othis, e){
  1409. changeChat(othis.parent(), 1);
  1410. stope(e);
  1411. }, closeThisChat: function(){
  1412. changeChat(null, 1);
  1413. }
  1414. //展开群组成员
  1415. ,groupMembers: function(othis, e){
  1416. var icon = othis.find('.layui-icon'), hide = function(){
  1417. icon.html('&#xe61a;');
  1418. othis.data('down', null);
  1419. layer.close(events.groupMembers.index);
  1420. }, stopmp = function(e){stope(e)};
  1421. if(othis.data('down')){
  1422. hide();
  1423. } else {
  1424. icon.html('&#xe619;');
  1425. othis.data('down', true);
  1426. events.groupMembers.index = layer.tips('<ul class="layim-members-list"></ul>', othis, {
  1427. tips: 3
  1428. ,time: 0
  1429. ,anim: 5
  1430. ,fixed: true
  1431. ,skin: 'layui-box layui-layim-members'
  1432. ,success: function(layero){
  1433. var members = cache.base.members || {}, thatChat = thisChat()
  1434. ,ul = layero.find('.layim-members-list'), li = '', membersCache = {}
  1435. ,hasFull = layimChat.find('.layui-layer-max').hasClass('layui-layer-maxmin')
  1436. ,listNone = layimChat.find('.layim-chat-list').css('display') === 'none';
  1437. if(hasFull){
  1438. ul.css({
  1439. width: $(window).width() - 22 - (listNone || 200)
  1440. });
  1441. }
  1442. members.data = $.extend(members.data, {
  1443. id: thatChat.data.id
  1444. });
  1445. post(members, function(res){
  1446. layui.each(res.list, function(index, item){
  1447. li += '<li data-uid="'+ item.id +'"><a href="javascript:;"><img src="'+ item.avatar +'"><cite>'+ item.username +'</cite></a></li>';
  1448. membersCache[item.id] = item;
  1449. });
  1450. ul.html(li);
  1451. //获取群员
  1452. othis.find('.layim-chat-members').html(res.members||(res.list||[]).length + '人');
  1453. //私聊
  1454. ul.find('li').on('click', function(){
  1455. var uid = $(this).data('uid'), info = membersCache[uid]
  1456. popchat({
  1457. name: info.username
  1458. ,type: 'friend'
  1459. ,avatar: info.avatar
  1460. ,id: info.id
  1461. });
  1462. hide();
  1463. });
  1464. layui.each(call.members, function(index, item){
  1465. item && item(res);
  1466. });
  1467. });
  1468. layero.on('mousedown', function(e){
  1469. stope(e);
  1470. });
  1471. }
  1472. });
  1473. $(document).off('mousedown', hide).on('mousedown', hide);
  1474. $(window).off('resize', hide).on('resize', hide);
  1475. othis.off('mousedown', stopmp).on('mousedown', stopmp);
  1476. }
  1477. }
  1478. //发送聊天内容
  1479. ,send: function(){
  1480. sendMessage();
  1481. }
  1482. //设置发送聊天快捷键
  1483. ,setSend: function(othis, e){
  1484. var box = events.setSend.box = othis.siblings('.layim-menu-box')
  1485. ,type = othis.attr('lay-type');
  1486. if(type === 'show'){
  1487. stope(e);
  1488. box.show().addClass(anim);
  1489. $(document).off('click', events.setSendHide).on('click', events.setSendHide);
  1490. } else {
  1491. othis.addClass(THIS).siblings().removeClass(THIS);
  1492. var local = layui.data('layim')[cache.mine.id] || {};
  1493. local.sendHotKey = type;
  1494. layui.data('layim', {
  1495. key: cache.mine.id
  1496. ,value: local
  1497. });
  1498. events.setSendHide(e, othis.parent());
  1499. }
  1500. }, setSendHide: function(e, box){
  1501. (box || events.setSend.box).hide().removeClass(anim);
  1502. }
  1503. //表情
  1504. ,face: function(othis, e){
  1505. var content = '', thatChat = thisChat();
  1506. for(var key in faces){
  1507. content += '<li title="'+ key +'"><img src="'+ faces[key] +'"></li>';
  1508. }
  1509. content = '<ul class="layui-clear layim-face-list">'+ content +'</ul>';
  1510. events.face.index = layer.tips(content, othis, {
  1511. tips: 1
  1512. ,time: 0
  1513. ,fixed: true
  1514. ,skin: 'layui-box layui-layim-face'
  1515. ,success: function(layero){
  1516. layero.find('.layim-face-list>li').on('mousedown', function(e){
  1517. stope(e);
  1518. }).on('click', function(){
  1519. focusInsert(thatChat.textarea[0], 'face' + this.title + ' ');
  1520. layer.close(events.face.index);
  1521. });
  1522. }
  1523. });
  1524. $(document).off('mousedown', events.faceHide).on('mousedown', events.faceHide);
  1525. $(window).off('resize', events.faceHide).on('resize', events.faceHide);
  1526. stope(e);
  1527. } ,faceHide: function(){
  1528. layer.close(events.face.index);
  1529. }
  1530. //图片或一般文件
  1531. ,image: function(othis){
  1532. var type = othis.data('type') || 'images', api = {
  1533. images: 'uploadImage'
  1534. ,file: 'uploadFile'
  1535. }
  1536. ,thatChat = thisChat(), conf = cache.base[api[type]] || {};
  1537. layui.upload.render({
  1538. url: conf.url || ''
  1539. ,method: conf.type
  1540. ,elem: othis.find('input')[0]
  1541. ,accept: type
  1542. ,done: function(res){
  1543. if(res.code == 0){
  1544. res.data = res.data || {};
  1545. if(type === 'images'){
  1546. focusInsert(thatChat.textarea[0], 'img['+ (res.data.src||'') +']');
  1547. } else if(type === 'file'){
  1548. focusInsert(thatChat.textarea[0], 'file('+ (res.data.src||'') +')['+ (res.data.name||'下载文件') +']');
  1549. }
  1550. sendMessage();
  1551. } else {
  1552. layer.msg(res.msg||'上传失败');
  1553. }
  1554. }
  1555. });
  1556. }
  1557. //音频和视频
  1558. ,media: function(othis){
  1559. var type = othis.data('type'), text = {
  1560. audio: '音频'
  1561. ,video: '视频'
  1562. } ,thatChat = thisChat()
  1563. layer.prompt({
  1564. title: '请输入网络'+ text[type] + '地址'
  1565. ,shade: false
  1566. ,offset: [
  1567. othis.offset().top - $(window).scrollTop() - 158 + 'px'
  1568. ,othis.offset().left + 'px'
  1569. ]
  1570. }, function(src, index){
  1571. focusInsert(thatChat.textarea[0], type + '['+ src +']');
  1572. sendMessage();
  1573. layer.close(index);
  1574. });
  1575. }
  1576. //扩展工具栏
  1577. ,extend: function(othis){
  1578. var filter = othis.attr('lay-filter')
  1579. ,thatChat = thisChat();
  1580. layui.each(call['tool('+ filter +')'], function(index, item){
  1581. item && item.call(othis, function(content){
  1582. focusInsert(thatChat.textarea[0], content);
  1583. }, sendMessage, thatChat);
  1584. });
  1585. }
  1586. //播放音频
  1587. ,playAudio: function(othis){
  1588. var audioData = othis.data('audio')
  1589. ,audio = audioData || document.createElement('audio')
  1590. ,pause = function(){
  1591. audio.pause();
  1592. othis.removeAttr('status');
  1593. othis.find('i').html('&#xe652;');
  1594. };
  1595. if(othis.data('error')){
  1596. return layer.msg('播放音频源异常');
  1597. }
  1598. if(!audio.play){
  1599. return layer.msg('您的浏览器不支持audio');
  1600. }
  1601. if(othis.attr('status')){
  1602. pause();
  1603. } else {
  1604. audioData || (audio.src = othis.data('src'));
  1605. audio.play();
  1606. othis.attr('status', 'pause');
  1607. othis.data('audio', audio);
  1608. othis.find('i').html('&#xe651;');
  1609. //播放结束
  1610. audio.onended = function(){
  1611. pause();
  1612. };
  1613. //播放异常
  1614. audio.onerror = function(){
  1615. layer.msg('播放音频源异常');
  1616. othis.data('error', true);
  1617. pause();
  1618. };
  1619. }
  1620. }
  1621. //播放视频
  1622. ,playVideo: function(othis){
  1623. var videoData = othis.data('src')
  1624. ,video = document.createElement('video');
  1625. if(!video.play){
  1626. return layer.msg('您的浏览器不支持video');
  1627. }
  1628. layer.close(events.playVideo.index);
  1629. events.playVideo.index = layer.open({
  1630. type: 1
  1631. ,title: '播放视频'
  1632. ,area: ['460px', '300px']
  1633. ,maxmin: true
  1634. ,shade: false
  1635. ,content: '<div style="background-color: #000; height: 100%;"><video style="position: absolute; width: 100%; height: 100%;" src="'+ videoData +'" loop="loop" autoplay="autoplay"></video></div>'
  1636. });
  1637. }
  1638. //聊天记录
  1639. ,chatLog: function(othis){
  1640. var thatChat = thisChat();
  1641. if(!cache.base.chatLog){
  1642. return layer.msg('未开启更多聊天记录');
  1643. }
  1644. layer.close(events.chatLog.index);
  1645. return events.chatLog.index = layer.open({
  1646. type: 2
  1647. ,maxmin: true
  1648. ,title: '与 '+ thatChat.data.name +' 的聊天记录'
  1649. ,area: ['450px', '100%']
  1650. ,shade: false
  1651. ,offset: 'rb'
  1652. ,skin: 'layui-box'
  1653. ,anim: 2
  1654. ,id: 'layui-layim-chatlog'
  1655. ,content: cache.base.chatLog + '?id=' + thatChat.data.id + '&type=' + thatChat.data.type
  1656. });
  1657. }
  1658. //历史会话右键菜单操作
  1659. ,menuHistory: function(othis, e){
  1660. var local = layui.data('layim')[cache.mine.id] || {};
  1661. var parent = othis.parent(), type = othis.data('type');
  1662. var hisElem = layimMain.find('.layim-list-history');
  1663. var none = '<li class="layim-null">暂无历史会话</li>'
  1664. if(type === 'one'){
  1665. var history = local.history;
  1666. delete history[parent.data('index')];
  1667. local.history = history;
  1668. layui.data('layim', {
  1669. key: cache.mine.id
  1670. ,value: local
  1671. });
  1672. //删除 DOM
  1673. $('.layim-list-history li.layim-'+parent.data('index')).remove();
  1674. if(hisElem.find('li').length === 0){
  1675. hisElem.html(none);
  1676. }
  1677. } else if(type === 'all') {
  1678. delete local.history;
  1679. layui.data('layim', {
  1680. key: cache.mine.id
  1681. ,value: local
  1682. });
  1683. hisElem.html(none);
  1684. }
  1685. layer.closeAll('tips');
  1686. }
  1687. };
  1688. //暴露接口
  1689. exports('layim', new LAYIM());
  1690. }).addcss(
  1691. 'modules/layim/layim.css?v=3.9.1'
  1692. ,'skinlayimcss'
  1693. );