pull/1/head
rekoe 2016-03-23 11:35:44 +08:00
parent f8549200e2
commit 76d376e01e
22 changed files with 1227 additions and 6 deletions

View File

@ -10,6 +10,7 @@ import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
@ -28,8 +29,10 @@ import org.nutz.plugins.view.freemarker.FreemarkerView;
import org.nutz.web.Webs;
import com.rekoe.domain.User;
import com.rekoe.domain.Usr;
import com.rekoe.exception.IncorrectCaptchaException;
import com.rekoe.filter.AuthenticationFilter;
import com.rekoe.service.UsrService;
/**
* @author ²º¹³<br />
@ -44,6 +47,9 @@ public class AdminLoginAct {
@Inject
private FreeMarkerConfigurer freeMarkerConfigurer;
@Inject
private UsrService usrService;
@At
@Filters(@By(type = AuthenticationFilter.class))
public View login(@Attr("loginToken") AuthenticationToken token, HttpSession session, HttpServletRequest req) {
@ -51,6 +57,10 @@ public class AdminLoginAct {
Subject subject = SecurityUtils.getSubject();
ThreadContext.bind(subject);
subject.login(token);
Usr usr = usrService.fetch(Cnd.where("usr", "=", "admin"));
if (!Lang.isEmpty(usr)) {
session.setAttribute("usr", usr);
}
session.setAttribute(Webs.ME, subject.getPrincipal());
return new ServerRedirectView("/admin/main.rk");
} catch (IncorrectCaptchaException e) {

View File

@ -1,8 +1,14 @@
package com.rekoe.module.admin;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
@ -13,25 +19,31 @@ import com.rekoe.annotation.PermissionTag;
import com.rekoe.common.Message;
import com.rekoe.common.page.Pagination;
import com.rekoe.domain.Pj;
import com.rekoe.domain.PjAuth;
import com.rekoe.module.BaseAction;
import com.rekoe.service.ProjectAuthService;
import com.rekoe.service.ProjectGroupService;
import com.rekoe.service.ProjectService;
import com.rekoe.service.RepositoryService;
import com.rekoe.service.UsrService;
import com.rekoe.utils.UsrProvider;
@IocBean
@At("/admin/project")
public class AdminProjectAct extends BaseAction{
public class AdminProjectAct extends BaseAction {
@Inject
private ProjectService projectService;
@At
@Ok("fm:template.admin.project.list")
@RequiresPermissions({ "svn.project:view" })
@PermissionTag(name = "SVN浏览项目", tag = "SVN项目管理")
public Pagination list(@Param(value = "pageNumber", df = "1") int page) {
System.out.println(UsrProvider.getCurrentUsr());
return projectService.getObjListByPager(page, 20, null);
}
@At
@Ok("fm:template.admin.project.add")
@RequiresPermissions({ "svn.project:add" })
@ -51,4 +63,74 @@ public class AdminProjectAct extends BaseAction{
}
return Message.error("error", req);
}
@Inject
private RepositoryService repositoryService;
@At
@Ok("fm:template.admin.project.rep")
@RequiresPermissions({ "svn.project:view" })
public String rep(@Param("pj") String pj, HttpServletRequest req) {
Pj project = projectService.fetch(Cnd.where("pj", "=", pj));
String root = repositoryService.getRepositoryRoot(project);
String svnUrl = RepositoryService.parseURL(project.getUrl());
String path = "/";
if (root != null) {
try {
root = URLDecoder.decode(root, "UTF-8");// @see issue 34
} catch (UnsupportedEncodingException e) {
}
if (svnUrl.indexOf(root) != -1) {
path = StringUtils.substringAfter(svnUrl, root);
if (!path.startsWith("/")) {
path = "/" + path;
}
}
} else {
root = svnUrl;
}
req.setAttribute("root", root);
req.setAttribute("path", path);
req.setAttribute("pj", pj);
return pj;
}
@Inject
private ProjectAuthService projectAuthService;
@Inject
private ProjectGroupService projectGroupService;
@Inject
private UsrService usrService;
@At
@Ok("fm:template.admin.project.pjauth")
@RequiresPermissions({ "svn.project:view" })
public String pjauth(@Param("pj") String pj, @Param("res") String res, HttpServletRequest req) {
PjAuth entity = (PjAuth) req.getAttribute("entity");
if (entity == null) {
entity = new PjAuth();
entity.setPj(pj);
entity.setRes("");
entity.setRw("");
req.setAttribute("entity", entity);
}
if (StringUtils.isBlank(res)) {
String path = req.getParameter("path");
if (StringUtils.isNotBlank(path)) {
res = this.projectAuthService.formatRes(pj, path);
}
} else {
res = entity.getRes();
}
entity.setRes(res);
List<PjAuth> list = projectAuthService.list(pj, res);
req.setAttribute("list", list);
req.setAttribute("pj", pj);
req.setAttribute("pjreslist", projectAuthService.getResList(pj));
req.setAttribute("pjgrlist",projectGroupService.getList(pj));
req.setAttribute("usrList", usrService.getList());
return pj;
}
}

View File

@ -46,7 +46,7 @@ public class ProjectAuthService extends BaseService<PjAuth> {
* @return
*/
public List<String> getResList(String pj) {
Sql sql = Sqls.create("select distinct res from pj_gr_auth where pj=? UNION select distinct res from pj_usr_auth where pj=@pj order by res");
Sql sql = Sqls.create("select distinct res from pj_gr_auth where pj=@pj UNION select distinct res from pj_usr_auth where pj=@pj order by res");
sql.setCallback(Sqls.callback.strList());
sql.setParam("pj", pj);
dao().execute(sql);

View File

@ -1,8 +1,17 @@
package com.rekoe.service;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.SqlCallback;
import org.nutz.ioc.loader.annotation.IocBean;
import com.rekoe.domain.PjGr;
@ -31,4 +40,29 @@ public class ProjectGroupService extends BaseService<PjGr> {
dao().update(getEntityClass(), Chain.make("des", pjGr.getDes()), Cnd.where("pj", "=", pjGr.getPj()).and("gr", "=", pjGr.getGr()));
}
}
public List<PjGr> getList(String pj) {
Sql sql = Sqls.create("select pj,gr,des from pj_gr $condition");
sql.setCondition(Cnd.where("pj", "=", pj).desc("pj,gr"));
final List<PjGr> list = new ArrayList<PjGr>();
sql.setCallback(new SqlCallback() {
@Override
public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
while (rs.next()) {
list.add(readPjGr(rs));
}
return list;
}
});
return list;
}
PjGr readPjGr(ResultSet rs) throws SQLException {
PjGr result = new PjGr();
result.setPj(rs.getString("pj"));
result.setGr(rs.getString("gr"));
result.setDes(rs.getString("des"));
return result;
}
}

