Wiki에 계층보기 기능 추가 (글쓰기 권한이 있는 사용자가 문서들을 tree구조로 바꿀 수 있도록 함)

git-svn-id: http://xe-core.googlecode.com/svn/sandbox@6637 201d5d3c-b55e-5fd7-737f-ddc643e51545
This commit is contained in:
zero 2009-06-22 09:16:53 +00:00
parent c40d10f686
commit 461144c955
22 changed files with 431 additions and 4 deletions

View file

@ -25,9 +25,11 @@
<action name="dispWikiEditPage" type="view" />
<action name="dispWikiHistory" type="view" />
<action name="dispWikiTitleIndex" type="view" />
<action name="dispWikiTreeIndex" type="view" />
<action name="dispWikiReplyComment" type="view" />
<action name="dispWikiModifyComment" type="view" />
<action name="dispWikiDeleteComment" type="view" />
<action name="getWikiTreeList" type="model" />
<action name="dispWikiAdminContent" type="view" standalone="true" admin_index="true" />
<action name="dispWikiAdminInsertWiki" type="view" standalone="true" setup_index="true" />
<action name="dispWikiAdminGrantInfo" type="view" standalone="true" />
@ -41,5 +43,6 @@
<action name="procWikiInsertDocument" type="controller" standalone="true" />
<action name="procWikiInsertComment" type="controller" standalone="true" />
<action name="procWikiDeleteComment" type="controller" standalone="true" />
<action name="procWikiMoveTree" type="controller" standalone="true" />
</actions>
</module>

View file

@ -11,6 +11,8 @@
$lang->cmd_wiki_list = 'List';
$lang->cmd_view_info = 'Wiki Information';
$lang->use_comment = 'Use Comments';
$lang->cmd_view_document_list = '문서 목록';
$lang->cmd_view_document_tree = '계층 보기';
$lang->about_use_comment = 'You may configure to enable comments.';
$lang->contributors = 'Contributors';
$lang->notice_old_revision = 'This is an old revision';

View file

@ -11,6 +11,8 @@
$lang->cmd_wiki_list = 'リスト';
$lang->cmd_view_info = 'wiki情報';
$lang->use_comment = 'コメント機能を使う';
$lang->cmd_view_document_list = '문서 목록';
$lang->cmd_view_document_tree = '계층 보기';
$lang->about_use_comment = 'コメント機能をオン・オフを設定します。';
$lang->contributors = '投稿者';
$lang->notice_old_revision = '過去のバージョンです。';

View file

@ -11,6 +11,8 @@
$lang->cmd_wiki_list = '목록';
$lang->cmd_view_info = '위키 정보';
$lang->use_comment = '댓글 사용';
$lang->cmd_view_document_list = '문서 목록';
$lang->cmd_view_document_tree = '계층 보기';
$lang->about_use_comment = '댓글을 활성화하거나 비활성화할 수 있습니다';
$lang->contributors = '공헌자';
$lang->notice_old_revision = '옛날 버전을 보고 계십니다';

View file

@ -11,6 +11,8 @@
$lang->cmd_wiki_list = '目录';
$lang->cmd_view_info = '维基信息';
$lang->use_comment = 'Use comment';
$lang->cmd_view_document_list = '문서 목록';
$lang->cmd_view_document_tree = '계층 보기';
$lang->about_use_comment = 'You may configure to enable comments.';
$lang->contributors = 'Contributors';
$lang->notice_old_revision = 'This is an old revision';

View file

@ -11,6 +11,8 @@
$lang->cmd_wiki_list = '列表';
$lang->cmd_view_info = '維基資訊';
$lang->use_comment = '使用評論';
$lang->cmd_view_document_list = '문서 목록';
$lang->cmd_view_document_tree = '계층 보기';
$lang->about_use_comment = '可設定是否使用評論功能。';
$lang->contributors = '作者';
$lang->notice_old_revision = '此為舊版本';

View file

@ -0,0 +1,22 @@
<query id="getTreeList" action="select">
<tables>
<table name="documents" alias="doc"/>
<table name="document_categories" alias="category" type="left join">
<conditions>
<condition operation="equal" column="category.module_srl" var="module_srl" filter="number" notnull="notnull" />
<condition operation="equal" column="category.category_srl" default="doc.document_srl" filter="number" pipe="and" />
</conditions>
</table>
</tables>
<columns>
<column name="doc.title" alias="title" />
<column name="doc.document_srl" alias="document_srl" />
<column name="category.parent_srl" alias="parent_srl" />
</columns>
<conditions>
<condition operation="equal" column="doc.module_srl" var="module_srl" filter="number" notnull="notnull" />
</conditions>
<navigation>
<index var="sort_index" default="doc.list_order" order="asc" />
</navigation>
</query>

