index.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. /**
  2. @Name: Fly社区主入口
  3. */
  4. layui.define(['layer', 'laytpl', 'form', 'element', 'upload', 'util'], function(exports){
  5. var $ = layui.jquery
  6. ,layer = layui.layer
  7. ,laytpl = layui.laytpl
  8. ,form = layui.form
  9. ,element = layui.element
  10. ,upload = layui.upload
  11. ,util = layui.util
  12. ,device = layui.device()
  13. ,DISABLED = 'layui-btn-disabled';
  14. //阻止IE7以下访问
  15. if(device.ie && device.ie < 8){
  16. layer.alert('如果您非得使用 IE 浏览器访问Fly社区,那么请使用 IE8+');
  17. }
  18. layui.focusInsert = function(obj, str){
  19. var result, val = obj.value;
  20. obj.focus();
  21. if(document.selection){ //ie
  22. result = document.selection.createRange();
  23. document.selection.empty();
  24. result.text = str;
  25. } else {
  26. result = [val.substring(0, obj.selectionStart), str, val.substr(obj.selectionEnd)];
  27. obj.focus();
  28. obj.value = result.join('');
  29. }
  30. };
  31. //数字前置补零
  32. layui.laytpl.digit = function(num, length, end){
  33. var str = '';
  34. num = String(num);
  35. length = length || 2;
  36. for(var i = num.length; i < length; i++){
  37. str += '0';
  38. }
  39. return num < Math.pow(10, length) ? str + (num|0) : num;
  40. };
  41. var fly = {
  42. //Ajax
  43. json: function(url, data, success, options){
  44. var that = this, type = typeof data === 'function';
  45. if(type){
  46. options = success
  47. success = data;
  48. data = {};
  49. }
  50. options = options || {};
  51. return $.ajax({
  52. type: options.type || 'post',
  53. dataType: options.dataType || 'json',
  54. data: data,
  55. url: url,
  56. success: function(res,status,xhr){
  57. if(xhr.status === 200) {
  58. success && success(res);
  59. } else {
  60. layer.msg(res.msg || res.code, {shift: 6});
  61. options.error && options.error();
  62. }
  63. }, error: function(e){
  64. layer.msg('请求异常,请重试', {shift: 6});
  65. options.error && options.error(e);
  66. }
  67. });
  68. }
  69. //计算字符长度
  70. ,charLen: function(val){
  71. var arr = val.split(''), len = 0;
  72. for(var i = 0; i < val.length ; i++){
  73. arr[i].charCodeAt(0) < 299 ? len++ : len += 2;
  74. }
  75. return len;
  76. }
  77. ,form: {}
  78. //简易编辑器
  79. ,layEditor: function(options){
  80. var html = ['<div class="layui-unselect fly-edit">'
  81. ,'<span type="face" title="插入表情"><i class="iconfont icon-yxj-expression" style="top: 1px;"></i></span>'
  82. ,'<span type="picture" title="插入图片:img[src]"><i class="iconfont icon-tupian"></i></span>'
  83. ,'<span type="href" title="超链接格式:a(href)[text]"><i class="iconfont icon-lianjie"></i></span>'
  84. ,'<span type="code" title="插入代码或引用"><i class="iconfont icon-emwdaima" style="top: 1px;"></i></span>'
  85. ,'<span type="hr" title="插入水平线">hr</span>'
  86. ,'<span type="yulan" title="预览"><i class="iconfont icon-yulan1"></i></span>'
  87. ,'</div>'].join('');
  88. var log = {}, mod = {
  89. face: function(editor, self){ //插入表情
  90. var str = '', ul, face = fly.faces;
  91. for(var key in face){
  92. str += '<li title="'+ key +'"><img src="'+ face[key] +'"></li>';
  93. }
  94. str = '<ul id="LAY-editface" class="layui-clear">'+ str +'</ul>';
  95. layer.tips(str, self, {
  96. tips: 3
  97. ,time: 0
  98. ,skin: 'layui-edit-face'
  99. });
  100. $(document).on('click', function(){
  101. layer.closeAll('tips');
  102. });
  103. $('#LAY-editface li').on('click', function(){
  104. var title = $(this).attr('title') + ' ';
  105. layui.focusInsert(editor[0], 'face' + title);
  106. });
  107. }
  108. ,picture: function(editor){ //插入图片
  109. layer.open({
  110. type: 1
  111. ,id: 'fly-jie-upload'
  112. ,title: '插入图片'
  113. ,area: 'auto'
  114. ,shade: false
  115. ,area: '465px'
  116. ,fixed: false
  117. ,offset: [
  118. editor.offset().top - $(window).scrollTop() + 'px'
  119. ,editor.offset().left + 'px'
  120. ]
  121. ,skin: 'layui-layer-border'
  122. ,content: ['<ul class="layui-form layui-form-pane" style="margin: 20px;">'
  123. ,'<li class="layui-form-item">'
  124. ,'<label class="layui-form-label">URL</label>'
  125. ,'<div class="layui-input-inline">'
  126. ,'<input required name="image" placeholder="粘贴远程图片地址" value="" class="layui-input">'
  127. ,'</div>'
  128. ,'<button type="button" lay-submit lay-filter="uploadImages" class="layui-btn">确认</button>'
  129. ,'</li>'
  130. ,'<li class="layui-form-item" style="text-align: center;">'
  131. ,'</li>'
  132. ,'</ul>'].join('')
  133. ,success: function(layero, index){
  134. var image = layero.find('input[name="image"]');
  135. //执行上传实例
  136. upload.render({
  137. elem: '#uploadImg'
  138. ,url: '/api/upload/'
  139. ,size: 200
  140. ,done: function(res){
  141. if(res.code == 0){
  142. image.val(res.url);
  143. } else {
  144. layer.msg(res.msg, {icon: 5});
  145. }
  146. }
  147. });
  148. form.on('submit(uploadImages)', function(data){
  149. var field = data.field;
  150. if(!field.image) return image.focus();
  151. layui.focusInsert(editor[0], 'img['+ field.image + '] ');
  152. layer.close(index);
  153. });
  154. }
  155. });
  156. }
  157. ,href: function(editor){ //超链接
  158. layer.prompt({
  159. title: '请输入合法链接'
  160. ,shade: false
  161. ,fixed: false
  162. ,id: 'LAY_flyedit_href'
  163. ,offset: [
  164. editor.offset().top - $(window).scrollTop() + 'px'
  165. ,editor.offset().left + 'px'
  166. ]
  167. }, function(val, index, elem){
  168. if(!/^http(s*):\/\/[\S]/.test(val)){
  169. layer.tips('这根本不是个链接,不要骗我。', elem, {tips:1})
  170. return;
  171. }
  172. layui.focusInsert(editor[0], ' a('+ val +')['+ val + '] ');
  173. layer.close(index);
  174. });
  175. }
  176. ,code: function(editor){ //插入代码
  177. layer.prompt({
  178. title: '请贴入代码或任意文本'
  179. ,formType: 2
  180. ,maxlength: 10000
  181. ,shade: false
  182. ,id: 'LAY_flyedit_code'
  183. ,area: ['800px', '360px']
  184. }, function(val, index, elem){
  185. layui.focusInsert(editor[0], '[pre]\n'+ val + '\n[/pre]');
  186. layer.close(index);
  187. });
  188. }
  189. ,hr: function(editor){ //插入水平分割线
  190. layui.focusInsert(editor[0], '[hr]');
  191. }
  192. ,yulan: function(editor){ //预览
  193. var content = editor.val();
  194. content = /^\{html\}/.test(content)
  195. ? content.replace(/^\{html\}/, '')
  196. : fly.content(content);
  197. layer.open({
  198. type: 1
  199. ,title: '预览'
  200. ,shade: false
  201. ,area: ['100%', '100%']
  202. ,scrollbar: false
  203. ,content: '<div class="detail-body" style="margin:20px;">'+ content +'</div>'
  204. });
  205. }
  206. };
  207. layui.use('face', function(face){
  208. options = options || {};
  209. fly.faces = face;
  210. $(options.elem).each(function(index){
  211. var that = this, othis = $(that), parent = othis.parent();
  212. parent.prepend(html);
  213. parent.find('.fly-edit span').on('click', function(event){
  214. var type = $(this).attr('type');
  215. mod[type].call(that, othis, this);
  216. if(type === 'face'){
  217. event.stopPropagation()
  218. }
  219. });
  220. });
  221. });
  222. }
  223. ,escape: function(html){
  224. return String(html||'').replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
  225. .replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/'/g, '&#39;').replace(/"/g, '&quot;');
  226. }
  227. //内容转义
  228. ,content: function(content){
  229. //支持的html标签
  230. var html = function(end){
  231. return new RegExp('\\n*\\['+ (end||'') +'(pre|hr|div|span|p|table|thead|th|tbody|tr|td|ul|li|ol|li|dl|dt|dd|h2|h3|h4|h5)([\\s\\S]*?)\\]\\n*', 'g');
  232. };
  233. content = fly.escape(content||'') //XSS
  234. .replace(/img\[([^\s]+?)\]/g, function(img){ //转义图片
  235. return '<img src="' + img.replace(/(^img\[)|(\]$)/g, '') + '">';
  236. }).replace(/@(\S+)(\s+?|$)/g, '@<a href="javascript:;" class="fly-aite">$1</a>$2') //转义@
  237. .replace(/face\[([^\s\[\]]+?)\]/g, function(face){ //转义表情
  238. var alt = face.replace(/^face/g, '');
  239. if(!fly.faces){fly.faces=[]}
  240. return '<img alt="'+ alt +'" title="'+ alt +'" src="' + fly.faces[alt] + '">';
  241. }).replace(/a\([\s\S]+?\)\[[\s\S]*?\]/g, function(str){ //转义链接
  242. var href = (str.match(/a\(([\s\S]+?)\)\[/)||[])[1];
  243. var text = (str.match(/\)\[([\s\S]*?)\]/)||[])[1];
  244. if(!href) return str;
  245. var rel = /^(http(s)*:\/\/)\b(?!(\w+\.)*(sentsin.com|layui.com))\b/.test(href.replace(/\s/g, ''));
  246. return '<a href="'+ href +'" target="_blank"'+ (rel ? ' rel="nofollow"' : '') +'>'+ (text||href) +'</a>';
  247. }).replace(html(), '\<$1 $2\>').replace(html('/'), '\</$1\>') //转移HTML代码
  248. .replace(/\n/g, '<br>') //转义换行
  249. return content;
  250. }
  251. //新消息通知
  252. ,newmsg: function(){
  253. var elemUser = $('.fly-nav-user');
  254. if(layui.cache.user.uid !== -1 && elemUser[0]){
  255. fly.json('/message/nums/', {
  256. _: new Date().getTime()
  257. }, function(res){
  258. if(res.code === 0 && res.count > 0){
  259. var msg = $('<a class="fly-nav-msg" href="javascript:;">'+ res.count +'</a>');
  260. elemUser.append(msg);
  261. msg.on('click', function(){
  262. fly.json('/message/read', {}, function(res){
  263. if(res.code === 0){
  264. location.href = '/user/message/';
  265. }
  266. });
  267. });
  268. layer.tips('你有 '+ res.count +' 条未读消息', msg, {
  269. tips: 3
  270. ,tipsMore: true
  271. ,fixed: true
  272. });
  273. msg.on('mouseenter', function(){
  274. layer.closeAll('tips');
  275. })
  276. }
  277. });
  278. }
  279. return arguments.callee;
  280. }
  281. };
  282. //签到
  283. var tplSignin = ['{{# if(d.signed){ }}'
  284. ,'<button class="layui-btn layui-btn-disabled">今日已签到</button>'
  285. ,'<span>获得了<cite>{{ d.experience }}</cite>飞吻</span>'
  286. ,'{{# } else { }}'
  287. ,'<button class="layui-btn layui-btn-danger" id="LAY_signin">今日签到</button>'
  288. ,'<span>可获得<cite>{{ d.experience }}</cite>飞吻</span>'
  289. ,'{{# } }}'].join('')
  290. ,tplSigninDay = '已连续签到<cite>{{ d.days }}</cite>天'
  291. ,signRender = function(data){
  292. laytpl(tplSignin).render(data, function(html){
  293. elemSigninMain.html(html);
  294. });
  295. laytpl(tplSigninDay).render(data, function(html){
  296. elemSigninDays.html(html);
  297. });
  298. }
  299. ,elemSigninHelp = $('#LAY_signinHelp')
  300. ,elemSigninTop = $('#LAY_signinTop')
  301. ,elemSigninMain = $('.fly-signin-main')
  302. ,elemSigninDays = $('.fly-signin-days');
  303. if(elemSigninMain[0]){
  304. /*
  305. fly.json('/sign/status', function(res){
  306. if(!res.data) return;
  307. signRender.token = res.data.token;
  308. signRender(res.data);
  309. });
  310. */
  311. }
  312. $('body').on('click', '#LAY_signin', function(){
  313. var othis = $(this);
  314. if(othis.hasClass(DISABLED)) return;
  315. fly.json('/sign/in', {
  316. token: signRender.token || 1
  317. }, function(res){
  318. signRender(res.data);
  319. }, {
  320. error: function(){
  321. othis.removeClass(DISABLED);
  322. }
  323. });
  324. othis.addClass(DISABLED);
  325. });
  326. //签到说明
  327. elemSigninHelp.on('click', function(){
  328. layer.open({
  329. type: 1
  330. ,title: '签到说明'
  331. ,area: '300px'
  332. ,shade: 0.8
  333. ,shadeClose: true
  334. ,content: ['<div class="layui-text" style="padding: 20px;">'
  335. ,'<blockquote class="layui-elem-quote">“签到”可获得社区飞吻,规则如下</blockquote>'
  336. ,'<table class="layui-table">'
  337. ,'<thead>'
  338. ,'<tr><th>连续签到天数</th><th>每天可获飞吻</th></tr>'
  339. ,'</thead>'
  340. ,'<tbody>'
  341. ,'<tr><td><5</td><td>5</td></tr>'
  342. ,'<tr><td>≥5</td><td>10</td></tr>'
  343. ,'<tr><td>≥15</td><td>15</td></tr>'
  344. ,'<tr><td>≥30</td><td>20</td></tr>'
  345. ,'</tbody>'
  346. ,'</table>'
  347. ,'<ul>'
  348. ,'<li>中间若有间隔,则连续天数重新计算</li>'
  349. ,'<li style="color: #FF5722;">不可利用程序自动签到,否则飞吻清零</li>'
  350. ,'</ul>'
  351. ,'</div>'].join('')
  352. });
  353. });
  354. //签到活跃榜
  355. var tplSigninTop = ['{{# layui.each(d.data, function(index, item){ }}'
  356. ,'<li>'
  357. ,'<a href="/u/{{item.uid}}" target="_blank">'
  358. ,'<img src="{{item.user.avatar}}">'
  359. ,'<cite class="fly-link">{{item.user.username}}</cite>'
  360. ,'</a>'
  361. ,'{{# var date = new Date(item.time); if(d.index < 2){ }}'
  362. ,'<span class="fly-grey">签到于 {{ layui.laytpl.digit(date.getHours()) + ":" + layui.laytpl.digit(date.getMinutes()) + ":" + layui.laytpl.digit(date.getSeconds()) }}</span>'
  363. ,'{{# } else { }}'
  364. ,'<span class="fly-grey">已连续签到 <i>{{ item.days }}</i> 天</span>'
  365. ,'{{# } }}'
  366. ,'</li>'
  367. ,'{{# }); }}'
  368. ,'{{# if(d.data.length === 0) { }}'
  369. ,'{{# if(d.index < 2) { }}'
  370. ,'<li class="fly-none fly-grey">今天还没有人签到</li>'
  371. ,'{{# } else { }}'
  372. ,'<li class="fly-none fly-grey">还没有签到记录</li>'
  373. ,'{{# } }}'
  374. ,'{{# } }}'].join('');
  375. elemSigninTop.on('click', function(){
  376. var loadIndex = layer.load(1, {shade: 0.8});
  377. fly.json('../json/signin.js', function(res){ //实际使用,请将 url 改为真实接口
  378. var tpl = $(['<div class="layui-tab layui-tab-brief" style="margin: 5px 0 0;">'
  379. ,'<ul class="layui-tab-title">'
  380. ,'<li class="layui-this">最新签到</li>'
  381. ,'<li>今日最快</li>'
  382. ,'<li>总签到榜</li>'
  383. ,'</ul>'
  384. ,'<div class="layui-tab-content fly-signin-list" id="LAY_signin_list">'
  385. ,'<ul class="layui-tab-item layui-show"></ul>'
  386. ,'<ul class="layui-tab-item">2</ul>'
  387. ,'<ul class="layui-tab-item">3</ul>'
  388. ,'</div>'
  389. ,'</div>'].join(''))
  390. ,signinItems = tpl.find('.layui-tab-item');
  391. layer.close(loadIndex);
  392. layui.each(signinItems, function(index, item){
  393. var html = laytpl(tplSigninTop).render({
  394. data: res.data[index]
  395. ,index: index
  396. });
  397. $(item).html(html);
  398. });
  399. layer.open({
  400. type: 1
  401. ,title: '签到活跃榜 - TOP 20'
  402. ,area: '300px'
  403. ,shade: 0.8
  404. ,shadeClose: true
  405. ,id: 'layer-pop-signintop'
  406. ,content: tpl.prop('outerHTML')
  407. });
  408. }, {type: 'get'});
  409. });
  410. //回帖榜
  411. var tplReply = ['{{# layui.each(d.data, function(index, item){ }}'
  412. ,'<dd>'
  413. ,'<a href="/u/{{item.uid}}">'
  414. ,'<img src="{{item.user.avatar}}">'
  415. ,'<cite>{{item.user.username}}</cite>'
  416. ,'<i>{{item["count(*)"]}}次回答</i>'
  417. ,'</a>'
  418. ,'</dd>'
  419. ,'{{# }); }}'].join('')
  420. ,elemReply = $('#LAY_replyRank');
  421. if(elemReply[0]){
  422. /*
  423. fly.json('/top/reply/', {
  424. limit: 20
  425. }, function(res){
  426. var html = laytpl(tplReply).render(res);
  427. elemReply.find('dl').html(html);
  428. });
  429. */
  430. };
  431. //相册
  432. if($(window).width() > 750){
  433. layer.photos({
  434. photos: '.photos'
  435. ,zIndex: 9999999999
  436. ,anim: -1
  437. });
  438. } else {
  439. $('body').on('click', '.photos img', function(){
  440. window.open(this.src);
  441. });
  442. }
  443. //搜索
  444. $('.fly-search').on('click', function(){
  445. layer.open({
  446. type: 1
  447. ,title: false
  448. ,closeBtn: false
  449. //,shade: [0.1, '#fff']
  450. ,shadeClose: true
  451. ,maxWidth: 10000
  452. ,skin: 'fly-layer-search'
  453. ,content: ['<form action="http://cn.bing.com/search">'
  454. ,'<input autocomplete="off" placeholder="搜索内容,回车跳转" type="text" name="q">'
  455. ,'</form>'].join('')
  456. ,success: function(layero){
  457. var input = layero.find('input');
  458. input.focus();
  459. layero.find('form').submit(function(){
  460. var val = input.val();
  461. if(val.replace(/\s/g, '') === ''){
  462. return false;
  463. }
  464. input.val('site:layui.com '+ input.val());
  465. });
  466. }
  467. })
  468. });
  469. //新消息通知
  470. fly.newmsg();
  471. //发送激活邮件
  472. fly.activate = function(email){
  473. fly.json('/api/activate/', {}, function(res){
  474. if(res.code === 0){
  475. layer.alert('已成功将激活链接发送到了您的邮箱,接受可能会稍有延迟,请注意查收。', {
  476. icon: 1
  477. });
  478. };
  479. });
  480. };
  481. $('#LAY-activate').on('click', function(){
  482. fly.activate($(this).attr('email'));
  483. });
  484. //点击@
  485. $('body').on('click', '.fly-aite', function(){
  486. var othis = $(this), text = othis.text();
  487. if(othis.attr('href') !== 'javascript:;'){
  488. return;
  489. }
  490. // text = text.replace(/^@|([\s\S]+?)/g, '');
  491. othis.attr({
  492. href: 'javascript:;'
  493. });
  494. });
  495. //表单提交
  496. form.on('submit(*)', function(data){
  497. var action = $(data.form).attr('action'), button = $(data.elem);
  498. fly.json(action, data.field, function(res){
  499. var end = function(){
  500. if(res.url){
  501. location.href = res.url;
  502. } else {
  503. fly.form[action||button.attr('key')](data.field, data.form,res);
  504. }
  505. };
  506. if(res.code == 0){
  507. button.attr('alert') ? layer.alert(res.msg, {
  508. icon: 5,
  509. time: 10*1000,
  510. end: end
  511. }) : end();
  512. }else{
  513. end();
  514. }
  515. });
  516. return false;
  517. });
  518. //加载特定模块
  519. if(layui.cache.page && layui.cache.page !== 'index'){
  520. var extend = {};
  521. extend[layui.cache.page] = layui.cache.page;
  522. layui.extend(extend);
  523. layui.use(layui.cache.page);
  524. }
  525. //加载IM
  526. if(!device.android && !device.ios){
  527. //layui.use('im');
  528. }
  529. //加载编辑器
  530. fly.layEditor({
  531. elem: '.fly-editor'
  532. });
  533. //手机设备的简单适配
  534. var treeMobile = $('.site-tree-mobile')
  535. ,shadeMobile = $('.site-mobile-shade')
  536. treeMobile.on('click', function(){
  537. $('body').addClass('site-mobile');
  538. });
  539. shadeMobile.on('click', function(){
  540. $('body').removeClass('site-mobile');
  541. });
  542. //获取统计数据
  543. $('.fly-handles').each(function(){
  544. var othis = $(this);
  545. $.get('/api/handle?alias='+ othis.data('alias'), function(res){
  546. othis.html('(下载量:'+ res.number +')');
  547. })
  548. });
  549. //固定Bar
  550. util.fixbar({
  551. bgcolor: '#009688'
  552. , click: function (type) {
  553. if (type === 'bar1') {
  554. layer.msg('未开启发表新贴');
  555. }
  556. }
  557. });
  558. exports('fly', fly);
  559. });