View File

@ -27,6 +27,13 @@ public class UsrService extends BaseService<Usr> {
super(dao);
}
/**
* @return
*/
public List<Usr> getList() {
return dao().query(getEntityClass(), null);
}
/**
* @param pj
*

View File

@ -3,6 +3,8 @@
*/
package com.rekoe.utils;
import org.nutz.mvc.Mvcs;
import com.rekoe.domain.Usr;
/**
@ -17,7 +19,7 @@ public class UsrProvider {
* @return
*/
public static Usr getCurrentUsr() {
Usr usr = USR_THREAD_LOCAL.get();
Usr usr = (Usr)Mvcs.getReq().getSession().getAttribute("usr");
if (usr == null) {
throw new RuntimeException("当前线程没有设置用户!");
}

View File

@ -25,7 +25,7 @@ function getTableForm() {
<@p.column title="ID" align="center">${i+1}</@p.column><#t/>
<@p.column title="姓名" align="center">${user.pj}</@p.column><#t/>
<@p.column title="路径" align="center">${user.path}</@p.column><#t/>
<@p.column title="URL" align="center">${user.url}</@p.column><#t/>
<@p.column title="URL" align="center"><a href="rep?pj=${user.pj}">${user.url}</a></@p.column><#t/>
<@p.column title="类型" align="center">${user.type}</@p.column><#t/>
<@p.column title="描述" align="center">${user.des}</@p.column><#t/>
<@p.column title="设置用户组" align="center">设置用户组</@p.column><#t/>

View File

@ -0,0 +1,206 @@
<html>
<head>
<script src="${base}/resources/jquery-1.7.min.js" type="text/javascript"></script>
<script src="${base}/resources/sorttable.js"></script>
<script src="${base}/resources/svnadmin.js"></script>
<link rel="stylesheet" href="${base}/resources/svnadmin.css" />
<script>
$(function(){
//移到用户组右边
$('#group_add').click(function() {
//获取选中的选项,删除并追加给对方
$('#select3 option:selected').appendTo('#select4');
});
//移到用户组左边
$('#group_del').click(function() {
$('#select4 option:selected').appendTo('#select3');
});
//全部移到用户组右边
$('#group_add_all').click(function() {
//获取全部的选项,删除并追加给对方
$('#select3 option').appendTo('#select4');
});
//全部移到用户组左边
$('#group_del_all').click(function() {
$('#select4 option').appendTo('#select3');
});
//移到用户右边
$('#user_add').click(function() {
//获取选中的选项,删除并追加给对方
$('#select1 option:selected').appendTo('#select2');
});
//移到用户左边
$('#user_del').click(function() {
$('#select2 option:selected').appendTo('#select1');
});
//全部移到用户右边
$('#user_add_all').click(function() {
//获取全部的选项,删除并追加给对方
$('#select1 option').appendTo('#select2');
});
//全部移到用户左边
$('#user_del_all').click(function() {
$('#select2 option').appendTo('#select1');
});
//双击选项
$('#select1').dblclick(function(){ //绑定双击事件
//获取全部的选项,删除并追加给对方
$("option:selected",this).appendTo('#select2'); //追加给对方
});
//双击选项
$('#select2').dblclick(function(){
$("option:selected",this).appendTo('#select1');
});
//双击选项
$('#select3').dblclick(function(){ //绑定双击事件
//获取全部的选项,删除并追加给对方
$("option:selected",this).appendTo('#select4'); //追加给对方
});
//双击选项
$('#select4').dblclick(function(){
$("option:selected",this).appendTo('#select3');
});
});
function checkForm(f){
if(f.elements["pj"].value==""){
alert("项目不可以为空");
f.elements["pj"].focus();
return false;
}
if(f.elements["res"].value==""){
alert("资源不可以为空");
f.elements["res"].focus();
return false;
}
if(f.elements["grs"].value=="" && f.elements["usrs"].value==""){
alert("请选择用户组或用户");
f.elements["grs"].focus();
return false;
}
return true;
}
</script>
</head>
<body style="margin: 0px;">
<#assign errorMsg="">
<#if errorMsg?exists>
<div style="color:red;">错误 ${errorMsg}</div>
</#if>
<form name="pjauth" action="${base}/pjauth" method="post" onsubmit="return checkForm(this);">
<input type="hidden" name="act" value="save">
<input type="hidden" name="pj" value="${pj}">
<table class="table table-striped table-bordered">
<tr>
<td class="lbl">资源</td>
<td colspan="3">
<input type="text" name="res" value="${entity.res!""}" style="width:400px;"><span style="color:red;">*</span>
<select onchange="this.form.res.value=this.value">
<option value="">选择资源</option>
<#list pjreslist as pjre>
<option value="${pjre}">${pjre}</option>
</#list>
</select>
</td>
</tr>
<tr>
<td class="lbl">用户组</td>
<td valign="top">
<table>
<tr>
<td style="border:0px;">
<select id="select3" multiple="multiple" style="height: 150px;width: 150px;">
<#list pjgrlist as pjGr>
<option value="${pjGr.gr}">${pjGr.gr}</option>
</#list>
</select>
</td>
<td style="border:0px;">
<input id="group_add" type="button" style="width:30px;" value="&gt;"><br>
<input id="group_add_all" type="button" style="width:30px;" value="&gt;&gt;"><br><br>
<input id="group_del" type="button" style="width:30px;" value="&lt;"><br>
<input id="group_del_all" type="button" style="width:30px;" value="&lt;&lt;"><br><br>
</td>
<td style="border:0px;">
<select id="select4" name="grs" multiple="multiple" style="height: 150px;width: 150px;">
</select>
</td>
</tr>
</table>
</td>
<td class="lbl">用户</td>
<td valign="top">
<table>
<tr>
<td style="border:0px;">
<select id="select1" multiple="multiple" style="height: 150px;width: 160px;">
<#list usrList as usr>
<option value="${usr.usr}">${usr.name!usr.usr}(${usr.usr})</option>
</#list>
</select>
</td>
<td style="border:0px;">
<input id="user_add" type="button" style="width:30px;" value="&gt;"><br>
<input id="user_add_all" type="button" style="width:30px;" value="&gt;&gt;"><br><br>
<input id="user_del" type="button" style="width:30px;" value="&lt;"><br>
<input id="user_del_all" type="button" style="width:30px;" value="&lt;&lt;"><br><br>
</td>
<td style="border:0px;">
<select id="select2" name="usrs" multiple="multiple" style="height: 150px;width: 160px;">
</select>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="lbl">权限</td>
<td colspan="3">
<select name="rw">
<option value="rw" <#if entity.rw == "rw">selected='selected'</#if>>可读可写</option>
<option value="" <#if entity.rw == "">selected='selected'</#if>>没有权限</option>
<option value="r"<#if entity.rw == "r">selected='selected'</#if>>可读</option>
</select>
</td>
</tr>
<tr>
<td colspan="4" align="center" style="text-align: center;">
<input type="submit" class="btn btn-primary" value="保存">
</td>
</tr>
</table>
</form>
<table class="table table-striped table-bordered">
<thead>
<td>NO.</td>
<td>项目</td>
<td>资源</td>
<td>用户组/用户</td>
<td>权限</td>
<td>删除</td>
</thead>
<#list list as pjAuth>
<tr>
<td>${pjAuth_index +1}</td>
<td>${pjAuth.pj}</td>
<td>${pjAuth.res}</td>
<td>${pjAuth.gr!""}${pjAuth.usr!pjAuth.usrName}:(${pjAuth.usr})</td>
<td>
<#if "r"== pjAuth.rw>
可读
<#elseif "rw"== pjAuth.rw>
可读可写
<#else>
没有权限
</#if>
</td>
<td>
<a href="javascript:if(confirm('确认删除?')){del('${base}/pjauth?pj=${pjAuth.pj}&res=${pjAuth.res}&gr=${pjAuth.gr}&usr=${pjAuth.usr}')}">删除</a>
</td>
</tr>
</#list>
</table>
</body>
</html>

View File

@ -0,0 +1,85 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title></title>
<#include "/template/admin/head.ftl"/>
<span style="color:green;font-weight:bold;"><a href="${base}/pj">项目管理(${pj})</a> | 权限管理</span><br><br>
<script type="text/javascript" src="${base}/resources/treeview/treeview.js"></script>
<link type="text/css" rel="stylesheet" href="${base}/resources/treeview/treeview.css"></link>
<style>
#svnroot li{
line-height: 11px;
}
#svnroot span{
line-height: 11px;
}
</style>
<script type="text/javascript">
AjaxTreeView.config.onclick=function(o,a){
var p=o.getAttribute("param");
if(p==null)p="";
var url="pjauth";
if(url!=""){
if(p!=""){
if(url.indexOf("?")>0){
url=url+"&"+p;
}else{
url=url+"?"+p;
}
}
//alert(url);
go(url,"pjauthWindow");
return false;
}
};
$(document).ready(function (){
AjaxTreeView.open(document.getElementById("svnroot"));
$('#path').bind('keyup', function(event){
if (event.keyCode=="13"){
freshTree();
}
});
});
function freshTree(){
var $p = $("#path");
var p = $p.val();
if(p==""){
p="/";
$p.val(p);
}else if(p.substring(0,1)!="/"){
p = "/"+p;
$p.val(p);
}
var $r = $("#svnroot");
$r.children("ul").first().remove();
$("#rootlink").text("${root}"+p);
AjaxTreeView.close($r[0]);
$r.attr("param","pj=${pj}&path="+p);
$r[0].loading = false;
$r[0].loaded = false;
AjaxTreeView.open($r[0]);
}
</script>
<table style="width:100%;height:80%;" class="table table-striped table-bordered">
<tr>
<td valign="top" style="width:300px;">
<input type="text" style="width:210px;" id="path" value="${path}"> <input onclick="freshTree();" class="btn btn-primary" type="button" value="刷新">
<div class="filetree treeview" style="width:300px;height:500px;overflow: auto;">
<ul>
<li id="svnroot" class="closed lastclosed" treeId="rep" param="pj=${pj}&path=${path}">
<div class="hit closed-hit lastclosed-hit" onclick='$att(this);'></div>
<span class="folder" onclick='$att(this);'>
<a id="rootlink" href='javascript:void(0);' onclick='$atc(this)'>${root}${path}</a>
</span>
</li>
</ul>
</div>
</td>
<td valign="top" height="100%">
<iframe height="100%" width="100%" style="border:0px;" frameBorder="0" name="pjauthWindow" src="pjauth?pj=${pj}"></iframe>
</td>
</tr>
</table>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,520 @@
/*
SortTable
version 2
7th April 2007
Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
Instructions:
Download this file
Add <script src="sorttable.js"></script> to your HTML
Add class="sortable" to any table you'd like to make sortable
Click on the headers to sort
Thanks to many, many people for contributions and suggestions.
Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
This basically means: do what you want with it.
*/
var stIsIE = /*@cc_on!@*/false;
sorttable = {
init: function() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
if (!document.createElement || !document.getElementsByTagName) return;
sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
forEach(document.getElementsByTagName('table'), function(table) {
if (table.className.search(/\bsortable\b/) != -1) {
sorttable.makeSortable(table);
sorttable.makeHightlightTable(table.tBodies[0]);//by Harvey 2011-09-03
sorttable.addHeadTitle(table);//by Harvey 2011-09-17
}
});
},
//by Harvey 2011-09-03
makeHightlightTable:function(tbody){
for (var i=0; i<tbody.rows.length; i++) {
tbody.rows[i]._sorttable_cls=tbody.rows[i].className=(i%2==0)?"even":"odd";
dean_addEvent(tbody.rows[i],"mouseover", function(e) {
this.className="over";
});
dean_addEvent(tbody.rows[i],"mouseout", function(e) {
this.className=this._sorttable_cls;
});
}
},
addHeadTitle:function(table){
// Safari doesn't support table.tHead, sigh
if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
if (table.tHead.rows.length != 1) return; // can't cope with two header rows
headrow = table.tHead.rows[0].cells;
for (var i=0; i<headrow.length; i++) {
text = sorttable.getInnerText(headrow[i]);
if(text == null){
text = "";
}
headrow[i].title="Sort "+ text;
}
},
//end by Harvey 2011-09-03
makeSortable: function(table) {
if (table.getElementsByTagName('thead').length == 0) {
// table doesn't have a tHead. Since it should have, create one and
// put the first table row in it.
the = document.createElement('thead');
the.appendChild(table.rows[0]);
table.insertBefore(the,table.firstChild);
}
// Safari doesn't support table.tHead, sigh
if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
if (table.tHead.rows.length != 1) return; // can't cope with two header rows
// Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
// "total" rows, for example). This is B&R, since what you're supposed
// to do is put them in a tfoot. So, if there are sortbottom rows,
// for backwards compatibility, move them to tfoot (creating it if needed).
sortbottomrows = [];
for (var i=0; i<table.rows.length; i++) {
if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
sortbottomrows[sortbottomrows.length] = table.rows[i];
}
}
if (sortbottomrows) {
if (table.tFoot == null) {
// table doesn't have a tfoot. Create one.
tfo = document.createElement('tfoot');
table.appendChild(tfo);
}
for (var i=0; i<sortbottomrows.length; i++) {
tfo.appendChild(sortbottomrows[i]);
}
delete sortbottomrows;
}
// work through each column and calculate its type
headrow = table.tHead.rows[0].cells;
for (var i=0; i<headrow.length; i++) {
// manually override the type with a sorttable_type attribute
if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
if (mtch) { override = mtch[1]; }
if (mtch && typeof sorttable["sort_"+override] == 'function') {
headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
} else {
headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
}
// make it clickable to sort
headrow[i].sorttable_columnindex = i;
headrow[i].sorttable_tbody = table.tBodies[0];
dean_addEvent(headrow[i],"click", function(e) {
if (this.className.search(/\bsorttable_sorted\b/) != -1) {
// if we're already sorted by this column, just
// reverse the table, which is quicker
sorttable.reverse(this.sorttable_tbody);
this.className = this.className.replace('sorttable_sorted',
'sorttable_sorted_reverse');
this.removeChild(document.getElementById('sorttable_sortfwdind'));
sortrevind = document.createElement('span');
sortrevind.id = "sorttable_sortrevind";
sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
this.appendChild(sortrevind);
return;
}
if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
// if we're already sorted by this column in reverse, just
// re-reverse the table, which is quicker
sorttable.reverse(this.sorttable_tbody);
this.className = this.className.replace('sorttable_sorted_reverse',
'sorttable_sorted');
this.removeChild(document.getElementById('sorttable_sortrevind'));
sortfwdind = document.createElement('span');
sortfwdind.id = "sorttable_sortfwdind";
sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
this.appendChild(sortfwdind);
return;
}
// remove sorttable_sorted classes
theadrow = this.parentNode;
forEach(theadrow.childNodes, function(cell) {
if (cell.nodeType == 1) { // an element
cell.className = cell.className.replace('sorttable_sorted_reverse','');
cell.className = cell.className.replace('sorttable_sorted','');
}
});
sortfwdind = document.getElementById('sorttable_sortfwdind');
if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
sortrevind = document.getElementById('sorttable_sortrevind');
if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
this.className += ' sorttable_sorted';
sortfwdind = document.createElement('span');
sortfwdind.id = "sorttable_sortfwdind";
sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
this.appendChild(sortfwdind);
// build an array to sort. This is a Schwartzian transform thing,
// i.e., we "decorate" each row with the actual sort key,
// sort based on the sort keys, and then put the rows back in order
// which is a lot faster because you only do getInnerText once per row
row_array = [];
col = this.sorttable_columnindex;
rows = this.sorttable_tbody.rows;
for (var j=0; j<rows.length; j++) {
row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
}
/* If you want a stable sort, uncomment the following line */
//sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
/* and comment out this one */
row_array.sort(this.sorttable_sortfunction);
tb = this.sorttable_tbody;
for (var j=0; j<row_array.length; j++) {
tb.appendChild(row_array[j][1]);
}
delete row_array;
});
}
}
},
guessType: function(table, column) {
// guess the type of a column based on its first non-blank row
sortfn = sorttable.sort_alpha;
for (var i=0; i<table.tBodies[0].rows.length; i++) {
text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
if (text != '') {
if (text.match(/^-?[?<3F>]?[\d,.]+%?$/)) {
return sorttable.sort_numeric;
}
// check for a date: dd/mm/yyyy or dd/mm/yy
// can have / or . or - as separator
// can be mm/dd as well
possdate = text.match(sorttable.DATE_RE)
if (possdate) {
// looks like a date
first = parseInt(possdate[1]);
second = parseInt(possdate[2]);
if (first > 12) {
// definitely dd/mm
return sorttable.sort_ddmm;
} else if (second > 12) {
return sorttable.sort_mmdd;
} else {
// looks like a date, but we can't tell which, so assume
// that it's dd/mm (English imperialism!) and keep looking
sortfn = sorttable.sort_ddmm;
}
}
}
}
return sortfn;
},
getInnerText: function(node) {
// gets the text we want to use for sorting for a cell.
// strips leading and trailing whitespace.
// this is *not* a generic getInnerText function; it's special to sorttable.
// for example, you can override the cell text with a customkey attribute.
// it also gets .value for <input> fields.
hasInputs = (typeof node.getElementsByTagName == 'function') &&
node.getElementsByTagName('input').length;
if (node.getAttribute("sorttable_customkey") != null) {
return node.getAttribute("sorttable_customkey");
}
else if (typeof node.textContent != 'undefined' && !hasInputs) {
return node.textContent.replace(/^\s+|\s+$/g, '');
}
else if (typeof node.innerText != 'undefined' && !hasInputs) {
return node.innerText.replace(/^\s+|\s+$/g, '');
}
else if (typeof node.text != 'undefined' && !hasInputs) {
return node.text.replace(/^\s+|\s+$/g, '');
}
else {
switch (node.nodeType) {
case 3:
if (node.nodeName.toLowerCase() == 'input') {
return node.value.replace(/^\s+|\s+$/g, '');
}
case 4:
return node.nodeValue.replace(/^\s+|\s+$/g, '');
break;
case 1:
case 11:
var innerText = '';
for (var i = 0; i < node.childNodes.length; i++) {
innerText += sorttable.getInnerText(node.childNodes[i]);
}
return innerText.replace(/^\s+|\s+$/g, '');
break;
default:
return '';
}
}
},
reverse: function(tbody) {
// reverse the rows in a tbody
newrows = [];
for (var i=0; i<tbody.rows.length; i++) {
newrows[newrows.length] = tbody.rows[i];
}
for (var i=newrows.length-1; i>=0; i--) {
tbody.appendChild(newrows[i]);
}
delete newrows;
},
/* sort functions
each sort function takes two parameters, a and b
you are comparing a[0] and b[0] */
sort_numeric: function(a,b) {
aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
if (isNaN(aa)) aa = 0;
bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
if (isNaN(bb)) bb = 0;
return aa-bb;
},
sort_alpha: function(a,b) {
if (a[0]==b[0]) return 0;
if (a[0]<b[0]) return -1;
return 1;
},
sort_ddmm: function(a,b) {
mtch = a[0].match(sorttable.DATE_RE);
y = mtch[3]; m = mtch[2]; d = mtch[1];
if (m.length == 1) m = '0'+m;
if (d.length == 1) d = '0'+d;
dt1 = y+m+d;
mtch = b[0].match(sorttable.DATE_RE);
y = mtch[3]; m = mtch[2]; d = mtch[1];
if (m.length == 1) m = '0'+m;
if (d.length == 1) d = '0'+d;
dt2 = y+m+d;
if (dt1==dt2) return 0;
if (dt1<dt2) return -1;
return 1;
},
sort_mmdd: function(a,b) {
mtch = a[0].match(sorttable.DATE_RE);
y = mtch[3]; d = mtch[2]; m = mtch[1];
if (m.length == 1) m = '0'+m;
if (d.length == 1) d = '0'+d;
dt1 = y+m+d;
mtch = b[0].match(sorttable.DATE_RE);
y = mtch[3]; d = mtch[2]; m = mtch[1];
if (m.length == 1) m = '0'+m;
if (d.length == 1) d = '0'+d;
dt2 = y+m+d;
if (dt1==dt2) return 0;
if (dt1<dt2) return -1;
return 1;
},
shaker_sort: function(list, comp_func) {
// A stable sort function to allow multi-level sorting of data
// see: http://en.wikipedia.org/wiki/Cocktail_sort
// thanks to Joseph Nahmias
var b = 0;
var t = list.length - 1;
var swap = true;
while(swap) {
swap = false;
for(var i = b; i < t; ++i) {
if ( comp_func(list[i], list[i+1]) > 0 ) {
var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
swap = true;
}
} // for
t--;
if (!swap) break;
for(var i = t; i > b; --i) {
if ( comp_func(list[i], list[i-1]) < 0 ) {
var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
swap = true;
}
} // for
b++;
} // while(swap)
}
}
/* ******************************************************************
Supporting functions: bundled here to avoid depending on a library
****************************************************************** */
// Dean Edwards/Matthias Miller/John Resig
/* for Mozilla/Opera9 */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", sorttable.init, false);
}
/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
sorttable.init(); // call the onload handler
}
};
/*@end @*/
/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
sorttable.init(); // call the onload handler
}
}, 10);
}
/* for other browsers */
window.onload = sorttable.init;
// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/
function dean_addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
// assign each event handler a unique ID
if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
// create a hash table of event types for the element
if (!element.events) element.events = {};
// create a hash table of event handlers for each element/event pair
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// store the existing event handler (if there is one)
if (element["on" + type]) {
handlers[0] = element["on" + type];
}
}
// store the event handler in the hash table
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work
element["on" + type] = handleEvent;
}
};
// a counter used to create unique IDs
dean_addEvent.guid = 1;
function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
};
function handleEvent(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
// get a reference to the hash table of event handlers
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};
function fixEvent(event) {
// add W3C standard event methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
}
// Dean's forEach: http://dean.edwards.name/base/forEach.js
/*
forEach, version 1.0
Copyright 2006, Dean Edwards
License: http://www.opensource.org/licenses/mit-license.php
*/
// array-like enumeration
if (!Array.forEach) { // mozilla already supports this
Array.forEach = function(array, block, context) {
for (var i = 0; i < array.length; i++) {
block.call(context, array[i], i, array);
}
};
}
// generic enumeration
Function.prototype.forEach = function(object, block, context) {
for (var key in object) {
if (typeof this.prototype[key] == "undefined") {
block.call(context, object[key], key, object);
}
}
};
// character enumeration
String.forEach = function(string, block, context) {
Array.forEach(string.split(""), function(chr, index) {
block.call(context, chr, index, string);
});
};
// globally resolve forEach enumeration
var forEach = function(object, block, context) {
if (object) {
var resolve = Object; // default
if (object instanceof Function) {
// functions have a "length" property
resolve = Function;
} else if (object.forEach instanceof Function) {
// the object implements a custom forEach method so use that
object.forEach(block, context);
return;
} else if (typeof object == "string") {
// the object is a string
resolve = String;
} else if (typeof object.length == "number") {
// the object is array-like
resolve = Array;
}
resolve.forEach(object, block, context);
}
};