View file

@ -0,0 +1,13 @@
<query id="getTreeMinListorder" action="select">
<tables>
<table name="documents" alias="doc"/>
<table name="document_categories" alias="category" />
</tables>
<columns>
<column name="min(doc.list_order)" alias="list_order" />
</columns>
<conditions>
<condition operation="equal" column="category.parent_srl" var="parent_srl" filter="number" notnull="notnull" />
<condition operation="equal" column="doc.document_srl" default="category.category_srl" pipe="and" />
</conditions>
</query>

View file

@ -0,0 +1,21 @@
<query id="getTreeNode" action="select">
<tables>
<table name="documents" alias="doc"/>
<table name="document_categories" alias="category" type="left join">
<conditions>
<condition operation="equal" column="category.category_srl" default="doc.document_srl" />
</conditions>
</table>
</tables>
<columns>
<column name="category.parent_srl" alias="parent_srl" />
<column name="category.category_srl" alias="is_exists" />
<column name="doc.module_srl" alias="module_srl" />
<column name="doc.title" alias="title" />
<column name="doc.document_srl" alias="document_srl" />
<column name="doc.list_order" alias="list_order" />
</columns>
<conditions>
<condition operation="equal" column="doc.document_srl" var="source_srl" filter="number" notnull="notnull" />
</conditions>
</query>

View file

@ -0,0 +1,15 @@
<query id="insertTreeNode" action="insert">
<tables>
<table name="document_categories" />
</tables>
<columns>
<column name="category_srl" var="source_srl" filter="number" notnull="notnull" />
<column name="module_srl" var="module_srl" filter="number" default="0" notnull="notnull" />
<column name="title" var="title" notnull="notnull" minlength="1" maxlength="250" />
<column name="regdate" var="regdate" default="curdate()" />
<column name="expand" default="Y" />
<column name="parent_srl" var="parent_srl" filter="number" default="0" />
<column name="last_update" var="last_update" default="curdate()" />
<column name="list_order" var="list_order" default="0" />
</columns>
</query>

View file

@ -0,0 +1,11 @@
<query id="updateDocumentListOrder" action="update">
<tables>
<table name="documents" />
</tables>
<columns>
<column name="list_order" var="list_order" />
</columns>
<conditions>
<condition operation="equal" column="document_srl" var="document_srl" filter="number" notnull="notnull" />
</conditions>
</query>

View file

@ -0,0 +1,13 @@
<query id="updateTreeNode" action="update">
<tables>
<table name="document_categories" />
</tables>
<columns>
<column name="list_order" default="plus(2)" />
</columns>
<conditions>
<column name="module_srl" var="module_srl" filter="number" default="0" notnull="notnull" />
<condition operation="equal" column="parent_srl" var="parent_srl" filter="number" notnull="notnull" pipe="and" />
<condition operation="more" column="list_order" var="list_order" filter="number" notnull="notnull" pipe="and" />
</conditions>
</query>

View file

@ -0,0 +1,16 @@
<query id="updateTreeNode" action="update">
<tables>
<table name="document_categories" />
</tables>
<columns>
<column name="title" var="title" />
<column name="expand" default="Y" />
<column name="parent_srl" var="parent_srl" />
<column name="last_update" var="last_update" default="curdate()" />
<column name="list_order" var="list_order" />
</columns>
<conditions>
<column name="module_srl" var="module_srl" filter="number" default="0" notnull="notnull" />
<condition operation="equal" column="category_srl" var="source_srl" filter="number" notnull="notnull" pipe="and" />
</conditions>
</query>

View file

@ -151,6 +151,7 @@
/* Search Form */
.wikiSearchForm{ position:relative; float:right; margin:0; padding:1px 0; line-height:normal;}
.wikiSearchForm.footer { clear:both; float:none; margin:20px 0; text-align:center; }
.wikiSearchForm *{ margin:0; padding:0;}
.wikiSearchForm fieldset{ border:0; clear:both; text-align:center;}
.wikiSearchForm fieldset:after{ content:""; display:block; float:none; clear:both;}
@ -422,3 +423,6 @@ a.buttonOfficial{ _margin-top:-1px;}
a.buttonOfficial a{ _vertical-align:top;}
.hide { display:none; }
/* tree */
#tree ul.simpleTree li.noIcon { background:none; }

View file

