layim.js 61 KB

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