layim.js 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857
  1. /**
  2. @Name:layim v3.7.2 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.7.2 Pro';
  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">&#xe618;</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">&#xe618;</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">&#xe618;</i>按Enter键发送消息</li>'
  265. ,'<li {{d.local.sendHotKey === "Ctrl+Enter" ? "class=layim-this" : ""}} layim-event="setSend" lay-type="Ctrl+Enter"><i class="layui-icon">&#xe618;</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. ,auto:true
  575. ,maxmin: true
  576. ,offset: data.offset || 'auto'
  577. ,anim: data.anim || 0
  578. ,closeBtn: cache.base.brief ? false : 1
  579. ,content: laytpl('<ul class="layui-unselect layim-chat-list">'+ elemChatList +'</ul><div class="layim-chat-box">' + elemChatTpl + '</div>').render(render)
  580. ,success: function(layero){
  581. layimChat = layero;
  582. layero.css({
  583. 'min-width': '100px'
  584. ,'min-height': '120px'
  585. });
  586. syncGray(data);
  587. typeof data.success === 'function' && data.success(layero);
  588. hotkeySend();
  589. setSkin(layero);
  590. setHistory(data);
  591. viewChatlog();
  592. showOffMessage();
  593. //聊天窗口的切换监听
  594. layui.each(call.chatChange, function(index, item){
  595. item && item(thisChat());
  596. });
  597. //查看大图
  598. layero.on('dblclick', '.layui-layim-photos', function(){
  599. var src = this.src;
  600. layer.close(popchat.photosIndex);
  601. layer.photos({
  602. photos: {
  603. data: [{
  604. "alt": "大图模式",
  605. "src": src
  606. }]
  607. }
  608. ,shade: 0.01
  609. ,closeBtn: 2
  610. ,anim: 0
  611. ,resize: false
  612. ,success: function(layero, index){
  613. popchat.photosIndex = index;
  614. }
  615. });
  616. });
  617. }
  618. ,full: function(layero){
  619. layer.style(index, {
  620. width: '100%'
  621. ,height: '100%'
  622. }, true);
  623. resizeChat();
  624. }
  625. ,resizing: resizeChat
  626. ,restore: resizeChat
  627. ,min: function(){
  628. setChatMin();
  629. return false;
  630. }
  631. ,end: function(){
  632. layer.closeAll('tips');
  633. layimChat = null;
  634. }
  635. });
  636. return index;
  637. };
  638. //同步置灰状态
  639. var syncGray = function(data){
  640. $('.layim-'+data.type+data.id).each(function(){
  641. if($(this).hasClass('layim-list-gray')){
  642. layui.layim.setFriendStatus(data.id, 'offline');
  643. }
  644. });
  645. };
  646. //重置聊天窗口大小
  647. var resizeChat = function(){
  648. var list = layimChat.find('.layim-chat-list')
  649. ,chatMain = layimChat.find('.layim-chat-main')
  650. ,chatHeight = layimChat.height();
  651. list.css({
  652. height: chatHeight
  653. });
  654. chatMain.css({
  655. height: chatHeight - 20 - 80 - 158
  656. })
  657. };
  658. //设置聊天窗口最小化 & 新消息提醒
  659. var setChatMin = function(newMsg){
  660. var thatChat = newMsg || thisChat().data, base = layui.layim.cache().base;
  661. if(layimChat && !newMsg){
  662. layimChat.hide();
  663. }
  664. layer.close(setChatMin.index);
  665. setChatMin.index = layer.open({
  666. type: 1
  667. ,title: false
  668. ,skin: 'layui-box layui-layim-min'
  669. ,shade: false
  670. ,closeBtn: false
  671. ,anim: thatChat.anim || 2
  672. ,offset: 'b'
  673. ,move: '#layui-layim-min'
  674. ,resize: false
  675. ,area: ['182px', '50px']
  676. ,content: '<img id="layui-layim-min" src="'+ thatChat.avatar +'"><span>'+ thatChat.name +'</span>'
  677. ,success: function(layero, index){
  678. if(!newMsg) layimMin = layero;
  679. if(base.minRight){
  680. layer.style(index, {
  681. left: $(window).width() - layero.outerWidth() - parseFloat(base.minRight)
  682. });
  683. }
  684. layero.find('.layui-layer-content span').on('click', function(){
  685. layer.close(index);
  686. newMsg ? layui.each(cache.chat, function(i, item){
  687. popchat(item);
  688. }) : layimChat.show();
  689. if(newMsg){
  690. cache.chat = [];
  691. chatListMore();
  692. }
  693. });
  694. layero.find('.layui-layer-content img').on('click', function(e){
  695. stope(e);
  696. });
  697. }
  698. });
  699. };
  700. //打开添加好友、群组面板、好友分组面板
  701. var popAdd = function(data, type){
  702. data = data || {};
  703. layer.close(popAdd.index);
  704. return popAdd.index = layer.open({
  705. type: 1
  706. ,area: '430px'
  707. ,title: {
  708. friend: '添加好友'
  709. ,group: '加入群组'
  710. }[data.type] || ''
  711. ,shade: false
  712. ,resize: false
  713. ,btn: type ? ['确认', '取消'] : ['发送申请', '关闭']
  714. ,content: laytpl(elemAddTpl).render({
  715. data: {
  716. name: data.username || data.groupname
  717. ,avatar: data.avatar
  718. ,group: data.group || parent.layui.layim.cache().friend || []
  719. ,type: data.type
  720. }
  721. ,type: type
  722. })
  723. ,yes: function(index, layero){
  724. var groupElem = layero.find('#LAY_layimGroup')
  725. ,remarkElem = layero.find('#LAY_layimRemark')
  726. if(type){
  727. data.submit && data.submit(groupElem.val(), index);
  728. } else {
  729. data.submit && data.submit(groupElem.val(), remarkElem.val(), index);
  730. }
  731. }
  732. });
  733. };
  734. //切换聊天
  735. var changeChat = function(elem, del){
  736. elem = elem || $('.layim-chat-list .' + THIS);
  737. var index = elem.index() === -1 ? 0 : elem.index();
  738. var str = '.layim-chat', cont = layimChat.find(str).eq(index);
  739. var hasFull = layimChat.find('.layui-layer-max').hasClass('layui-layer-maxmin');
  740. if(del){
  741. //如果关闭的是当前聊天,则切换聊天焦点
  742. if(elem.hasClass(THIS)){
  743. changeChat(index === 0 ? elem.next() : elem.prev());
  744. }
  745. var length = layimChat.find(str).length;
  746. //关闭聊天界面
  747. if(length === 1){
  748. return layer.close(chatIndex);
  749. }
  750. elem.remove();
  751. cont.remove();
  752. //只剩下1个列表,隐藏左侧区块
  753. if(length === 2){
  754. layimChat.find('.layim-chat-list').hide();
  755. if(!hasFull){
  756. layimChat.css('width', '600px');
  757. }
  758. layimChat.find('.layim-chat-box').css('margin-left', 0);
  759. }
  760. return false;
  761. }
  762. elem.addClass(THIS).siblings().removeClass(THIS);
  763. cont.addClass(SHOW).siblings(str).removeClass(SHOW);
  764. cont.find('textarea').focus();
  765. //聊天窗口的切换监听
  766. layui.each(call.chatChange, function(index, item){
  767. item && item(thisChat());
  768. });
  769. showOffMessage();
  770. };
  771. //展示存在队列中的消息
  772. var showOffMessage = function(){
  773. var thatChat = thisChat();
  774. var message = cache.message[thatChat.data.type + thatChat.data.id];
  775. if(message){
  776. //展现后,删除队列中消息
  777. delete cache.message[thatChat.data.type + thatChat.data.id];
  778. }
  779. };
  780. //获取当前聊天面板
  781. var thisChat = function(){
  782. if(!layimChat) return;
  783. var index = $('.layim-chat-list .' + THIS).index();
  784. var cont = layimChat.find('.layim-chat').eq(index);
  785. var to = JSON.parse(decodeURIComponent(cont.find('.layim-chat-tool').data('json')));
  786. return {
  787. elem: cont
  788. ,data: to
  789. ,textarea: cont.find('textarea')
  790. };
  791. };
  792. //记录初始背景
  793. var setSkin = function(layero){
  794. var local = layui.data('layim')[cache.mine.id] || {}
  795. ,skin = local.skin;
  796. layero.css({
  797. 'background-image': skin ? 'url('+ skin +')' : function(){
  798. return cache.base.initSkin
  799. ? 'url('+ (layui.cache.dir+'css/modules/layim/skin/'+ cache.base.initSkin) +')'
  800. : 'none';
  801. }()
  802. });
  803. };
  804. //记录历史会话
  805. var setHistory = function(data){
  806. var local = layui.data('layim')[cache.mine.id] || {};
  807. var obj = {}, history = local.history || {};
  808. var is = history[data.type + data.id];
  809. if(!layimMain) return;
  810. var historyElem = layimMain.find('.layim-list-history');
  811. data.historyTime = new Date().getTime();
  812. history[data.type + data.id] = data;
  813. local.history = history;
  814. layui.data('layim', {
  815. key: cache.mine.id
  816. ,value: local
  817. });
  818. if(is) return;
  819. obj[data.type + data.id] = data;
  820. var historyList = laytpl(listTpl({
  821. type: 'history'
  822. ,item: 'd.data'
  823. })).render({data: obj});
  824. historyElem.prepend(historyList);
  825. historyElem.find('.layim-null').remove();
  826. };
  827. //发送消息
  828. var sendMessage = function(){
  829. var data = {
  830. username: cache.mine ? cache.mine.username : '访客'
  831. ,avatar: cache.mine ? cache.mine.avatar : (layui.cache.dir+'css/pc/layim/skin/logo.jpg')
  832. ,id: cache.mine ? cache.mine.id : null
  833. ,mine: true
  834. };
  835. var thatChat = thisChat(), ul = thatChat.elem.find('.layim-chat-main ul');
  836. var maxLength = cache.base.maxLength || 3000;
  837. data.content = thatChat.textarea.val();
  838. if(data.content.replace(/\s/g, '') !== ''){
  839. if(data.content.length > maxLength){
  840. return layer.msg('内容最长不能超过'+ maxLength +'个字符')
  841. }
  842. ul.append(laytpl(elemChatMain).render(data));
  843. var param = {
  844. mine: data
  845. ,to: thatChat.data
  846. }, message = {
  847. username: param.mine.username
  848. ,avatar: param.mine.avatar
  849. ,id: param.to.id
  850. ,type: param.to.type
  851. ,content: param.mine.content
  852. ,timestamp: new Date().getTime()
  853. ,mine: true
  854. };
  855. pushChatlog(message);
  856. layui.each(call.sendMessage, function(index, item){
  857. item && item(param);
  858. });
  859. }
  860. chatListMore();
  861. thatChat.textarea.val('').focus();
  862. };
  863. //桌面消息提醒
  864. var notice = function(data){
  865. data = data || {};
  866. if (window.Notification){
  867. if(Notification.permission === 'granted'){
  868. var notification = new Notification(data.title||'', {
  869. body: data.content||''
  870. ,icon: data.avatar||'http://tp2.sinaimg.cn/5488749285/50/5719808192/1'
  871. });
  872. }else {
  873. Notification.requestPermission();
  874. };
  875. }
  876. };
  877. //消息声音提醒
  878. var voice = function() {
  879. if(device.ie && device.ie < 9) return;
  880. var audio = document.createElement("audio");
  881. audio.src = layui.cache.dir+'css/modules/layim/voice/'+ cache.base.voice;
  882. audio.play();
  883. };
  884. //接受消息
  885. var messageNew = {}, getMessage = function(data){
  886. data = data || {};
  887. var elem = $('.layim-chatlist-'+ data.type + data.id);
  888. var group = {}, index = elem.index();
  889. data.timestamp = data.timestamp || new Date().getTime();
  890. if(data.fromid == cache.mine.id){
  891. data.mine = true;
  892. }
  893. data.system || pushChatlog(data);
  894. messageNew = JSON.parse(JSON.stringify(data));
  895. if(cache.base.voice){
  896. voice();
  897. }
  898. if((!layimChat && data.content) || index === -1){
  899. if(cache.message[data.type + data.id]){
  900. cache.message[data.type + data.id].push(data)
  901. } else {
  902. cache.message[data.type + data.id] = [data];
  903. //记录聊天面板队列
  904. if(data.type === 'friend'){
  905. var friend;
  906. layui.each(cache.friend, function(index1, item1){
  907. layui.each(item1.list, function(index, item){
  908. if(item.id == data.id){
  909. item.type = 'friend';
  910. item.name = item.username;
  911. cache.chat.push(item);
  912. return friend = true;
  913. }
  914. });
  915. if(friend) return true;
  916. });
  917. if(!friend){
  918. data.name = data.username;
  919. data.temporary = true; //临时会话
  920. cache.chat.push(data);
  921. }
  922. } else if(data.type === 'group'){
  923. var isgroup;
  924. layui.each(cache.group, function(index, item){
  925. if(item.id == data.id){
  926. item.type = 'group';
  927. item.name = item.groupname;
  928. cache.chat.push(item);
  929. return isgroup = true;
  930. }
  931. });
  932. if(!isgroup){
  933. data.name = data.groupname;
  934. cache.chat.push(data);
  935. }
  936. } else {
  937. data.name = data.name || data.username || data.groupname;
  938. cache.chat.push(data);
  939. }
  940. }
  941. if(data.type === 'group'){
  942. layui.each(cache.group, function(index, item){
  943. if(item.id == data.id){
  944. group.avatar = item.avatar;
  945. return true;
  946. }
  947. });
  948. }
  949. if(!data.system){
  950. if(cache.base.notice){
  951. notice({
  952. title: '来自 '+ data.username +' 的消息'
  953. ,content: data.content
  954. ,avatar: group.avatar || data.avatar
  955. });
  956. }
  957. return setChatMin({
  958. name: '收到新消息'
  959. ,avatar: group.avatar || data.avatar
  960. ,anim: 6
  961. });
  962. }
  963. }
  964. if(!layimChat) return;
  965. //接受到的消息不在当前Tab
  966. var thatChat = thisChat();
  967. if(thatChat.data.type + thatChat.data.id !== data.type + data.id){
  968. elem.addClass('layui-anim layer-anim-06');
  969. setTimeout(function(){
  970. elem.removeClass('layui-anim layer-anim-06')
  971. }, 300);
  972. }
  973. var cont = layimChat.find('.layim-chat').eq(index);
  974. var ul = cont.find('.layim-chat-main ul');
  975. //系统消息
  976. if(data.system){
  977. if(index !== -1){
  978. ul.append('<li class="layim-chat-system"><span>'+ data.content +'</span></li>');
  979. }
  980. } else if(data.content.replace(/\s/g, '') !== ''){
  981. ul.append(laytpl(elemChatMain).render(data));
  982. }
  983. chatListMore();
  984. };
  985. //消息盒子的提醒
  986. var ANIM_MSG = 'layui-anim-loop layer-anim-05', msgbox = function(num){
  987. var msgboxElem = layimMain.find('.layim-tool-msgbox');
  988. msgboxElem.find('span').addClass(ANIM_MSG).html(num);
  989. };
  990. //存储最近MAX_ITEM条聊天记录到本地
  991. var pushChatlog = function(message){
  992. var local = layui.data('layim')[cache.mine.id] || {};
  993. local.chatlog = local.chatlog || {};
  994. var thisChatlog = local.chatlog[message.type + message.id];
  995. if(thisChatlog){
  996. //避免浏览器多窗口时聊天记录重复保存
  997. var nosame;
  998. layui.each(thisChatlog, function(index, item){
  999. if((item.timestamp === message.timestamp
  1000. && item.type === message.type
  1001. && item.id === message.id
  1002. && item.content === message.content)){
  1003. nosame = true;
  1004. }
  1005. });
  1006. if(!(nosame || message.fromid == cache.mine.id)){
  1007. thisChatlog.push(message);
  1008. }
  1009. if(thisChatlog.length > MAX_ITEM){
  1010. thisChatlog.shift();
  1011. }
  1012. } else {
  1013. local.chatlog[message.type + message.id] = [message];
  1014. }
  1015. layui.data('layim', {
  1016. key: cache.mine.id
  1017. ,value: local
  1018. });
  1019. };
  1020. //渲染本地最新聊天记录到相应面板
  1021. var viewChatlog = function(){
  1022. var local = layui.data('layim')[cache.mine.id] || {}
  1023. ,thatChat = thisChat(), chatlog = local.chatlog || {}
  1024. ,ul = thatChat.elem.find('.layim-chat-main ul');
  1025. layui.each(chatlog[thatChat.data.type + thatChat.data.id], function(index, item){
  1026. ul.append(laytpl(elemChatMain).render(item));
  1027. });
  1028. chatListMore();
  1029. };
  1030. //添加好友或群
  1031. var addList = function(data){
  1032. var obj = {}, has, listElem = layimMain.find('.layim-list-'+ data.type);
  1033. if(cache[data.type]){
  1034. if(data.type === 'friend'){
  1035. layui.each(cache.friend, function(index, item){
  1036. if(data.groupid == item.id){
  1037. //检查好友是否已经在列表中
  1038. layui.each(cache.friend[index].list, function(idx, itm){
  1039. if(itm.id == data.id){
  1040. return has = true
  1041. }
  1042. });
  1043. if(has) return layer.msg('好友 ['+ (data.username||'') +'] 已经存在列表中',{anim: 6});
  1044. cache.friend[index].list = cache.friend[index].list || [];
  1045. obj[cache.friend[index].list.length] = data;
  1046. data.groupIndex = index;
  1047. cache.friend[index].list.push(data); //在cache的friend里面也增加好友
  1048. return true;
  1049. }
  1050. });
  1051. } else if(data.type === 'group'){
  1052. //检查群组是否已经在列表中
  1053. layui.each(cache.group, function(idx, itm){
  1054. if(itm.id == data.id){
  1055. return has = true
  1056. }
  1057. });
  1058. if(has) return layer.msg('您已是 ['+ (data.groupname||'') +'] 的群成员',{anim: 6});
  1059. obj[cache.group.length] = data;
  1060. cache.group.push(data);
  1061. }
  1062. }
  1063. if(has) return;
  1064. var list = laytpl(listTpl({
  1065. type: data.type
  1066. ,item: 'd.data'
  1067. ,index: data.type === 'friend' ? 'data.groupIndex' : null
  1068. })).render({data: obj});
  1069. if(data.type === 'friend'){
  1070. var li = listElem.find('>li').eq(data.groupIndex);
  1071. li.find('.layui-layim-list').append(list);
  1072. li.find('.layim-count').html(cache.friend[data.groupIndex].list.length); //刷新好友数量
  1073. //如果初始没有好友
  1074. if(li.find('.layim-null')[0]){
  1075. li.find('.layim-null').remove();
  1076. }
  1077. } else if(data.type === 'group'){
  1078. listElem.append(list);
  1079. //如果初始没有群组
  1080. if(listElem.find('.layim-null')[0]){
  1081. listElem.find('.layim-null').remove();
  1082. }
  1083. }
  1084. };
  1085. //移出好友或群
  1086. var removeList = function(data){
  1087. var listElem = layimMain.find('.layim-list-'+ data.type);
  1088. var obj = {};
  1089. if(cache[data.type]){
  1090. if(data.type === 'friend'){
  1091. layui.each(cache.friend, function(index1, item1){
  1092. layui.each(item1.list, function(index, item){
  1093. if(data.id == item.id){
  1094. var li = listElem.find('>li').eq(index1);
  1095. var list = li.find('.layui-layim-list>li');
  1096. li.find('.layui-layim-list>li').eq(index).remove();
  1097. cache.friend[index1].list.splice(index, 1); //从cache的friend里面也删除掉好友
  1098. li.find('.layim-count').html(cache.friend[index1].list.length); //刷新好友数量
  1099. //如果一个好友都没了
  1100. if(cache.friend[index1].list.length === 0){
  1101. li.find('.layui-layim-list').html('<li class="layim-null">该分组下已无好友了</li>');
  1102. }
  1103. return true;
  1104. }
  1105. });
  1106. });
  1107. } else if(data.type === 'group'){
  1108. layui.each(cache.group, function(index, item){
  1109. if(data.id == item.id){
  1110. listElem.find('>li').eq(index).remove();
  1111. cache.group.splice(index, 1); //从cache的group里面也删除掉数据
  1112. //如果一个群组都没了
  1113. if(cache.group.length === 0){
  1114. listElem.html('<li class="layim-null">暂无群组</li>');
  1115. }
  1116. return true;
  1117. }
  1118. });
  1119. }
  1120. }
  1121. };
  1122. //查看更多记录
  1123. var chatListMore = function(){
  1124. var thatChat = thisChat(), chatMain = thatChat.elem.find('.layim-chat-main');
  1125. var ul = chatMain.find('ul');
  1126. var length = ul.find('li').length;
  1127. if(length >= MAX_ITEM){
  1128. var first = ul.find('li').eq(0);
  1129. if(!ul.prev().hasClass('layim-chat-system')){
  1130. ul.before('<div class="layim-chat-system"><span layim-event="chatLog">查看更多记录</span></div>');
  1131. }
  1132. if(length > MAX_ITEM){
  1133. first.remove();
  1134. }
  1135. }
  1136. chatMain.scrollTop(chatMain[0].scrollHeight + 1000);
  1137. chatMain.find('ul li:last').find('img').load(function(){
  1138. chatMain.scrollTop(chatMain[0].scrollHeight+1000);
  1139. });
  1140. };
  1141. //快捷键发送
  1142. var hotkeySend = function(){
  1143. var thatChat = thisChat(), textarea = thatChat.textarea;
  1144. textarea.focus();
  1145. textarea.off('keydown').on('keydown', function(e){
  1146. var local = layui.data('layim')[cache.mine.id] || {};
  1147. var keyCode = e.keyCode;
  1148. if(local.sendHotKey === 'Ctrl+Enter'){
  1149. if(e.ctrlKey && keyCode === 13){
  1150. sendMessage();
  1151. }
  1152. return;
  1153. }
  1154. if(keyCode === 13){
  1155. if(e.ctrlKey){
  1156. return textarea.val(textarea.val()+'\n');
  1157. }
  1158. if(e.shiftKey) return;
  1159. e.preventDefault();
  1160. sendMessage();
  1161. }
  1162. });
  1163. };
  1164. //表情库
  1165. var faces = function(){
  1166. var alt = ["[微笑]", "[嘻嘻]", "[哈哈]", "[可爱]", "[可怜]", "[挖鼻]", "[吃惊]", "[害羞]", "[挤眼]", "[闭嘴]", "[鄙视]", "[爱你]", "[泪]", "[偷笑]", "[亲亲]", "[生病]", "[太开心]", "[白眼]", "[右哼哼]", "[左哼哼]", "[嘘]", "[衰]", "[委屈]", "[吐]", "[哈欠]", "[抱抱]", "[怒]", "[疑问]", "[馋嘴]", "[拜拜]", "[思考]", "[汗]", "[困]", "[睡]", "[钱]", "[失望]", "[酷]", "[色]", "[哼]", "[鼓掌]", "[晕]", "[悲伤]", "[抓狂]", "[黑线]", "[阴险]", "[怒骂]", "[互粉]", "[心]", "[伤心]", "[猪头]", "[熊猫]", "[兔子]", "[ok]", "[耶]", "[good]", "[NO]", "[赞]", "[来]", "[弱]", "[草泥马]", "[神马]", "[囧]", "[浮云]", "[给力]", "[围观]", "[威武]", "[奥特曼]", "[礼物]", "[钟]", "[话筒]", "[蜡烛]", "[蛋糕]"], arr = {};
  1167. layui.each(alt, function(index, item){
  1168. arr[item] = layui.cache.dir + 'images/face/'+ index + '.gif';
  1169. });
  1170. return arr;
  1171. }();
  1172. var stope = layui.stope; //组件事件冒泡
  1173. //在焦点处插入内容
  1174. var focusInsert = function(obj, str){
  1175. var result, val = obj.value;
  1176. obj.focus();
  1177. if(document.selection){ //ie
  1178. result = document.selection.createRange();
  1179. document.selection.empty();
  1180. result.text = str;
  1181. } else {
  1182. result = [val.substring(0, obj.selectionStart), str, val.substr(obj.selectionEnd)];
  1183. obj.focus();
  1184. obj.value = result.join('');
  1185. }
  1186. };
  1187. //事件
  1188. var anim = 'layui-anim-upbit', events = {
  1189. //在线状态
  1190. status: function(othis, e){
  1191. var hide = function(){
  1192. othis.next().hide().removeClass(anim);
  1193. };
  1194. var type = othis.attr('lay-type');
  1195. if(type === 'show'){
  1196. stope(e);
  1197. othis.next().show().addClass(anim);
  1198. $(document).off('click', hide).on('click', hide);
  1199. } else {
  1200. var prev = othis.parent().prev();
  1201. othis.addClass(THIS).siblings().removeClass(THIS);
  1202. prev.html(othis.find('cite').html());
  1203. prev.removeClass('layim-status-'+(type === 'online' ? 'hide' : 'online'))
  1204. .addClass('layim-status-'+type);
  1205. layui.each(call.online, function(index, item){
  1206. item && item(type);
  1207. });
  1208. }
  1209. }
  1210. //编辑签名
  1211. ,sign: function(){
  1212. var input = layimMain.find('.layui-layim-remark');
  1213. input.on('change', function(){
  1214. var value = this.value;
  1215. layui.each(call.sign, function(index, item){
  1216. item && item(value);
  1217. });
  1218. });
  1219. input.on('keyup', function(e){
  1220. var keyCode = e.keyCode;
  1221. if(keyCode === 13){
  1222. this.blur();
  1223. }
  1224. });
  1225. }
  1226. //大分组切换
  1227. ,tab: function(othis){
  1228. var index, main = '.layim-tab-content';
  1229. var tabs = layimMain.find('.layui-layim-tab>li');
  1230. typeof othis === 'number' ? (
  1231. index = othis
  1232. ,othis = tabs.eq(index)
  1233. ) : (
  1234. index = othis.index()
  1235. );
  1236. index > 2 ? tabs.removeClass(THIS) : (
  1237. events.tab.index = index
  1238. ,othis.addClass(THIS).siblings().removeClass(THIS)
  1239. )
  1240. layimMain.find(main).eq(index).addClass(SHOW).siblings(main).removeClass(SHOW);
  1241. }
  1242. //展开联系人分组
  1243. ,spread: function(othis){
  1244. var type = othis.attr('lay-type');
  1245. var spread = type === 'true' ? 'false' : 'true';
  1246. var local = layui.data('layim')[cache.mine.id] || {};
  1247. othis.next()[type === 'true' ? 'removeClass' : 'addClass'](SHOW);
  1248. local['spread' + othis.parent().index()] = spread;
  1249. layui.data('layim', {
  1250. key: cache.mine.id
  1251. ,value: local
  1252. });
  1253. othis.attr('lay-type', spread);
  1254. othis.find('.layui-icon').html(spread === 'true' ? '&#xe61a;' : '&#xe602;');
  1255. }
  1256. //搜索
  1257. ,search: function(othis){
  1258. var search = layimMain.find('.layui-layim-search');
  1259. var main = layimMain.find('#layui-layim-search');
  1260. var input = search.find('input'), find = function(e){
  1261. var val = input.val().replace(/\s/);
  1262. if(val === ''){
  1263. events.tab(events.tab.index|0);
  1264. } else {
  1265. var data = [], friend = cache.friend || [];
  1266. var group = cache.group || [], html = '';
  1267. for(var i = 0; i < friend.length; i++){
  1268. for(var k = 0; k < (friend[i].list||[]).length; k++){
  1269. if(friend[i].list[k].username.indexOf(val) !== -1){
  1270. friend[i].list[k].type = 'friend';
  1271. friend[i].list[k].index = i;
  1272. friend[i].list[k].list = k;
  1273. data.push(friend[i].list[k]);
  1274. }
  1275. }
  1276. }
  1277. for(var j = 0; j < group.length; j++){
  1278. if(group[j].groupname.indexOf(val) !== -1){
  1279. group[j].type = 'group';
  1280. group[j].index = j;
  1281. group[j].list = j;
  1282. data.push(group[j]);
  1283. }
  1284. }
  1285. if(data.length > 0){
  1286. for(var l = 0; l < data.length; l++){
  1287. 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>';
  1288. }
  1289. } else {
  1290. html = '<li class="layim-null">无搜索结果</li>';
  1291. }
  1292. main.html(html);
  1293. events.tab(3);
  1294. }
  1295. };
  1296. if(!cache.base.isfriend && cache.base.isgroup){
  1297. events.tab.index = 1;
  1298. } else if(!cache.base.isfriend && !cache.base.isgroup){
  1299. events.tab.index = 2;
  1300. }
  1301. search.show();
  1302. input.focus();
  1303. input.off('keyup', find).on('keyup', find);
  1304. }
  1305. //关闭搜索
  1306. ,closeSearch: function(othis){
  1307. othis.parent().hide();
  1308. events.tab(events.tab.index|0);
  1309. }
  1310. //消息盒子
  1311. ,msgbox: function(){
  1312. var msgboxElem = layimMain.find('.layim-tool-msgbox');
  1313. layer.close(events.msgbox.index);
  1314. msgboxElem.find('span').removeClass(ANIM_MSG).html('');
  1315. return events.msgbox.index = layer.open({
  1316. type: 2
  1317. ,title: '消息盒子'
  1318. ,shade: false
  1319. ,maxmin: true
  1320. ,area: ['600px', '520px']
  1321. ,skin: 'layui-box layui-layer-border'
  1322. ,resize: false
  1323. ,content: cache.base.msgbox
  1324. });
  1325. }
  1326. //弹出查找页面
  1327. ,find: function(){
  1328. layer.close(events.find.index);
  1329. return events.find.index = jp.openViewDialog("管理界面",cache.base.find,"800px", "500px");
  1330. }
  1331. //弹出更换背景
  1332. ,skin: function(){
  1333. layer.open({
  1334. type: 1
  1335. ,title: '更换背景'
  1336. ,shade: false
  1337. ,area: '300px'
  1338. ,skin: 'layui-box layui-layer-border'
  1339. ,id: 'layui-layim-skin'
  1340. ,zIndex: 66666666
  1341. ,resize: false
  1342. ,content: laytpl(elemSkinTpl).render({
  1343. skin: cache.base.skin
  1344. })
  1345. });
  1346. }
  1347. //关于
  1348. ,about: function(){
  1349. layer.alert('版本: '+ v + '<br>版权所有:<a href="http://layim.layui.com" target="_blank">layim.layui.com</a>', {
  1350. title: '关于 LayIM'
  1351. ,shade: false
  1352. });
  1353. }
  1354. //生成换肤
  1355. ,setSkin: function(othis){
  1356. var src = othis.attr('src');
  1357. var local = layui.data('layim')[cache.mine.id] || {};
  1358. local.skin = src;
  1359. if(!src) delete local.skin;
  1360. layui.data('layim', {
  1361. key: cache.mine.id
  1362. ,value: local
  1363. });
  1364. try{
  1365. layimMain.css({
  1366. 'background-image': src ? 'url('+ src +')' : 'none'
  1367. });
  1368. layimChat.css({
  1369. 'background-image': src ? 'url('+ src +')' : 'none'
  1370. });
  1371. } catch(e) {}
  1372. layui.each(call.setSkin, function(index, item){
  1373. var filename = (src||'').replace(layui.cache.dir+'css/modules/layim/skin/', '');
  1374. item && item(filename, src);
  1375. });
  1376. }
  1377. //弹出聊天面板
  1378. ,chat: function(othis){
  1379. var local = layui.data('layim')[cache.mine.id] || {};
  1380. var type = othis.data('type'), index = othis.data('index');
  1381. var list = othis.attr('data-list') || othis.index(), data = {};
  1382. if(type === 'friend'){
  1383. data = cache[type][index].list[list];
  1384. } else if(type === 'group'){
  1385. data = cache[type][list];
  1386. } else if(type === 'history'){
  1387. data = (local.history || {})[index] || {};
  1388. }
  1389. data.name = data.name || data.username || data.groupname;
  1390. if(type !== 'history'){
  1391. data.type = type;
  1392. }
  1393. popchat(data);
  1394. }
  1395. //切换聊天
  1396. ,tabChat: function(othis){
  1397. changeChat(othis);
  1398. }
  1399. //关闭聊天列表
  1400. ,closeChat: function(othis, e){
  1401. changeChat(othis.parent(), 1);
  1402. stope(e);
  1403. }, closeThisChat: function(){
  1404. changeChat(null, 1);
  1405. }
  1406. //展开群组成员
  1407. ,groupMembers: function(othis, e){
  1408. var icon = othis.find('.layui-icon'), hide = function(){
  1409. icon.html('&#xe61a;');
  1410. othis.data('down', null);
  1411. layer.close(events.groupMembers.index);
  1412. }, stopmp = function(e){stope(e)};
  1413. if(othis.data('down')){
  1414. hide();
  1415. } else {
  1416. icon.html('&#xe619;');
  1417. othis.data('down', true);
  1418. events.groupMembers.index = layer.tips('<ul class="layim-members-list"></ul>', othis, {
  1419. tips: 3
  1420. ,time: 0
  1421. ,anim: 5
  1422. ,fixed: true
  1423. ,skin: 'layui-box layui-layim-members'
  1424. ,success: function(layero){
  1425. var members = cache.base.members || {}, thatChat = thisChat()
  1426. ,ul = layero.find('.layim-members-list'), li = '', membersCache = {}
  1427. ,hasFull = layimChat.find('.layui-layer-max').hasClass('layui-layer-maxmin')
  1428. ,listNone = layimChat.find('.layim-chat-list').css('display') === 'none';
  1429. if(hasFull){
  1430. ul.css({
  1431. width: $(window).width() - 22 - (listNone || 200)
  1432. });
  1433. }
  1434. members.data = $.extend(members.data, {
  1435. id: thatChat.data.id
  1436. });
  1437. post(members, function(res){
  1438. layui.each(res.list, function(index, item){
  1439. li += '<li data-uid="'+ item.id +'"><a href="javascript:;"><img src="'+ item.avatar +'"><cite>'+ item.username +'</cite></a></li>';
  1440. membersCache[item.id] = item;
  1441. });
  1442. ul.html(li);
  1443. //获取群员
  1444. othis.find('.layim-chat-members').html(res.members||(res.list||[]).length + '人');
  1445. //私聊
  1446. ul.find('li').on('click', function(){
  1447. var uid = $(this).data('uid'), info = membersCache[uid]
  1448. popchat({
  1449. name: info.username
  1450. ,type: 'friend'
  1451. ,avatar: info.avatar
  1452. ,id: info.id
  1453. });
  1454. hide();
  1455. });
  1456. layui.each(call.members, function(index, item){
  1457. item && item(res);
  1458. });
  1459. });
  1460. layero.on('mousedown', function(e){
  1461. stope(e);
  1462. });
  1463. }
  1464. });
  1465. $(document).off('mousedown', hide).on('mousedown', hide);
  1466. $(window).off('resize', hide).on('resize', hide);
  1467. othis.off('mousedown', stopmp).on('mousedown', stopmp);
  1468. }
  1469. }
  1470. //发送聊天内容
  1471. ,send: function(){
  1472. sendMessage();
  1473. }
  1474. //设置发送聊天快捷键
  1475. ,setSend: function(othis, e){
  1476. var box = events.setSend.box = othis.siblings('.layim-menu-box')
  1477. ,type = othis.attr('lay-type');
  1478. if(type === 'show'){
  1479. stope(e);
  1480. box.show().addClass(anim);
  1481. $(document).off('click', events.setSendHide).on('click', events.setSendHide);
  1482. } else {
  1483. othis.addClass(THIS).siblings().removeClass(THIS);
  1484. var local = layui.data('layim')[cache.mine.id] || {};
  1485. local.sendHotKey = type;
  1486. layui.data('layim', {
  1487. key: cache.mine.id
  1488. ,value: local
  1489. });
  1490. events.setSendHide(e, othis.parent());
  1491. }
  1492. }, setSendHide: function(e, box){
  1493. (box || events.setSend.box).hide().removeClass(anim);
  1494. }
  1495. //表情
  1496. ,face: function(othis, e){
  1497. var content = '', thatChat = thisChat();
  1498. for(var key in faces){
  1499. content += '<li title="'+ key +'"><img src="'+ faces[key] +'"></li>';
  1500. }
  1501. content = '<ul class="layui-clear layim-face-list">'+ content +'</ul>';
  1502. events.face.index = layer.tips(content, othis, {
  1503. tips: 1
  1504. ,time: 0
  1505. ,fixed: true
  1506. ,skin: 'layui-box layui-layim-face'
  1507. ,success: function(layero){
  1508. layero.find('.layim-face-list>li').on('mousedown', function(e){
  1509. stope(e);
  1510. }).on('click', function(){
  1511. focusInsert(thatChat.textarea[0], 'face' + this.title + ' ');
  1512. layer.close(events.face.index);
  1513. });
  1514. }
  1515. });
  1516. $(document).off('mousedown', events.faceHide).on('mousedown', events.faceHide);
  1517. $(window).off('resize', events.faceHide).on('resize', events.faceHide);
  1518. stope(e);
  1519. } ,faceHide: function(){
  1520. layer.close(events.face.index);
  1521. }
  1522. //图片或一般文件
  1523. ,image: function(othis){
  1524. var type = othis.data('type') || 'images', api = {
  1525. images: 'uploadImage'
  1526. ,file: 'uploadFile'
  1527. }
  1528. ,thatChat = thisChat(), upload = cache.base[api[type]] || {};
  1529. layui.upload.render({
  1530. url: upload.url || ''
  1531. ,method: upload.type
  1532. ,elem: othis.find('input')[0]
  1533. ,accept: type
  1534. ,done: function(res){
  1535. if(res.code == 0){
  1536. res.data = res.data || {};
  1537. if(type === 'images'){
  1538. focusInsert(thatChat.textarea[0], 'img['+ (res.data.src||'') +']');
  1539. } else if(type === 'file'){
  1540. focusInsert(thatChat.textarea[0], 'file('+ (res.data.src||'') +')['+ (res.data.name||'下载文件') +']');
  1541. }
  1542. sendMessage();
  1543. } else {
  1544. layer.msg(res.msg||'上传失败');
  1545. }
  1546. }
  1547. });
  1548. }
  1549. //音频和视频
  1550. ,media: function(othis){
  1551. var type = othis.data('type'), text = {
  1552. audio: '音频'
  1553. ,video: '视频'
  1554. } ,thatChat = thisChat()
  1555. layer.prompt({
  1556. title: '请输入网络'+ text[type] + '地址'
  1557. ,shade: false
  1558. ,offset: [
  1559. othis.offset().top - $(window).scrollTop() - 158 + 'px'
  1560. ,othis.offset().left + 'px'
  1561. ]
  1562. }, function(src, index){
  1563. focusInsert(thatChat.textarea[0], type + '['+ src +']');
  1564. sendMessage();
  1565. layer.close(index);
  1566. });
  1567. }
  1568. //扩展工具栏
  1569. ,extend: function(othis){
  1570. var filter = othis.attr('lay-filter')
  1571. ,thatChat = thisChat();
  1572. layui.each(call['tool('+ filter +')'], function(index, item){
  1573. item && item.call(othis, function(content){
  1574. focusInsert(thatChat.textarea[0], content);
  1575. }, sendMessage, thatChat);
  1576. });
  1577. }
  1578. //播放音频
  1579. ,playAudio: function(othis){
  1580. var audioData = othis.data('audio')
  1581. ,audio = audioData || document.createElement('audio')
  1582. ,pause = function(){
  1583. audio.pause();
  1584. othis.removeAttr('status');
  1585. othis.find('i').html('&#xe652;');
  1586. };
  1587. if(othis.data('error')){
  1588. return layer.msg('播放音频源异常');
  1589. }
  1590. if(!audio.play){
  1591. return layer.msg('您的浏览器不支持audio');
  1592. }
  1593. if(othis.attr('status')){
  1594. pause();
  1595. } else {
  1596. audioData || (audio.src = othis.data('src'));
  1597. audio.play();
  1598. othis.attr('status', 'pause');
  1599. othis.data('audio', audio);
  1600. othis.find('i').html('&#xe651;');
  1601. //播放结束
  1602. audio.onended = function(){
  1603. pause();
  1604. };
  1605. //播放异常
  1606. audio.onerror = function(){
  1607. layer.msg('播放音频源异常');
  1608. othis.data('error', true);
  1609. pause();
  1610. };
  1611. }
  1612. }
  1613. //播放视频
  1614. ,playVideo: function(othis){
  1615. var videoData = othis.data('src')
  1616. ,video = document.createElement('video');
  1617. if(!video.play){
  1618. return layer.msg('您的浏览器不支持video');
  1619. }
  1620. layer.close(events.playVideo.index);
  1621. events.playVideo.index = layer.open({
  1622. type: 1
  1623. ,title: '播放视频'
  1624. ,area: ['460px', '300px']
  1625. ,maxmin: true
  1626. ,shade: false
  1627. ,content: '<div style="background-color: #000; height: 100%;"><video style="position: absolute; width: 100%; height: 100%;" src="'+ videoData +'" loop="loop" autoplay="autoplay"></video></div>'
  1628. });
  1629. }
  1630. //聊天记录
  1631. ,chatLog: function(othis){
  1632. var thatChat = thisChat();
  1633. if(!cache.base.chatLog){
  1634. return layer.msg('未开启更多聊天记录');
  1635. }
  1636. layer.close(events.chatLog.index);
  1637. return events.chatLog.index = layer.open({
  1638. type: 2
  1639. ,maxmin: true
  1640. ,title: '与 '+ thatChat.data.name +' 的聊天记录'
  1641. ,area: ['450px', '100%']
  1642. ,shade: false
  1643. ,offset: 'rb'
  1644. ,skin: 'layui-box'
  1645. ,anim: 2
  1646. ,id: 'layui-layim-chatlog'
  1647. ,content: cache.base.chatLog + '?id=' + thatChat.data.id + '&type=' + thatChat.data.type
  1648. });
  1649. }
  1650. //历史会话右键菜单操作
  1651. ,menuHistory: function(othis, e){
  1652. var local = layui.data('layim')[cache.mine.id] || {};
  1653. var parent = othis.parent(), type = othis.data('type');
  1654. var hisElem = layimMain.find('.layim-list-history');
  1655. var none = '<li class="layim-null">暂无历史会话</li>'
  1656. if(type === 'one'){
  1657. var history = local.history;
  1658. delete history[parent.data('index')];
  1659. local.history = history;
  1660. layui.data('layim', {
  1661. key: cache.mine.id
  1662. ,value: local
  1663. });
  1664. $('#'+parent.data('id')).remove();
  1665. if(hisElem.find('li').length === 0){
  1666. hisElem.html(none);
  1667. }
  1668. } else if(type === 'all') {
  1669. delete local.history;
  1670. layui.data('layim', {
  1671. key: cache.mine.id
  1672. ,value: local
  1673. });
  1674. hisElem.html(none);
  1675. }
  1676. layer.closeAll('tips');
  1677. }
  1678. };
  1679. //暴露接口
  1680. exports('layim', new LAYIM());
  1681. }).addcss(
  1682. 'modules/layim/layim.css'
  1683. ,'skinlayimcss'
  1684. );