diff --git a/Last_Volatility/conf.json b/Last_Volatility/conf.json new file mode 100644 index 0000000..45e5ba2 --- /dev/null +++ b/Last_Volatility/conf.json @@ -0,0 +1,11 @@ +{ + "name": "Volatility", + "brief": "与浏览器融为一体 - 更接近原生APP的主题, 目前仅作用于手机页面, (更新: 修复导航滚动)", + "version": "1.2", + "bbs_version": "4.0", + "installed": 1, + "enable": 1, + "hooks_rank": [], + "overwrites_rank": [], + "dependencies": [] +} \ No newline at end of file diff --git a/Last_Volatility/hook/footer_js_after.htm b/Last_Volatility/hook/footer_js_after.htm new file mode 100644 index 0000000..ba6cefa --- /dev/null +++ b/Last_Volatility/hook/footer_js_after.htm @@ -0,0 +1,21 @@ + + \ No newline at end of file diff --git a/Last_Volatility/hook/forum_start.htm b/Last_Volatility/hook/forum_start.htm new file mode 100644 index 0000000..f2275b9 --- /dev/null +++ b/Last_Volatility/hook/forum_start.htm @@ -0,0 +1 @@ + diff --git a/Last_Volatility/hook/header_link_after.htm b/Last_Volatility/hook/header_link_after.htm new file mode 100644 index 0000000..2894d7f --- /dev/null +++ b/Last_Volatility/hook/header_link_after.htm @@ -0,0 +1,3 @@ + + + diff --git a/Last_Volatility/hook/index_start.htm b/Last_Volatility/hook/index_start.htm new file mode 100644 index 0000000..f2275b9 --- /dev/null +++ b/Last_Volatility/hook/index_start.htm @@ -0,0 +1 @@ + diff --git a/Last_Volatility/hook/post_list_inc_filelist_after.htm b/Last_Volatility/hook/post_list_inc_filelist_after.htm new file mode 100644 index 0000000..9db34f8 --- /dev/null +++ b/Last_Volatility/hook/post_list_inc_filelist_after.htm @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/Last_Volatility/hook/thread_username_before.htm b/Last_Volatility/hook/thread_username_before.htm new file mode 100644 index 0000000..6f3c72e --- /dev/null +++ b/Last_Volatility/hook/thread_username_before.htm @@ -0,0 +1,11 @@ + + + +
+
+ + " + class="text-muted font-weight-bold"> + +
+
\ No newline at end of file diff --git a/Last_Volatility/hook/thread_views_after.htm b/Last_Volatility/hook/thread_views_after.htm new file mode 100644 index 0000000..50b9e11 --- /dev/null +++ b/Last_Volatility/hook/thread_views_after.htm @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/Last_Volatility/icon.png b/Last_Volatility/icon.png new file mode 100644 index 0000000..4c9cef4 Binary files /dev/null and b/Last_Volatility/icon.png differ diff --git a/Last_Volatility/view/css/style.css b/Last_Volatility/view/css/style.css new file mode 100644 index 0000000..1ff5002 --- /dev/null +++ b/Last_Volatility/view/css/style.css @@ -0,0 +1,405 @@ +.message .date { + display: none; +} + +@media (max-width: 576px) { + /** + .thread .media-body { + min-width: 0; + } + .thread .media-body .subject { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + **/ + a { + color: #555555; + } + a:link { + text-decoration: none; + } + a:visited { + text-decoration: none; + } + a:hover { + text-decoration: none; + } + a:active { + text-decoration: none; + } + body { + padding-top: 0; + background: #ffffff; + } + .navbar { + display: none; + } + #body>.container>.row>div { + padding: 0; + border: none; + } + .card { + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + word-wrap: break-word; + background-color: #fff; + background-clip: border-box; + border: 0; + border-radius: 0.25rem; + } + .card-body { + flex: 1 1 auto; + padding: 9px 18px; + } + .message { + padding-top: 5px; + } + .message p { + margin: 0; + line-height: 2; + color: #525252; + font-family: Helvetica Neue, NotoSansHans-Regular, AvenirNext-Regular, arial, Hiragino Sans GB, Microsoft Yahei, WenQuanYi Micro Hei, serif; + } + .message img { + max-width: 100%; + height: auto !important; + border: 0px; + border-radius: 3px; + margin-bottom: 9px; + } + .message textarea { + border: none; + border-radius: 1rem; + background: #f8f9fa; + } + .message textarea:focus { + border-radius: 1rem; + background: #f8f9fa; + outline: none; + border: 0; + outline: none; + } + /* 主题列表 */ + .card-threadlist { + margin-top: 8rem; + } + .card-threadlist .card-header { + display: none !important; + } + .card-threadlist a:visited { + color: #666666; + text-decoration: none; + } + .message .date { + display: block; + font-size: .8rem; + margin-top: .5rem; + } + /* 移除全局页脚 */ + #footer { + display: none; + } + /* 附件 */ + .message .fieldset>legend { + display: none; + } + .message .fieldset::before { + position: relative; + top: -1.4rem; + left: 0; + content: "attach"; + padding: 0 10px; + font-size: 1rem; + border-radius: .5rem; + color: #ffffff; + background-color: #FFBA10; + } + /* DEBUG - info */ + .fieldset { + padding: 8px; + margin: 24px 0; + border: none; + border-radius: 2px; + background: #f8f9fa; + } + .fieldset>p { + color: #525252; + } + .fieldset>ul { + list-style: none; + padding: 0; + margin: 0; + color: #525252; + } + .debug::before { + position: relative; + top: -1.4rem; + left: 0; + content: "DEBUG"; + padding: 0 10px; + font-size: 1rem; + border-radius: .5rem; + color: #ffffff; + background-color: #FFBA10; + } +} + +.card-thread .media .user_avatar { + display: none; +} + +.card-thread .card-body .media .media-body .a { + display: none; +} + +@media (max-width: 576px) { + /* 主贴标题 */ + .card-thread .card-body>.media { + margin: 1rem 0; + } + .card-thread .card-body>.media>a { + display: none; + } + .card-thread .card-body .media .media-body>h4 { + margin-bottom: 0.8rem; + } + .card-thread .card-body .media .media-body>div>div { + display: flex; + flex-direction: row; + } + .card-thread .card-body .media .media-body>div>div:first-child>a { + display: flex; + align-items: center; + } + .card-thread .card-body .media .media-body>div>div>div { + display: flex; + flex-direction: column; + } + .card-thread .card-body .media .media-body .a { + display: block; + } + .card-thread .card-body .media .media-body .a span.username { + font-size: 1rem; + } + .card-thread .card-body .media .media-body .b span.username { + display: none; + } + .card-thread .card-body .media .media-body .b span.date { + margin-left: 0 !important; + } + /* 主贴分割线 */ + .card-thread .card-body>hr { + display: none; + } + .thread, + .post { + border-bottom: 0; + padding: 0.8rem 0px; + } + /* 移除原有时间 */ + .post .media-body .justify-content-between>div>span.date { + display: none; + } +} + + +/* 分页导航 */ + +@media (max-width: 576px) { + .page-item:first-child .page-link { + margin-left: 0; + padding-left: 1rem; + border-top-left-radius: .5rem; + border-bottom-left-radius: .5rem; + } + .page-item:last-child .page-link { + padding-right: 1rem; + border-top-right-radius: .5rem; + border-bottom-right-radius: .5rem; + } + .page-link { + font-size: 1.2rem; + position: relative; + display: block; + padding: 0.5rem 1rem; + margin-left: -1px; + line-height: 1.25; + color: #555555; + background-color: #fff; + border: 1px solid #dee2e6; + } + .page-item.active .page-link { + z-index: 1; + color: #fff; + background-color: #999999; + border-color: #999999; + } +} + + +/* Rw Nav */ + +nav.navbar { + display: none; +} + +@media (max-width: 576px) { + nav.navbar { + position: fixed; + right: 0; + left: 0; + top: 0; + z-index: 1030; + border-width: 0 0 1px; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; + display: flex; + flex-direction: column; + background-color: #ffffff; + -webkit-transition: all 0.8s ease; + transition: all 0.8s ease; + } + nav.navbar.shrink { + min-height: 120px; + } + nav.navbar ul { + display: flex; + align-items: center; + flex-direction: row; + list-style: none; + padding: 0; + margin: 0; + } + nav.navbar>.a { + opacity: 0; + height: 0; + -webkit-transition: all 0.8s ease; + transition: all 0.8s ease; + } + nav.navbar>.b { + width: 100%; + overflow-x: scroll; + overflow-y: hidden; + white-space: nowrap; + } + nav.navbar>.b::-webkit-scrollbar {display:none} + nav.navbar.shrink>.a { + opacity: 1; + height: 3rem; + } + nav.navbar .user {} + nav.navbar .user img {} + nav.navbar .search { + flex: 8; + padding: 0 12px; + } + nav.navbar .search div { + width: 100%; + min-width: 150px; + height: 2.2rem; + padding: 0 1rem; + border-radius: 1.1rem; + background: #eeeeee; + border: 0; + outline: none; + } + /** 暂时放弃输入框 + nav.navbar .search input { + width: 100%; + min-width: 150px; + height: 2.2rem; + padding: 0 1rem; + border-radius: 1.1rem; + background: #eeeeee; + border: 0; + outline: none; + } + ::-webkit-input-placeholder { + color: #ddd; + text-align: center; + } + :-moz-placeholder { + color: #ddd; + text-align: center; + } + ::-moz-placeholder { + color: #ddd; + text-align: center; + } + :-ms-input-placeholder { + color: #ddd; + text-align: center; + } + */ + nav.navbar .add { + flex: 1; + } + nav.navbar .add a { + display: block; + height: 2.2rem; + width: 2.2rem; + padding: 0; + text-align: center; + border-radius: 1.1rem; + line-height: 2.2rem; + color: #ccc; + background: #eeeeee; + } + nav.navbar .add .icon-edit:before { + padding: 0; + color: #555555; + line-height: 2.2rem; + } + /* 返回按钮 */ + .xn-back { + display: block; + width: 60%; + } +} + +/* USER */ +#signin { + display: flex; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1031; + background: rgba(255, 255, 255, .8); +} + +/*设置移动效果*/ +.card-threadlist .card-body { + padding-left: 0; + padding-right: 0; +} +.thread { + padding-left: 18px; + padding-right: 18px; + transition:all 0.2s ; + -webkit-transition:all 0.2s ; +} +.moveleft{ + transform: translateX(-20px); + -webkit-transform: translateX(-20px); + position: relative; + transition:all 0.2s ; + -webkit-transition:all 0.2s ; +} +.moveleft::after { + content: " "; + position: absolute; + right: -20px; + display: block; + background: #FFBA10; + width: 20px; + height: 100%; + margin-top: -0.8rem; + transition:all 0.2s ; + -webkit-transition:all 0.2s ; +} diff --git a/Last_Volatility/view/htm/nav.htm b/Last_Volatility/view/htm/nav.htm new file mode 100644 index 0000000..0deb378 --- /dev/null +++ b/Last_Volatility/view/htm/nav.htm @@ -0,0 +1,43 @@ + diff --git a/Last_Volatility/view/js/main.js b/Last_Volatility/view/js/main.js new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Last_Volatility/view/js/main.js @@ -0,0 +1 @@ + diff --git a/Last_Volatility/view/js/user.js b/Last_Volatility/view/js/user.js new file mode 100644 index 0000000..0c83440 --- /dev/null +++ b/Last_Volatility/view/js/user.js @@ -0,0 +1,167 @@ +var storage = { + // 检查可用的模式 + test: function () { + // 本地存储是否可用 + var test = 'test'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch (e) { + return false; + } + }, + setItem: function (k, v) { + localStorage.setItem(k, v) + } + // cookies 是否可用 + // 都不可用, 直接提示无法登陆 + // 要存储的数据一般有 身份信息, 状态信息"x, 设置信息? 统计信息 +} +var cookie = { + get: function (cname) { + var name = cname + "=" + var ca = document.cookie.split(';') + for (var i = 0; i < ca.length; i++) { + var c = ca[i].trim() + if (c.indexOf(name) == 0) return c.substring(name.length, c.length) + } + return "" + }, + sid: function () { + return this.get("bbs_sid") + }, + token: function () { + return this.get("bbs_token") + } +} +var user = { + signin: function () { + var div = document.createElement("div") + div.id = "signin" + div.innerHTML = `` + document.body.appendChild(div) + + // 为登录按钮挂载一个事件监听, 如果已经登录则这个挂载是不必要的 + // 为窗口背景挂载一个关闭按钮区域 + // 当登录成功, 移除登录窗口时, 事件监听是否还存在? + return div.onclick = function () { + if (div.style.display == "none") { + div.style.display = "" + } else { + div.style.display = "none" + } + } + }, + signout: function () { + // 发送退出数据 转变模式到游客 + // 清空本地存储的所有数据, 通常退出的意义 + // 当退出登录时, 重新挂载登录窗口, 也可以始终都不移除它? + // alert("aoaoaoaoaoao") + }, + regedit: function () { + // 游客可以注册, 但通常作为低频数据结构, 它不应放入js + }, + id: "int", + token: "string", + name: "string", + avact: "string", + online: false, + init: function () { + // 基本数据初始化 + this.online = cookie.token == "" ? false : true + + // 基本状态初始化 + this.online ? this.signout() : this.signin() + } +} + +user.init() +//alert("cacxscasca") +// 所以只在判断未登录状态下才挂载这个面板 +// 为页面添加默认隐藏的登录窗口 +// signin() + +var admin = { + thread: { + list: [], + delete: function(){}, + }, +} + +// 侧滑选中 +window.onload = function () { + + //侧滑显示删除按钮 + + var open = null;//open初始化,判断是否是已展开元素 + var list = document.getElementsByClassName("thread");//list获取所有的待展开框 + for (var i = 0; i < list.length; i++) { + var x, y, X, Y, moveX, moveY; + list[i].addEventListener('touchstart', function (e) { + /*获取最初的触摸位置*/ + x = e.changedTouches[0].pageX; + y = e.changedTouches[0].pageY; + moveX = true; + moveY = true; + }); + + list[i].addEventListener('touchmove', function (e) { + X = e.changedTouches[0].pageX; + Y = e.changedTouches[0].pageY; + + //左右滑动 + if (moveX && Math.abs(X - x) - Math.abs(Y - y) > 0) { + e.stopPropagation();//阻止冒泡事件 + //右滑收起删除按钮 + if (X - x > 10) { + e.preventDefault(); + this.classList.remove("moveleft"); + } + //左滑显示删除按钮 + if (x - X > 10) { + e.preventDefault(); + this.classList.add("moveleft"); + open = this;//存入展开的li元素 + } + //moveY = false;//左右滑动时不执行上下滑动时的事件 + } + + //上下滑动 + if (moveY && Math.abs(X - x) - Math.abs(Y - y) < 0) { + moveX = false;//上下滑动时不执行左右滑动时的事件 + } + }); + + list[i].addEventListener('click', function (e) { + //在已展开的元素中执行操作 + if (open) { + var obj = e.target; + var objli = e.target.closest(".list-li"); + + //点击li元素里不是删除按钮的部分,li元素收起 + if (obj.className != "btn") { + open.classList.remove("moveleft"); + } else if (obj.className == "btn") {//点击删除按钮执行删除 + var objp = obj.parentNode; + var objpp = obj.parentNode.parentNode; + objpp.removeChild(objp); + } + } + }); + + } +} \ No newline at end of file diff --git a/git_tags/README.md b/git_tags/README.md new file mode 100644 index 0000000..5f3ca47 --- /dev/null +++ b/git_tags/README.md @@ -0,0 +1,81 @@ +### 前言 + +如果大家以及感兴趣的开发者朋友,希望拥有一个传统的帖子标签插件,请支持该项目,请前来完善协作该插件,插件挂载在码云,可以多人协作代码,以便更好的完善。该插件是否完善的更好,取决于大家协作的效果,本人只是开个门。 + + + +### 插件简介 + +插件名:帖子标签 + +插件ID:git_tags + +邀请广大的xiuno bbs开发者朋友,请前来协助完善这款标签插件。 + +这款标签插件,可以给标签任意加标签,传统方式纯用途的帖子标签插件。可以结合官方axiuno的标签插件共同使用,没有冲突,可以正常使用。 + + + +### 最新版本 + +版本号:1.0.0 beta + +说明:版本未经过多测试,如有问题请反馈! + +下载:https://gitee.com/soyoumi/git_tags/tree/History/ + + + +### 申请加入协作 + +如要加入申请协作该项目,请在此进行申请加入项目协作。 + +http://bbs.xiuno.com/thread-21013.htm + +加入QQ交流群 625244937,[点击加入](https://jq.qq.com/?_wv=1027&k=5JYjW6A),随时沟通讨论完善项目. + + + +### 插件协作历史 + +2018年5月24日 +>修复tag主题列表页翻页功能 +>修正数据表索引 +>修正删除主题时删标签 +>精简字符过滤 +>允许输入空格 +>标签云加缓存 +>前端自动聚焦 +>后端样式调整 + +2018年5月3日 +>暂不启用关联主题,等待方案后续完成
+>整理推送1.0测试版,原因:目前项目整体代码,并不适合发布正式版,仅适合测试使用 +

+ +2018年4月16日 +>√标签页已经完成
+>√完善标签页页面名信息,暂定方式
+>暂时丢弃主题列表后面标签推
+>待完成
+>...帖子内容页下方,相关主题推荐,完成后预备发布版本
+>后续考虑
+>...前端重写,放置发布版本之后再做考虑
+

+ +2018年3月18日 +>【予感开发者】更新 conf.json、优化、修正
+>【动态】第3位协作者加入
+>【商量讨论】经过讨论,确定不采纳新的查询方式,虽然新查询方法更高效,但查询有问题,以及不好处理,继续采用原方法
+>【soyoumi开发者】增加2个空hook,以及备注hook作用,以便其它协作者即将开始的工作,更新插件信息,设计新的插件黑色图标 +

+ +2018年3月17日 +> 迎来第二位协作者
+>【予感开发者】增加 tag单页方法,增加优化样式逻辑
+>【soyoumi开发者】变更插件标识名,解决与xn_tag插件安装时只能选其一的问题,标识名全变更为:git_tags,git意为git上多人协作版插件。 +

+ +2018年3月16日 +>【soyoumi开发者】创建项目,上传原标签插件项目文件
+>【soyoumi开发者】简单修复已无法使用的标签插件,修复为可用,但存在问题,问题是标签列表,有错位问题,未修复! diff --git a/git_tags/conf.json b/git_tags/conf.json new file mode 100644 index 0000000..1254ec4 --- /dev/null +++ b/git_tags/conf.json @@ -0,0 +1,11 @@ +{ + "name": "标签", + "brief": "主题任意加标签, 通过关联调取近相关的主题用于推送,
协作完善", + "version": "1.0.0", + "bbs_version": "4.3", + "installed": 1, + "enable": 1, + "hooks_rank": [], + "overwrites_rank": [], + "dependencies": [] +} \ No newline at end of file diff --git a/git_tags/hook/bk/post_subject_after.htm b/git_tags/hook/bk/post_subject_after.htm new file mode 100644 index 0000000..7b1853f --- /dev/null +++ b/git_tags/hook/bk/post_subject_after.htm @@ -0,0 +1,16 @@ +$tid), array(), $page, $pagesize); + if($data){ + $tagid = arrlist_values($data, 'tagid'); + $tag = db_find('git_tags',array('tagid'=>$tagid), array(), $page, $pagesize); + foreach($tag as $k){ $taglist .= $k['name'].' '; } + } +?> + +
+
+ +
\ No newline at end of file diff --git a/git_tags/hook/bk/post_update_get_post.php b/git_tags/hook/bk/post_update_get_post.php new file mode 100644 index 0000000..655e55f --- /dev/null +++ b/git_tags/hook/bk/post_update_get_post.php @@ -0,0 +1,41 @@ +//获取填写框内容,进行字符替换处理 +$from_tag=param('tag_post'); //取到填写框的值 +$from_tag=str_replace(" ",",",$from_tag); +$regex = "/\/|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\(|\)|\+|\{|\}|\<|\>|\[|\]|\.|\/|\;|\'|\`|\=|\\\|\s+/"; +$from_tag=preg_replace($regex,"",$from_tag); +$from_tag=str_replace(",",",",str_replace(" ",",",$from_tag)); +$from_tag=str_replace(",,",",",str_replace(",,,",",",$from_tag)); +$tag_arry=array_unique(explode(',',$from_tag)); //最终得到填写框的内容数组 +$tag_arry=array_merge($tag_arry); +$from_tag=implode(",",$tag_arry); //将填写框内容分割为逗号隔开的字符串 + + +if($from_tag==true){ + //删除淀余的标签记录 + $aa = db_sql_find("SELECT * FROM bbs_git_tags_thread where tid='$tid'"); + if($aa !== false || count($aa)>0) { + $db_tagid_arry = array_map('array_shift',$aa); + db_delete('git_tags_thread', array('tid'=>$tid)); + + for($y=0;$y$tagid)); + if($if_g === FALSE){ + db_delete('git_tags', array('tagid'=>$tagid)); + } + } + } + + + //将填写框重新编辑的标签,更新进数据库 + db_delete('git_tags_thread', array('tid'=>$tid)); + for($i=0;$i$tag_arry[$i])); + if($arrlist==FALSE){ + $tagid = db_insert('git_tags',array('tagid'=>null,'name'=>$tag_arry[$i])); + db_insert('git_tags_thread',array('tagid'=>$tagid,'tid'=>$tid)); + }else{ + db_insert('git_tags_thread',array('tagid'=>$arrlist['tagid'],'tid'=>$tid)); + } + } +} diff --git a/git_tags/hook/bk/thread_create_thread_end.php b/git_tags/hook/bk/thread_create_thread_end.php new file mode 100644 index 0000000..3906b0c --- /dev/null +++ b/git_tags/hook/bk/thread_create_thread_end.php @@ -0,0 +1,20 @@ +$from_tag=param('tag_post'); +$from_tag=str_replace(" ",",",$from_tag); +$regex = "/\/|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\(|\)|\+|\{|\}|\<|\>|\[|\]|\.|\/|\;|\'|\`|\=|\\\|\s+/"; +$from_tag=preg_replace($regex,"",$from_tag); +$from_tag=str_replace(" ",",",str_replace(",",",",$from_tag)); +$from_tag=str_replace(",,",",",str_replace(",,,",",",$from_tag)); +$tag_arry=array_unique(explode(',',$from_tag)); +$from_tag=implode(",",$tag_arry); + +if($from_tag==true){ + for($i=0;$i$tag_arry[$i])); + if($arrlist == FALSE){ + $tagid = db_insert('git_tags',array('tagid'=>null,'name'=>$tag_arry[$i])); + db_insert('git_tags_thread',array('tagid'=>$tagid,'tid'=>$tid)); + }else{ + db_insert('git_tags_thread',array('tagid'=>$arrlist['tagid'],'tid'=>$tid)); + } + } +} diff --git a/git_tags/hook/forum_mod_after.htm b/git_tags/hook/forum_mod_after.htm new file mode 100644 index 0000000..b53ef9c --- /dev/null +++ b/git_tags/hook/forum_mod_after.htm @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/git_tags/hook/header_link_after.htm b/git_tags/hook/header_link_after.htm new file mode 100644 index 0000000..ba1a46a --- /dev/null +++ b/git_tags/hook/header_link_after.htm @@ -0,0 +1,2 @@ + + diff --git a/git_tags/hook/index_route_case_end.php b/git_tags/hook/index_route_case_end.php new file mode 100644 index 0000000..685c54c --- /dev/null +++ b/git_tags/hook/index_route_case_end.php @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/git_tags/hook/model_inc_file.php b/git_tags/hook/model_inc_file.php new file mode 100644 index 0000000..6605c33 --- /dev/null +++ b/git_tags/hook/model_inc_file.php @@ -0,0 +1,2 @@ +$tid), array(), $page, $pagesize); + if($data){ + // 删关联 降计数 ( 权限主题已验证 ) + $arr = arrlist_values($data, 'tagid'); + db_delete('git_tags_thread', array('tid'=>$tid)); + db_update('git_tags', array('tagid'=>$arr), array('link-'=>1)); + db_delete('git_tags', array('tagid'=>$arr,'link'=>0)); + } +} +**/ diff --git a/git_tags/hook/thread_filelist_after.htm b/git_tags/hook/thread_filelist_after.htm new file mode 100644 index 0000000..b9fff83 --- /dev/null +++ b/git_tags/hook/thread_filelist_after.htm @@ -0,0 +1,7 @@ + + + + + + + diff --git a/git_tags/hook/thread_js.htm b/git_tags/hook/thread_js.htm new file mode 100644 index 0000000..eb03cfd --- /dev/null +++ b/git_tags/hook/thread_js.htm @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/git_tags/hook/thread_user_after.htm b/git_tags/hook/thread_user_after.htm new file mode 100644 index 0000000..b21a0ce --- /dev/null +++ b/git_tags/hook/thread_user_after.htm @@ -0,0 +1,6 @@ + + + + + + diff --git a/git_tags/icon.png b/git_tags/icon.png new file mode 100644 index 0000000..ea4574b Binary files /dev/null and b/git_tags/icon.png differ diff --git a/git_tags/install.php b/git_tags/install.php new file mode 100644 index 0000000..464e1ff --- /dev/null +++ b/git_tags/install.php @@ -0,0 +1,39 @@ +tablepre; + + +$sql="CREATE TABLE IF NOT EXISTS {$tablepre}git_tags ( + tagid int(11) unsigned NOT NULL AUTO_INCREMENT, # 标签id + name char(32) NOT NULL DEFAULT '', # 标签名 + link int(11) NOT NULL DEFAULT '0', # 关联数量 + PRIMARY KEY (tagid), + KEY (name) +) ENGINE=MyISAM DEFAULT CHARSET=utf8"; + +db_exec($sql); + + +$sql="CREATE TABLE IF NOT EXISTS {$tablepre}git_tags_thread ( + tagid int(11) unsigned NOT NULL DEFAULT '0', + tid int(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (tagid,tid), + KEY (tid) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;"; + +db_exec($sql); + + +$kv = kv_cache_get('git_tags'); +if(!$kv) { + $kv = array('lock'=>'1', 'stop'=>'商女不知亡国恨 隔江犹唱双截棍', 'limit'=>'24'); + kv_cache_set('git_tags', $kv); +} + +?> diff --git a/git_tags/model/tag.func.php b/git_tags/model/tag.func.php new file mode 100644 index 0000000..3efbe35 --- /dev/null +++ b/git_tags/model/tag.func.php @@ -0,0 +1,156 @@ +$tagid),$order,$page,$pagesize); + $r = arrlist_values($r,'tid'); + $r = db_find('thread', array('tid'=>$r),$order,1,$pagesize); + return $r; +} + + + +// 标签的完整信息 +function tag_info($tagid){ + $r = db_find_one('git_tags', array('tagid'=>$tagid)); + return $r; +} + + +// 主题对应的标签 +function tag_taglist($tid){ + $list = array(); + $r = db_find('git_tags_thread', array('tid'=>$tid), array(), 1, 12); + if($r){ + $r = arrlist_values($r, 'tagid'); + $list = db_find('git_tags', array('tagid'=>$r), array(), 1, 12); + } + return $list; +} + + +function tag_push($tagid){ + //关联推荐 (取得所有关联的主题, 可能数量庞大, 暂限制1k) (暂弃用) + $tlist = db_find('git_tags_thread', array('tagid'=>$tagid), array('tid'=>-1), 1 , 1000); + $tlist = arrlist_values($tlist, 'tid'); // 取出tid, 可能数量庞大 + $tlist = array_unique($tlist); // 移除重复 + $tlist = array_diff($tlist,array('tid'=>$tid)); // 移除自身id + shuffle($tlist); // 打乱排序(需要保障多标签时不只取前面的) + $tlist = array_slice($tlist,0,4); // 取前 4 个,(可能不足4个) + if($tlist){ $lists = db_find('thread', array('tid'=>$tlist)); } + return $list; +} + + + +// add +function tag_add($tid,$tag){ + $r = db_find_one('git_tags',array('name'=>$tag)); + if ($r == FALSE){ + $r = db_insert('git_tags',array('name'=>$tag, 'link'=>1)); + db_insert('git_tags_thread',array('tid'=>$tid, 'tagid'=>$r)); + // 记录到历史 + }else{ + $r = $r['tagid']; + db_insert('git_tags_thread',array('tid'=>$tid, 'tagid'=>$r)); + db_update('git_tags',array('tagid'=>$r),array('link+'=>1)); + // 记录到历史 + } + return $r; +} + + +// del (输入的参数不能为空) +function tag_del($tid,$tagid){ + if($tagid == 'all'){ + $r = db_find('git_tags_thread', array('tid'=>$tid), array(), 1, 12); + if($r){ + // 删关联 降计数 (批量) + $arr = arrlist_values($r, 'tagid'); + db_delete('git_tags_thread', array('tid'=>$tid)); + db_update('git_tags', array('tagid'=>$arr), array('link-'=>1)); + db_delete('git_tags', array('tagid'=>$arr, 'link'=>0)); + } + }else{ + // 删关联 降计数 (单条) + db_delete('git_tags_thread', array('tid'=>$tid,'tagid'=>$tagid)); + db_update('git_tags', array('tagid'=>$tagid), array('link-'=>1)); + db_delete('git_tags', array('tagid'=>$tagid, 'link'=>0)); + } +} + + + + + + + + + + + + + + +/** + * 状态判断 + * + */ + +function tag_max($tid){ + $r = db_count('git_tags_thread', array('tid'=>$tid)); + if ($r > 11) return true; + return FALSE; +} + +function tag_lock($uid,$tid,$gid,$lock) { + /* 若是管理员或作者 + * 若是 TAG 全局未锁且作者未锁 + * $t 是作者锁, 暂未实装 + */ + $t = '1'; + $k = db_find_one('thread', array('tid'=>$tid, 'uid'=>$uid)); + + if ($k != FALSE || $gid == 1) { return FALSE; } + if ($lock==1 && $t==1){ return FALSE; } + return true; +} + +function tag_law($tag,$kv){ + /* 验证长度, 小于2和大于设定的最大字符数禁止 + * 检查危险字符 (首尾空格前端过滤, 此处发现即非法) + * 移除两侧空格, 转化所有符号为空格, 不相等则非法 + * 检查禁用词汇 (回避词 而非脏词过滤, 不宜设置过多) + */ + if( mb_strlen($tag)<2 || mb_strlen($tag)>$kv['limit']) return true; + $r = preg_replace("/[[:punct:]\s]/",' ',trim($tag)); + if ($tag !== $r) return true; + $r = array_unique(explode(' ',$kv['stop'])); + foreach ($r as $v) { if(strpos($tag,$v)) return true; } + return FALSE; +} + +function tag_rep($tag,$tid){ + /* 重复标签检查 (此处效率略低) + * 不要使用反查! 先取出本主题的标签最多 12 个 + */ + $data = db_find('git_tags_thread', array('tid'=>$tid), array(), 1, 12); + if($data){ + $tagidlist = arrlist_values($data, 'tagid'); + $kb = db_find('git_tags', array('tagid'=>$tagidlist)); + $kblist = arrlist_values($kb, 'name'); + if(in_array($tag,$kblist)){ + return true; + } + } + return FALSE; +} + +?> diff --git a/git_tags/route/tag.php b/git_tags/route/tag.php new file mode 100644 index 0000000..3f16051 --- /dev/null +++ b/git_tags/route/tag.php @@ -0,0 +1,65 @@ +-1); + + // lastpid 似乎会导致错误.. + // $order = $conf['order_default']; + + $tag = tag_info($action) OR message(-1,'TAG 不存在'); + $list = tag_list($action, $page, $pagesize, $order); + + // 过滤无权访问的(或许会导致页码总数错误..?) + // thread_list_access_filter($list, $gid); + + $header['title'] = $tag['name']; + $header['mobile_title'] = $tag['name']; + $header['mobile_link']= "#"; + + + if($ajax && !isset($_SERVER['HTTP_X_PJAX'])) message(0, $list); + include _include(APP_PATH.'plugin/git_tags/view/htm/tag.htm'); + +}else{ + + // hook tag_end.php + message(-1, "error"); + +} diff --git a/git_tags/setting.htm b/git_tags/setting.htm new file mode 100644 index 0000000..87d3462 --- /dev/null +++ b/git_tags/setting.htm @@ -0,0 +1,135 @@ + + + +
+
+
+
+
" method="post" id="form"> +

TAG 设置

+
+
全局锁
+ + +
+ +
+
字数限制
+ + + +
+ +
+
回避词
+ +
+ +
+
关于
+

TAG锁开启时, 则所有会员都可以编辑和删除标签, 锁定则只允许作者和管理员编辑 (当前作者锁未实装)

+

按业务场景调整允许的字数范围, 1 中文等于 3 字母

+

回避词非 危险字符过滤 亦非 脏词过滤字典, 请勿添加过多词汇, 否则效率低下

+
+ + +
+ +
+
+ + +
+
+
+
+
+
+
+ + + + diff --git a/git_tags/setting.php b/git_tags/setting.php new file mode 100644 index 0000000..d1d9e70 --- /dev/null +++ b/git_tags/setting.php @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/git_tags/tagtool.php b/git_tags/tagtool.php new file mode 100644 index 0000000..e2da809 --- /dev/null +++ b/git_tags/tagtool.php @@ -0,0 +1,31 @@ +tablepre; +$sql = "DROP TABLE {$tablepre}git_tags"; +db_exec($sql); + +$sql = "DROP TABLE {$tablepre}git_tags_thread"; +db_exec($sql); + +kv_cache_delete('git_tags'); + +?> diff --git a/git_tags/view/css/tag.css b/git_tags/view/css/tag.css new file mode 100644 index 0000000..54563c0 --- /dev/null +++ b/git_tags/view/css/tag.css @@ -0,0 +1,64 @@ +/** + * User: last + * Date: 2018/5/14 + * Time: 上午8:41 + */ + + + +/* 全局默认 */ +a:link,a:visited,a:hover { text-decoration:none } +#tag:after,#tagPush:after,#taghot ul:after,#other ul:after { content: " "; display: block; height: 0; clear: both; visibility: hidden } + + +/* 主题标签 */ +#tag { padding:10px; margin:20px 0; border-radius: 5px; list-style-type: none; } +#tag>li { float: left; border:1px solid #e5e9ef; border-radius:15px; margin:10px 8px 0 0; padding:0 5px 0 3px;} +#tag>li button { font-size:12px; color: #555; border:0; padding:0; background-color:transparent; display:block; width:2rem; } +#tag>li:hover { border:1px solid #ffa7bf; } +#tag>li:hover>a,#tag>li:hover>button { color:#ffa7bf; } +#tag>li>a { font-size:12px; color: #555; display: block; } +#tag>li>a>i { padding:0 3px } + + +/* 主题标签 ( 动态组件 ) */ +#tag-add { display: none; margin-bottom: 3rem; text-align: center } +#tag-add h5,#tag-add h5 a { font-size: 1rem; color:#555; } +#tag-add input,#tag-add button { margin:0; border:none; background:#f1f1f1; line-height:32px; font-size:.8rem; color:#555; padding:0 .8rem; } +#tag-add input { border-radius:3px 0 0 3px; outline: none; -webkit-tap-highlight-color: rgba(0,0,0,0); } +#tag-add button { border-radius:0 3px 3px 0; outline: none; -webkit-tap-highlight-color: rgba(0,0,0,0); } +#tag-add input::placeholder { color: #bbb; font-size: .8rem; } +#tag-add input:hover, #tag-add button:hover, #tag-add input:focus,#tag-add button:focus { color: #ffa7bf; background:#fff; } + + +/* 主题关联 ( 或考虑取消 ) */ +#tagPush { padding:0px; margin:20px 0; border-radius: 5px; list-style-type: none; } +#tagPush>li { /*float: left; width:25%;*/ border-radius:3px; margin:0; padding:8px; } +#tagPush>li>a { color:#555; display:block; overflow: hidden; text-overflow:ellipsis; white-space: nowrap; } +#tagPush>li>a>img { width: 100%; border:none; border-radius:4px; } +#tagPush>li:hover { background: rgba(50,100,100,.1) } + + + +/* 标签云 ( 边缘色 e5e9ef, 底色 f5f5f5 ) */ +#taghot { padding:1rem; } +#taghot h5 { color:#999; font-size: 1rem } +#taghot ul { padding: 0.5rem 0; margin: 0; list-style-type: none;} +#taghot ul li { margin:0 0.3rem 0.3rem 0; float: left; border:1px solid #f1f1f1; border-radius:4px; background:#f1f1f1; } +#taghot ul li a { font-size:12px; color: #555; display: block; padding:0 0.5rem;} +#taghot h5:hover { color:#ffa7bf; } +#taghot ul li:hover { border:1px solid #ffe7ff; background:#fff; } +#taghot ul li:hover a { color: #ffa7bf; } + + + +/* 作者相关 */ +#other { padding:1rem; } +#other h5 { color:#999; font-size: 1rem } +#other ul { padding: 0.5rem 0; margin: 0; list-style-type: none;} +#other ul li { margin:0 0.3rem; padding:.5rem 0; border-bottom: 1px solid #f1f1f1; border-radius:4px } +#other ul li a { font-size:12px; color: #555; display: block; padding:0 0.5rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;} +#other h5:hover { color:#ffa7bf; } +#other ul li:hover { background:#fff; } +#other ul li:hover a { color: #ffa7bf;} +#other ul li:last-child { border-bottom: none } diff --git a/git_tags/view/htm/inc_cloud.htm b/git_tags/view/htm/inc_cloud.htm new file mode 100644 index 0000000..1ce7828 --- /dev/null +++ b/git_tags/view/htm/inc_cloud.htm @@ -0,0 +1,16 @@ +-1), 1, 20); + cache_set('tagCloud', $tagCloud, 600); +} +?> +
+
TAG
+ +
diff --git a/git_tags/view/htm/inc_other.htm b/git_tags/view/htm/inc_other.htm new file mode 100644 index 0000000..6634e08 --- /dev/null +++ b/git_tags/view/htm/inc_other.htm @@ -0,0 +1,9 @@ +$thread['uid']), array('lastpid'=>-1),1,6); ?> +
+
作者主题
+ +
\ No newline at end of file diff --git a/git_tags/view/htm/inc_push.htm b/git_tags/view/htm/inc_push.htm new file mode 100644 index 0000000..01f9e3f --- /dev/null +++ b/git_tags/view/htm/inc_push.htm @@ -0,0 +1,7 @@ + + + diff --git a/git_tags/view/htm/inc_tag.htm b/git_tags/view/htm/inc_tag.htm new file mode 100644 index 0000000..2faabd1 --- /dev/null +++ b/git_tags/view/htm/inc_tag.htm @@ -0,0 +1,5 @@ + diff --git a/git_tags/view/htm/tag.htm b/git_tags/view/htm/tag.htm new file mode 100644 index 0000000..364fe56 --- /dev/null +++ b/git_tags/view/htm/tag.htm @@ -0,0 +1,60 @@ + + + + +
+ +
+ +
+
+ +
+
+ + +
+ + +
+ + + + + + +
+
+ + + + diff --git a/git_tags/view/img/user_last.png b/git_tags/view/img/user_last.png new file mode 100644 index 0000000..a80d0db Binary files /dev/null and b/git_tags/view/img/user_last.png differ diff --git a/git_tags/view/img/user_none.png b/git_tags/view/img/user_none.png new file mode 100644 index 0000000..eeb575d Binary files /dev/null and b/git_tags/view/img/user_none.png differ diff --git a/git_tags/view/img/user_shitou.png b/git_tags/view/img/user_shitou.png new file mode 100644 index 0000000..be2d5d2 Binary files /dev/null and b/git_tags/view/img/user_shitou.png differ diff --git a/git_tags/view/img/user_soyoumi.png b/git_tags/view/img/user_soyoumi.png new file mode 100644 index 0000000..3222ad3 Binary files /dev/null and b/git_tags/view/img/user_soyoumi.png differ diff --git a/git_tags/view/js/tag.js b/git_tags/view/js/tag.js new file mode 100644 index 0000000..8d8bbb9 --- /dev/null +++ b/git_tags/view/js/tag.js @@ -0,0 +1,209 @@ +// 定义输入框的全局变量 #tag-add, 0 为隐藏状态, 1 为显示状态 +var tag_dis = 0 + + + +/*---------------------------------------- +| +| 初始化时添加组建 (显示的) +| 初始化时添加组件 (隐藏的) +| 增加标签按钮 +| 删除标签按钮 +| +---------------------------------------- */ + +$('#tag').append( '
  • ' ) +$('#tag').after( + '
    '+ + '
    '+ + //'
    添加标签
    '+ + ''+ + '
    '+ + '
    ' +) + + + +/*---------------------------------------- +| +| 监听 #tag-add 显示与隐藏的开关 #tagRes +| 根据全局变量转变 标签图标 +| 根据全局变量转变 #tag-add 的显隐状态 +| +----------------------------------------*/ + + $(document).on('click', '#tagRes', function() { + if(tag_dis==0){ + $("#tag li i").removeClass("icon-tag"); + $("#tag li i").addClass("icon-times-circle"); + $("#tag-add").fadeToggle("slow"); + $("#tag-data").focus(); + tag_dis = 1 + }else{ + $("#tag li i").removeClass("icon-times-circle"); + $("#tag li i").addClass("icon-tag"); + $("#tag-add").fadeToggle("slow"); + tag_dis = 0 + } + }) + + + +/*---------------------------------------- +| +| delete +| +----------------------------------------*/ + +$(document).on('click', '#tag li a', function() { + if(tag_dis==1){ + var t = $(this).parent() // this不能直接传递 + var tid = $('#tag').data('tid') + var tag = $(this).parent().data('tag') + var url = 'tag-del.htm' + if (location.search.indexOf("?") != -1) { url = '?tag-del.htm' } + $.xpost(url, {'tid': tid, 'tag': tag }, function(code,msg){ + if (code == 0) { + // 删除成功则移除此标签 + t.remove() + } else { + alert(msg) + } + }) + return false + } +}) + + + +/*---------------------------------------- +| +| add tag ( Allow Space ) +| +----------------------------------------*/ + +$(document).on('click', '#tag-add button', function() { + var r = $('#tag-data').val() + var tid = $('#tag').attr('data-tid') + if (安检(r)){ + var url = 'tag-add.htm' + if (location.search.indexOf("?") != -1) { url = '?tag-add.htm' } + $.xpost(url, {'tid': tid, 'tag': r.trim() }, function(code,msg){ + if (code == 1) { + if ( $("#tag li[data-tag='"+msg+"']").length > 0 ) { + //alert(tag+'标签已存在') + return false + } + // 先移除结尾的元素, 增加完毕再添加结尾的元素 + $("#tag li:last").remove() + $("#tag").append('
  • '+r+'
  • ') + $('#tag').append('
  • ') + + // 关闭组件 并切回tag状态 + $("#tag-add").fadeOut("slow"); + $("#tag li i").removeClass("icon-times-circle"); + $("#tag li i").addClass("icon-tag"); + $("#tagRes").focus(); + + tag_dis = 0 + $("#tag-data").val("") + } else { + alert(msg) + } + }) + } + return false +}) + + + +/*---------------------------------------- +| +| 封装整理 +| +----------------------------------------*/ + +function 安检(r){ + var q = $('#tag').children('li').length + if(q > 12){ + 提示('标签最多设置12个') + return false + } + + if(r==null||r.length==0){ + 提示('你明明什么都没写..') + return false + } + + if( 检查字符长度(r) ){ + 提示('中文字数 1-8 个, 英文2-24个 ') + return false + } + + if( 检查特殊字符(r) ){ + 提示('不可使用特殊字符') + return false + } + + if( 检查重复标签(r) ){ + 提示('标签已存在') + return false + } + + // 重复检查( 前端检查 ) + + return true +} + + + +function 检查重复标签(r){ + // 服务端也需要判断一遍, 或许本地可以省略.. + return false +} + + +function 检查特殊字符(r){ + // 特殊符号不可使用 (各种空格与危险字符/但英文空格是允许的) + var a = new Array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "{", "}", "[", "]", "(", ")") + a.push(":", ";", "'", "|", "\\\\", "<", ">", "?", "/", "<<", ">>", "||", "//", " ", ",", ".") + a.push("select", "delete", "update", "insert", "create", "drop", "alter", "trancate") + var s = r.toLowerCase(); + for (var i = 0; i < a.length; i++) { + if (s.indexOf(a[i]) >= 0) { + return true + } + } + return false +} + + +function 检查字符长度(str){ + // UTF8字符集实际长度计算 + var realLength = 0 + var len = str.length + var charCode = -1 + for(var i = 0; i < len; i++){ + charCode = str.charCodeAt(i) + if (charCode >= 0 && charCode <= 128) { + realLength += 1 + }else{ + // 中文则长度加3 + realLength += 3 + } + } + if( realLength>24 || realLength<2 ){ + return true + } + return false +} + + + +function 提示(r){ + var timestamp = (new Date()).valueOf() + $("#tag-add").after(''); + setTimeout(function () { $("#t"+timestamp).hide(1000) }, 4000) + setTimeout(function () { $("#t"+timestamp).remove() }, 5000) + +}