@ -23,15 +23,16 @@
<div class="wikiInformation">
<div class="infoView">
<span class="buttonOfficial"><a href="{getUrl('act','dispWikiContent','entry','','document_srl','')}">Front Page</a></span>
<span class="buttonOfficial"><a href="{getUrl('act','dispWikiTitleIndex','entry','','document_srl','')}">Title Index</a></span>
<!--@if($grant->manager)-->
<span class="buttonOfficial"><a href="{getUrl('act','dispWikiAdminInsertWiki')}">{$lang->cmd_setup}</a></span>
<!--@end-->
<span class="buttonOfficial"><a href="{getUrl('act','dispWikiTitleIndex','entry','','document_srl','')}">{$lang->cmd_view_document_list}</a></span>
<span class="buttonOfficial"><a href="{getUrl('act','dispWikiTreeIndex','entry','','document_srl','')}">{$lang->cmd_view_document_tree}</a></span>
</div>
<form action="./" method="get" onsubmit="moveHistory(this); return false;" class="wikiSearchForm">
<input type="text" class="inputText" name="entry" />
<span class="buttonOfficial"><input type="submit" value="{$lang->cmd_move}" /></span>
<!--@if($grant->manager)-->
<span class="buttonOfficial"><input type="button" onclick="location.href='{getUrl('act','dispWikiAdminInsertWiki')}';return false;" value="{$lang->cmd_setup}" /></span>
<!--@end-->
</form>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

View file

@ -11,3 +11,80 @@ function viewHistory(history_srl) {
if(zone.css('display')=='block') zone.css('display','none');
else zone.css('display','block');
}
/**
* @file modules/document/tpl/js/document_category.js
* @author sol (sol@ngleader.com)
* @brief document 모듈의 category tree javascript
**/
var simpleTreeCollection;
function Tree(){
var url = request_uri.setQuery('mid',current_mid).setQuery('act','getWikiTreeList');
if(typeof(xeVid)!='undefined') url.setQuery('vid',xeVid);
// clear tree;
jQuery('#tree > ul > li > ul').remove();
//ajax get data and transeform ul il
jQuery.get(url,function(data){
jQuery(data).find("node").each(function(i){
var title = jQuery(this).attr("title");
var node_srl = jQuery(this).attr("node_srl");
var parent_srl = jQuery(this).attr("parent_srl");
var url = request_uri;
var args = new Array("mid="+current_mid, "entry="+title);
if(typeof(xeVid)!='undefined') args[args.length] = "vid="+xeVid;
url = request_uri+'?'+args.join('&');
// node
var node = jQuery('<li id="tree_'+node_srl+'" rel="'+url+'"><span>'+title+'</span></li>');
// insert parent child
if(parent_srl>0){
if(jQuery('#tree_'+parent_srl+'>ul').length==0) jQuery('#tree_'+parent_srl).append(jQuery('<ul>'));
jQuery('#tree_'+parent_srl+'> ul').append(node);
}else{
if(jQuery('#tree ul.simpleTree > li > ul').length==0) jQuery("<ul>").appendTo('#tree ul.simpleTree > li');
jQuery('#tree ul.simpleTree > li > ul').append(node);
}
});
// draw tree
simpleTreeCollection = jQuery('.simpleTree').simpleTree({
autoclose: false,
afterClick:function(node){
location.href = node.attr('rel');
return false;
},
afterMove:function(destination, source, pos){
if(!isManageGranted) return;
if(destination.size() == 0){
Tree();
return;
}
var parent_srl = destination.attr('id').replace(/.*_/g,'');
var source_srl = source.attr('id').replace(/.*_/g,'');
var target = source.prevAll("li:not([class^=line])");
var target_srl = 0;
if(target.length >0){
target_srl = source.prevAll("li:not([class^=line])").get(0).id.replace(/.*_/g,'');
parent_srl = 0;
}
jQuery.exec_json("wiki.procWikiMoveTree",{ "mid":current_mid,"parent_srl":parent_srl,"target_srl":target_srl,"source_srl":source_srl}, function(data){ Tree(); });
},
beforeMovedToLine : function() { return true; },
beforeMovedToFolder : function() { return true; },
afterAjax:function() { },
docToFolderConvert:true,
drag:isManageGranted
});
jQuery("[class*=close]", simpleTreeCollection[0]).each(function(){
simpleTreeCollection[0].nodeToggle(this);
});
},"xml");
}

View file