View File

@ -0,0 +1,24 @@
table.thinborder {
border-collapse:collapse;
border:solid #999;
border-width:1px 0 0 1px;
}
table.thinborder caption {font-size:14px;font-weight:bolder;}
table.thinborder th,table.thinborder td {
border:solid #999;
border-width:0 1px 1px 0;
padding:2px;
word-break : keep-all;
white-space:nowrap;
}
table.sortablet foot td {text-align:center;background: #ECF20F;}
table.sortable thead td {text-align:center;background: #ECF20F;}
table.sortable tr.odd{background: #ECFCCC;}
table.sortable tr.even{background: #FFFFFF;}
table.sortable tr.over{background: #ECF2AF;}
td.lbl{
text-align: right;
}

View File

@ -0,0 +1,56 @@
function del(act){
var ind = act.indexOf("?");
if(ind == -1){
go(act+"?act=del");
}else{
go(act+"&act=del");
}
}
function go(act,target){
var fm =document.getElementById("goForm");
//clear
var eles = fm.elements;
if(eles != null && eles.length > 0){
for(var i=0;i<eles.length;i++){
fm.removeChild(eles[i]);
i--;
}
}
fm.target = "_self";
//action?a=1&b=2
var ind = act.indexOf("?");
if(ind == -1){
fm.action = act;
}else{
fm.action = act.substring(0,ind);
var parms = act.substring(ind+1);
if(parms !=null && parms.length > 0){
var arr=parms.split("&");
if(arr!=null && arr.length>0){
for(var i=0;i<arr.length;i++){
if(arr[i] == null || arr[i].length == 0){
continue;
}
var pv = arr[i].split("=");
if(pv == null || pv.length==0 || pv[0] == null){
continue;
}
var inp = document.createElement("input");
inp.setAttribute("type","hidden");
inp.setAttribute("name",pv[0]);
if(pv.length == 2){
inp.setAttribute("value",pv[1]);
}
fm.appendChild(inp);
}
}
}
}
//submit
if(target){
fm.target = target;
}
fm.submit();
}
document.write("<form id='goForm' name='goForm' action='#' method='post'></form>");

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,71 @@
.treeview {
font-family: Verdana, helvetica, arial, sans-serif;
font-size: 68.75%;
background: #fff;
color: #333;
}
.treeview, .treeview ul {
padding: 0;
margin: 0;
list-style: none;
}
.treeview ul {
background-color: white;
margin-top: 4px;
}
.treeview .closed ul {display:none;}
.treeview .hit {
background: url(images/treeview-default.gif) -64px -25px no-repeat;
height: 16px;
width: 16px;
margin-left: -16px;
float: left;
cursor: pointer;
}
/* fix for IE6 */
* html .hit {
display: inline;
float:none;
}
.treeview li {
margin: 0;
padding: 3px 0pt 3px 16px;
}
.treeview a.selected {
background-color: #eee;
}
#treecontrol { margin: 1em 0; display: none; }
.treeview .hover { color: red; cursor: pointer; }
.treeview a {background:none;text-decoration:none;color:#000;}
.treeview a:visited {color:#000;}
.treeview li { background: url(images/treeview-default-line.gif) 0 0 no-repeat; }
.treeview li.open, .treeview li.closed { background-position: 0 -176px; }
.treeview .closed-hit { background-position: -80px -3px; }
.treeview li.last { background-position: 0 -1766px }
.treeview li.lastopen, .treeview li.lastclosed { background-image: url(images/treeview-default.gif); }
.treeview li.lastopen { background-position: 0 -111px }
.treeview li.lastclosed { background-position: -32px -67px }
.treeview div.lastopen-hit, .treeview div.lastclosed-hit { background-position: 0; }
.treeview span.loading {
background: url(images/ajax-loader.gif) 0 0 no-repeat;
display: block;
cursor: wait;
padding: 1px 0 1px 16px;
}
.filetree li { padding: 3px 0 2px 16px; }
.filetree span.folder, .filetree span.file {padding: 1px 0 1px 16px; display: block; }
.filetree span.folder {cursor: pointer;background: url(images/folder.gif) 0 0 no-repeat; }
.filetree li.closed span.folder { background: url(images/folder-closed.gif) 0 0 no-repeat; }
.filetree span.file { background: url(images/file.gif) 0 0 no-repeat; }

View File

@ -0,0 +1,120 @@
var AjaxTreeView={
config:{
classLoading: "loading",//ajax loading css
ontoggle : null,//function(o,b) when toggle folder.o:li,b:is open
onclick : null,//function(o,a) when click text.o: li;a:a
url:"ajaxTreeService.ajax",//ajax load url
attrs:["treeId","treeParentId"]
},
open:function(o){//li
var $o=$(o),b=$o.hasClass("closed"),$div=$o.children("div").first();
if(b){//open
var isl=!o.loading && !o.loaded && ($o.attr("treeId")!=null||$o.attr("treeParentId")!=null);
if(isl){
o.loading=true;
AjaxTreeView.load(o);
}
$div.removeClass("closed-hit");
$o.removeClass("closed");
$div.addClass("open-hit");
$o.addClass("open");
//last?
if($o.hasClass("lastclosed")){
$o.removeClass("lastclosed");
$o.addClass("lastopen");
}
if($div.hasClass("lastclosed-hit")){
$div.removeClass("lastclosed-hit");
$div.addClass("lastopen-hit");
}
}
},
close:function(o){//li
var $o=$(o),b=$o.hasClass("open"),$div=$o.children("div").first();
if(b){//close
$div.removeClass("open-hit");
$o.removeClass("open");
$div.addClass("closed-hit");
$o.addClass("closed");
//last?
if($o.hasClass("lastopen")){
$o.removeClass("lastopen");
$o.addClass("lastclosed");
}
if($div.hasClass("lastopen-hit")){
$div.removeClass("lastopen-hit");
$div.addClass("lastclosed-hit");
}
}
},
toggle:function(o){//li
var $o=$(o),c="closed",b=$o.hasClass(c);
if(b){//open
AjaxTreeView.open(o);
}else{//close
AjaxTreeView.close(o);
}
if(typeof(AjaxTreeView.config.ontoggle)=="function"){//call ontoggle
return AjaxTreeView.config.ontoggle(o,b);
}else{
return false;
}
},
load:function(o,func){//li,func
if(o.loaded){
return;
}
var $o=$(o),$span = $o.children("span").first();
$span.attr("class",AjaxTreeView.config.classLoading);
var pa=AjaxTreeView.getParams(o);
$.post(AjaxTreeView.config.url,pa,
function(d){
if(d.length>0){
//$(o.children[o.children.length-1]).after(d);//not good
$o.append(d);
}
o.loaded=true;
o.loading=false;
$span.attr("class","folder");
if(typeof(func)=="function"){
func(o,d);
}
}
,"html");
},
getParams:function(o){//eg. {suggest:txt}
var n, v;
var r={};
for (var i = 0; i < AjaxTreeView.config.attrs.length; i++) {
n = AjaxTreeView.config.attrs[i];
v = o.getAttribute(n);
if (v) {
r[AjaxTreeView.config.attrs[i]]=v;
}
}
var p=o.getAttribute("param");//eg a=1&b=2
if(p!=null&&p!=""){
var ar = p.split("&");
for(var j=0;j<ar.length;j++){
var nvr = ar[j].split("=");
r[nvr[0]]=nvr[1];
}
}
//console.log(r);
return r;
},
click:function(a){
if(typeof(AjaxTreeView.config.onclick)=="function"){//call onclick
return AjaxTreeView.config.onclick(a.parentNode.parentNode,a);
}
},
end:""
};
var $att = function(o){AjaxTreeView.toggle(o.parentNode);};
var $atc = AjaxTreeView.click;