@ -21,6 +21,28 @@
</tbody>
</table>
<form action="{getUrl()}" method="get" class="wikiSearchForm footer">
<fieldset>
<legend>Wiki Search</legend>
<input type="hidden" name="vid" value="{$vid}" />
<input type="hidden" name="mid" value="{$mid}" />
<input type="hidden" name="act" value="{$act}" />
<input type="hidden" name="category" value="{$category}" />
<input type="hidden" name="search_target" value="title_content" />
<select name="search_target">
<!--@foreach($search_option as $key => $val)-->
<option value="{$key}" <!--@if($search_target==$key)-->selected="selected"<!--@end-->>{$val}</option>
<!--@end-->
</select>
<input type="text" name="search_keyword" value="{htmlspecialchars($search_keyword)}" class="inputText" accesskey="S" title="{$lang->cmd_search}" />
<!--@if($last_division)-->
<a href="{getUrl('page',1,'document_srl','','division',$last_division,'last_division','')}" class="button"><span>{$lang->cmd_search_next}</span></a>
<!--@end-->
<span class="buttonOfficial"><button type="submit">{$lang->cmd_search}</button></span>
</fieldset>
</form>
<div class="pagination a1">
<a href="{getUrl('page','','document_srl','','division',$division,'last_division',$last_division,'entry','')}" class="prevEnd">{$lang->first_page}</a>
<!--@while($page_no = $page_navigation->getNextPage())-->

View file

@ -0,0 +1,17 @@
<!--#include("header.html")-->
<!--// tree javascript plugin load -->
<!--%load_js_plugin("ui.tree")-->
<div id="tree">
<ul class="simpleTree">
<li class="root noIcon"></li>
</ul>
</div>
<script type="text/javascript">
var isManageGranted = {$isManageGranted};
jQuery(window).load( function() { Tree(); } );
</script>
<!--#include("footer.html")-->

View file

@ -152,6 +152,103 @@
$this->add('document_srl', $output->get('document_srl'));
$this->setMessage('success_deleted');
}
function procWikiMoveTree() {
// 권한 체크
if(!$this->grant->write_document) return new Object(-1, 'msg_not_permitted');
// request argument 추출
$args = Context::gets('parent_srl','target_srl','source_srl');
debugPrint($args);
// 노드 정보 구함
$output = executeQuery('wiki.getTreeNode', $args);
$node = $output->data;
if(!$node->document_srl) return new Object('msg_invalid_request');
$args->module_srl = $node->module_srl;
$args->title = $node->title;
// parent_srl 이 있으면 자식으로 추가
if($args->parent_srl) {
// target이 없으면 부모의 list_order중 최소 list_order를 구함
if(!$args->target_srl) {
$list_order->parent_srl = $args->parent_srl;
$output = executeQuery('wiki.getTreeMinListorder',$list_order);
if($output->data->list_order) $args->list_order = $output->data->list_order-1;
// target이 있으면 그 target의 list_order + 1
} else {
$t_args->source_srl = $args->target_srl;
$output = executeQuery('wiki.getTreeNode', $t_args);
$target = $output->data;
// target보다 list_order가 크고 부모가 같은 node에 대해서 list_order+2를 해주고 선택된 node에 list_order+1을 해줌
$update_args->module_srl = $target->module_srl;
$update_args->parent_srl = $target->parent_srl;
$update_args->list_order = $target->list_order;
$output = executeQuery('wiki.updateTreeListOrder', $update_args);
if(!$output->toBool()) return $output;
// target을 원위치 (list_order중복 문제로 인하여 1번 더 업데이트를 시도함)
$restore_args->module_srl = $target->module_srl;
$restore_args->source_srl = $target->document_srl;
$restore_args->list_order = $target->list_order;
$output = executeQuery('wiki.updateTreeNode', $restore_args);
if(!$output->toBool()) return $output;
$args->list_order = $target->list_order+1;
}
if(!$node->is_exists) $output = executeQuery('wiki.insertTreeNode',$args);
else $output = executeQuery('wiki.updateTreeNode',$args);
if(!$output->toBool()) return $output;
if($args->list_order) {
$doc->document_srl = $args->source_srl;
$doc->list_order = $args->list_order;
$output = executeQuery('wiki.updateDocumentListOrder', $doc);
if(!$output->toBool()) return $output;
}
// parent_srl이 없고 target_srl 이 있으면 형제로 node 업데이트
} elseif($args->target_srl) {
$t_args->source_srl = $args->target_srl;
$output = executeQuery('wiki.getTreeNode', $t_args);
$target = $output->data;
// target보다 list_order가 크고 부모가 같은 node에 대해서 list_order+2를 해주고 선택된 node에 list_order+1을 해줌
$update_args->module_srl = $target->module_srl;
$update_args->parent_srl = $target->parent_srl;
$update_args->list_order = $target->list_order;
$output = executeQuery('wiki.updateTreeListOrder', $update_args);
if(!$output->toBool()) return $output;
// target을 원위치 (list_order중복 문제로 인하여 1번 더 업데이트를 시도함)
$restore_args->module_srl = $target->module_srl;
$restore_args->source_srl = $target->document_srl;
$restore_args->list_order = $target->list_order;
$output = executeQuery('wiki.updateTreeNode', $restore_args);
if(!$output->toBool()) return $output;
$args->list_order = $target->list_order+1;
// 선택된 노드의 부모 값 맞춤
$args->parent_srl = $target->parent_srl;
if(!$node->is_exists) $output = executeQuery('wiki.insertTreeNode',$args);
else $output = executeQuery('wiki.updateTreeNode',$args);
if(!$output->toBool()) return $output;
if($args->list_order) {
$doc->document_srl = $args->source_srl;
$doc->list_order = $args->list_order;
$output = executeQuery('wiki.updateDocumentListOrder', $doc);
if(!$output->toBool()) return $output;
}
}
// 캐시파일 재생성
FileHandler::removeFile(sprintf('%sfiles/cache/wiki/%d.xml', _XE_PATH_,$this->module_srl));
}
}
?>

View file

@ -12,6 +12,77 @@
function init() {
}
/**
* @brief 계층구조 추출
* document_category테이블을 이용해서 위키 문서의 계층 구조도를 그림
* document_category테이블에 등록되어 있지 않은 경우 depth = 0 으로 하여 신규 생성
**/
function getWikiTreeList() {
header("Content-Type: text/xml; charset=UTF-8");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
$cache_file = sprintf('%sfiles/cache/wiki/%d.xml', _XE_PATH_,$this->module_srl);
if(!file_exists($cache_file)) FileHandler::writeFile($cache_file, $this->loadWikiTreeList($this->module_srl));
print FileHandler::readFile($cache_file);
Context::close();
exit();
}
function loadWikiTreeList($module_srl) {
// 문서 목록
$list = array();
// 목록을 구함
$args->module_srl = $module_srl;
$output = executeQueryArray('wiki.getTreeList', $args);
// 구해온 데이터가 없다면 빈 XML파일 return
if($output->data) {
// 데이트를 이용하여 XML 문서로 생성
foreach($output->data as $node) {
$tree[(int)$node->parent_srl][$node->document_srl] = $node;
}
// XML 데이터를 생성
$xml_doc = '<root>'.$this->getXmlTree($tree[0], $tree).'</root>';
} else {
$xml_doc = '<root></root>';
}
return $xml_doc;
}
function getXmlTree($source_node, $tree) {
if(!$source_node) return;
foreach($source_node as $document_srl => $node) {
$child_buff = "";
// 자식 노드의 데이터 가져옴
if($document_srl && $tree[$document_srl]) $child_buff = $this->getXmlTree($tree[$document_srl], $tree);
// 변수 정리
$parent_srl = $node->parent_srl;
$title = $node->title;
$attribute = sprintf(
'node_srl="%d" parent_srl="%d" title="%s" ',
$document_srl,
$parent_srl,
$title
);
if($child_buff) $buff .= sprintf('<node %s>%s</node>', $attribute, $child_buff);
else $buff .= sprintf('<node %s />', $attribute);
}
return $buff;
}
function getContributors($document_srl) {
$oDocumentModel = &getModel('document');
$oDocument = $oDocumentModel->getDocument($document_srl);

View file

@ -6,6 +6,7 @@
**/
class wikiView extends wiki {
var $search_option = array('title','content','title_content','comment','user_name','nick_name','user_id','tag');
/**
* @brief 초기화
@ -106,6 +107,9 @@
$obj->sort_index = "title";
$obj->page = $page;
$obj->list_count = 50;
$obj->search_keyword = Context::get('search_keyword');
$obj->search_target = Context::get('search_target');
$output = $oDocumentModel->getDocumentList($obj);
Context::set('document_list', $output->data);
@ -113,9 +117,19 @@
Context::set('total_page', $output->total_page);
Context::set('page', $output->page);
Context::set('page_navigation', $output->page_navigation);
// 검색 옵션 세팅
foreach($this->search_option as $opt) $search_option[$opt] = Context::getLang($opt);
Context::set('search_option', $search_option);
$this->setTemplateFile('title_index');
}
function dispWikiTreeIndex() {
Context::set('isManageGranted', $this->grant->write_document?'true':'false');
$this->setTemplateFile('tree_list');
}
function dispWikiContentView() {
// 요청된 변수 값들을 정리
$document_srl = Context::get('document_srl');