Merge pull request #178 from DigitalUnion/master

增加了导出单篇文档为 PDF 的功能。
This commit is contained in:
Minho 2017-12-21 15:56:55 +08:00 committed by GitHub
commit 4e4035b27a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 452 additions and 267 deletions

10
TODO Normal file
View File

@ -0,0 +1,10 @@
1、把 log 提取出 dbgout 之类的方法;已改作 beego.Info() 调用;
2、把源代码里的 TODO 完成;
3、Export 的两个 URL 应该可以合并,用是否有 :id 来区分;这样 0 号文档输出整个 book 更顺;已完成;
4、统一代码风格空格、命名之类的
5、美化 PDF 的输出格式;
6、自动登录新开标签页而且并不能跳转至起始请求页的问题
7、用户分组管理
8、[自动]展示历史版本;增强历史版本对比显示的能力;
9、[自动]展示作者信息;也许可以和上一需求合并考虑;
10、查看了解评论功能

File diff suppressed because it is too large Load Diff

View File

@ -5,86 +5,85 @@ import (
"github.com/lifei6671/mindoc/controllers" "github.com/lifei6671/mindoc/controllers"
) )
func init() { func init() {
beego.Router("/",&controllers.HomeController{},"*:Index") beego.Router("/", &controllers.HomeController{}, "*:Index")
beego.Router("/login", &controllers.AccountController{},"*:Login") beego.Router("/login", &controllers.AccountController{}, "*:Login")
beego.Router("/logout", &controllers.AccountController{},"*:Logout") beego.Router("/logout", &controllers.AccountController{}, "*:Logout")
beego.Router("/register", &controllers.AccountController{},"*:Register") beego.Router("/register", &controllers.AccountController{}, "*:Register")
beego.Router("/find_password", &controllers.AccountController{},"*:FindPassword") beego.Router("/find_password", &controllers.AccountController{}, "*:FindPassword")
beego.Router("/valid_email", &controllers.AccountController{},"post:ValidEmail") beego.Router("/valid_email", &controllers.AccountController{}, "post:ValidEmail")
beego.Router("/captcha", &controllers.AccountController{},"*:Captcha") beego.Router("/captcha", &controllers.AccountController{}, "*:Captcha")
beego.Router("/manager", &controllers.ManagerController{},"*:Index") beego.Router("/manager", &controllers.ManagerController{}, "*:Index")
beego.Router("/manager/users", &controllers.ManagerController{},"*:Users") beego.Router("/manager/users", &controllers.ManagerController{}, "*:Users")
beego.Router("/manager/users/edit/:id", &controllers.ManagerController{},"*:EditMember") beego.Router("/manager/users/edit/:id", &controllers.ManagerController{}, "*:EditMember")
beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember") beego.Router("/manager/member/create", &controllers.ManagerController{}, "post:CreateMember")
beego.Router("/manager/member/delete", &controllers.ManagerController{},"post:DeleteMember") beego.Router("/manager/member/delete", &controllers.ManagerController{}, "post:DeleteMember")
beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus") beego.Router("/manager/member/update-member-status", &controllers.ManagerController{}, "post:UpdateMemberStatus")
beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole") beego.Router("/manager/member/change-member-role", &controllers.ManagerController{}, "post:ChangeMemberRole")
beego.Router("/manager/books", &controllers.ManagerController{},"*:Books") beego.Router("/manager/books", &controllers.ManagerController{}, "*:Books")
beego.Router("/manager/books/edit/:key", &controllers.ManagerController{},"*:EditBook") beego.Router("/manager/books/edit/:key", &controllers.ManagerController{}, "*:EditBook")
beego.Router("/manager/books/delete", &controllers.ManagerController{},"*:DeleteBook") beego.Router("/manager/books/delete", &controllers.ManagerController{}, "*:DeleteBook")
beego.Router("/manager/comments", &controllers.ManagerController{},"*:Comments") beego.Router("/manager/comments", &controllers.ManagerController{}, "*:Comments")
beego.Router("/manager/books/token", &controllers.ManagerController{},"post:CreateToken") beego.Router("/manager/books/token", &controllers.ManagerController{}, "post:CreateToken")
beego.Router("/manager/setting",&controllers.ManagerController{},"*:Setting") beego.Router("/manager/setting", &controllers.ManagerController{}, "*:Setting")
beego.Router("/manager/books/transfer", &controllers.ManagerController{},"post:Transfer") beego.Router("/manager/books/transfer", &controllers.ManagerController{}, "post:Transfer")
beego.Router("/manager/books/open", &controllers.ManagerController{},"post:PrivatelyOwned") beego.Router("/manager/books/open", &controllers.ManagerController{}, "post:PrivatelyOwned")
beego.Router("/manager/attach/list", &controllers.ManagerController{},"*:AttachList") beego.Router("/manager/attach/list", &controllers.ManagerController{}, "*:AttachList")
beego.Router("/manager/attach/detailed/:id", &controllers.ManagerController{},"*:AttachDetailed") beego.Router("/manager/attach/detailed/:id", &controllers.ManagerController{}, "*:AttachDetailed")
beego.Router("/manager/attach/delete", &controllers.ManagerController{},"post:AttachDelete") beego.Router("/manager/attach/delete", &controllers.ManagerController{}, "post:AttachDelete")
beego.Router("/setting", &controllers.SettingController{}, "*:Index")
beego.Router("/setting/password", &controllers.SettingController{}, "*:Password")
beego.Router("/setting/upload", &controllers.SettingController{}, "*:Upload")
beego.Router("/setting", &controllers.SettingController{},"*:Index") beego.Router("/book", &controllers.BookController{}, "*:Index")
beego.Router("/setting/password", &controllers.SettingController{},"*:Password") beego.Router("/book/:key/dashboard", &controllers.BookController{}, "*:Dashboard")
beego.Router("/setting/upload", &controllers.SettingController{},"*:Upload") beego.Router("/book/:key/setting", &controllers.BookController{}, "*:Setting")
beego.Router("/book/:key/users", &controllers.BookController{}, "*:Users")
beego.Router("/book/:key/release", &controllers.BookController{}, "post:Release")
beego.Router("/book/:key/sort", &controllers.BookController{}, "post:SaveSort")
beego.Router("/book", &controllers.BookController{},"*:Index") beego.Router("/book/create", &controllers.BookController{}, "*:Create")
beego.Router("/book/:key/dashboard", &controllers.BookController{},"*:Dashboard") beego.Router("/book/users/create", &controllers.BookMemberController{}, "post:AddMember")
beego.Router("/book/:key/setting", &controllers.BookController{},"*:Setting") beego.Router("/book/users/change", &controllers.BookMemberController{}, "post:ChangeRole")
beego.Router("/book/:key/users", &controllers.BookController{},"*:Users") beego.Router("/book/users/delete", &controllers.BookMemberController{}, "post:RemoveMember")
beego.Router("/book/:key/release", &controllers.BookController{},"post:Release")
beego.Router("/book/:key/sort", &controllers.BookController{},"post:SaveSort")
beego.Router("/book/create", &controllers.BookController{},"*:Create") beego.Router("/book/setting/save", &controllers.BookController{}, "post:SaveBook")
beego.Router("/book/users/create", &controllers.BookMemberController{},"post:AddMember") beego.Router("/book/setting/open", &controllers.BookController{}, "post:PrivatelyOwned")
beego.Router("/book/users/change", &controllers.BookMemberController{},"post:ChangeRole") beego.Router("/book/setting/transfer", &controllers.BookController{}, "post:Transfer")
beego.Router("/book/users/delete", &controllers.BookMemberController{},"post:RemoveMember") beego.Router("/book/setting/upload", &controllers.BookController{}, "post:UploadCover")
beego.Router("/book/setting/token", &controllers.BookController{}, "post:CreateToken")
beego.Router("/book/setting/delete", &controllers.BookController{}, "post:Delete")
beego.Router("/book/setting/save", &controllers.BookController{},"post:SaveBook") beego.Router("/api/attach/remove/", &controllers.DocumentController{}, "post:RemoveAttachment")
beego.Router("/book/setting/open", &controllers.BookController{},"post:PrivatelyOwned") beego.Router("/api/:key/edit/?:id", &controllers.DocumentController{}, "*:Edit")
beego.Router("/book/setting/transfer", &controllers.BookController{},"post:Transfer") beego.Router("/api/upload", &controllers.DocumentController{}, "post:Upload")
beego.Router("/book/setting/upload", &controllers.BookController{},"post:UploadCover") beego.Router("/api/:key/create", &controllers.DocumentController{}, "post:Create")
beego.Router("/book/setting/token", &controllers.BookController{},"post:CreateToken") beego.Router("/api/:key/delete", &controllers.DocumentController{}, "post:Delete")
beego.Router("/book/setting/delete", &controllers.BookController{},"post:Delete") beego.Router("/api/:key/content/?:id", &controllers.DocumentController{}, "*:Content")
beego.Router("/api/:key/compare/:id", &controllers.DocumentController{}, "*:Compare")
beego.Router("/api/attach/remove/", &controllers.DocumentController{},"post:RemoveAttachment") beego.Router("/history/get", &controllers.DocumentController{}, "get:History")
beego.Router("/api/:key/edit/?:id", &controllers.DocumentController{},"*:Edit") beego.Router("/history/delete", &controllers.DocumentController{}, "*:DeleteHistory")
beego.Router("/api/upload",&controllers.DocumentController{},"post:Upload") beego.Router("/history/restore", &controllers.DocumentController{}, "*:RestoreHistory")
beego.Router("/api/:key/create",&controllers.DocumentController{},"post:Create")
beego.Router("/api/:key/delete", &controllers.DocumentController{},"post:Delete")
beego.Router("/api/:key/content/?:id",&controllers.DocumentController{},"*:Content")
beego.Router("/api/:key/compare/:id", &controllers.DocumentController{},"*:Compare")
beego.Router("/history/get", &controllers.DocumentController{},"get:History") beego.Router("/docs/:key", &controllers.DocumentController{}, "*:Index")
beego.Router("/history/delete", &controllers.DocumentController{},"*:DeleteHistory") beego.Router("/docs/:key/:id", &controllers.DocumentController{}, "*:Read")
beego.Router("/history/restore", &controllers.DocumentController{},"*:RestoreHistory") beego.Router("/docs/:key/search", &controllers.DocumentController{}, "post:Search")
beego.Router("/export/:key", &controllers.DocumentController{}, "*:ExportBook")
beego.Router("/export/:key/:id", &controllers.DocumentController{}, "*:ExportDoc")
beego.Router("/qrcode/:key.png", &controllers.DocumentController{}, "get:QrCode")
beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index") beego.Router("/attach_files/:key/:attach_id", &controllers.DocumentController{}, "get:DownloadAttachment")
beego.Router("/docs/:key/:id", &controllers.DocumentController{},"*:Read")
beego.Router("/docs/:key/search", &controllers.DocumentController{},"post:Search")
beego.Router("/export/:key", &controllers.DocumentController{},"*:Export")
beego.Router("/qrcode/:key.png",&controllers.DocumentController{},"get:QrCode")
beego.Router("/attach_files/:key/:attach_id",&controllers.DocumentController{},"get:DownloadAttachment") beego.Router("/comment/create", &controllers.CommentController{}, "post:Create")
beego.Router("/comment/lists", &controllers.CommentController{}, "get:Lists")
beego.Router("/comment/index", &controllers.CommentController{}, "*:Index")
beego.Router("/comment/create", &controllers.CommentController{},"post:Create") beego.Router("/search", &controllers.SearchController{}, "get:Index")
beego.Router("/comment/lists", &controllers.CommentController{},"get:Lists")
beego.Router("/comment/index", &controllers.CommentController{},"*:Index")
beego.Router("/search",&controllers.SearchController{},"get:Index") beego.Router("/tag/:key", &controllers.LabelController{}, "get:Index")
beego.Router("/tags", &controllers.LabelController{}, "get:List")
beego.Router("/tag/:key", &controllers.LabelController{},"get:Index")
beego.Router("/tags", &controllers.LabelController{},"get:List")
} }

View File

@ -417,7 +417,8 @@ table>tbody>tr:hover{
} }
.manual-article .article-head { .manual-article .article-head {
position: relative; position: relative;
zoom:1;padding: 10px 20px zoom: 1;
padding: 10px 20px
} }
.manual-reader .book-title{ .manual-reader .book-title{
color: #333333; color: #333333;
@ -430,7 +431,7 @@ table>tbody>tr:hover{
.manual-article .article-head h1 { .manual-article .article-head h1 {
margin: 0; margin: 0;
font-size: 20px; font-size: 20px;
font-weight: 200; font-weight: 300;
text-align: center; text-align: center;
line-height: 30px; line-height: 30px;
overflow: hidden; overflow: hidden;
@ -438,6 +439,17 @@ table>tbody>tr:hover{
white-space: nowrap; white-space: nowrap;
color: #444 color: #444
} }
.manual-article .article-head h3 {
margin: 0;
font-size: 12px;
font-weight: 200;
text-align: center;
line-height: 18px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #444
}
.manual-article .article-content{ .manual-article .article-content{
min-width: 980px; min-width: 980px;
max-width: 98%; max-width: 98%;

View File

@ -4,51 +4,58 @@
* @param $id * @param $id
* @param $callback * @param $callback
*/ */
function loadDocument($url,$id,$callback) { function loadDocument($url, $id, $callback) {
$.ajax({ $.ajax({
url : $url, url : $url,
type : "GET", type : "GET",
beforeSend :function (xhr) { beforeSend : function (xhr) {
var body = events.data('body_' + $id); var body = events.data('body_' + $id);
var title = events.data('title_' + $id); var title = events.data('title_' + $id);
var doc_title = events.data('doc_title_' + $id); var doc_title = events.data('doc_title_' + $id);
var doc_info = events.data('doc_info_' + $id);
if(body && title && doc_title){ if (body && title && doc_title) {
if (typeof $callback === "function") { if (typeof $callback === "function") {
body = $callback(body); body = $callback(body);
} }
$("#page-content").html(body); $("#page-content").html(body);
$("title").text(title); $("title").text(title);
$("#article-title").text(doc_title); $("#article-title").text(doc_title);
$("#article-info").text(doc_info);
events.trigger('article.open',{ $url : $url, $init : false , $id : $id }); events.trigger('article.open', { $url : $url, $init : false, $id : $id });
return false; return false;
} }
NProgress.start(); NProgress.start();
}, },
success : function (res) { success : function (res) {
if(res.errcode === 0){ if (res.errcode === 0) {
var body = res.data.body; var body = res.data.body;
var doc_title = res.data.doc_title; var doc_title = res.data.doc_title;
var title = res.data.title; var title = res.data.title;
var doc_info = res.data.doc_info;
$body = body; $body = body;
if (typeof $callback === "function" ){ if (typeof $callback === "function" ) {
$body = $callback(body); $body = $callback(body);
} }
$("#page-content").html($body); $("#page-content").html($body);
$("title").text(title); $("title").text(title);
$("#article-title").text(doc_title); $("#article-title").text(doc_title);
$("#article-info").text(doc_info);
events.data('body_' + $id,body); events.data('body_' + $id, body);
events.data('title_' + $id,title); events.data('title_' + $id, title);
events.data('doc_title_' + $id,doc_title); events.data('doc_title_' + $id, doc_title);
events.data('doc_info_' + $id, doc_info);
events.trigger('article.open',{ $url : $url, $init : true, $id : $id }); events.trigger('article.open', { $url : $url, $init : true, $id : $id });
} else if (res.errcode === 6000) {
}else{ window.location.href = "/";
} else {
layer.msg("加载失败"); layer.msg("加载失败");
} }
}, },
@ -74,9 +81,9 @@ $(function () {
}); });
$(".manual-right").scroll(function () { $(".manual-right").scroll(function () {
var top = $(".manual-right").scrollTop(); var top = $(".manual-right").scrollTop();
if(top > 100){ if (top > 100) {
$(".view-backtop").addClass("active"); $(".view-backtop").addClass("active");
}else{ } else {
$(".view-backtop").removeClass("active"); $(".view-backtop").removeClass("active");
} }
}); });
@ -85,7 +92,7 @@ $(function () {
initHighlighting(); initHighlighting();
window.jsTree = $("#sidebar").jstree({ window.jsTree = $("#sidebar").jstree({
'plugins':["wholerow","types"], 'plugins' : ["wholerow", "types"],
"types": { "types": {
"default" : { "default" : {
"icon" : false // 删除默认图标 "icon" : false // 删除默认图标
@ -93,31 +100,31 @@ $(function () {
}, },
'core' : { 'core' : {
'check_callback' : true, 'check_callback' : true,
"multiple" : false , "multiple" : false,
'animation' : 0 'animation' : 0
} }
}).on('select_node.jstree',function (node,selected,event) { }).on('select_node.jstree', function (node, selected, event) {
$(".m-manual").removeClass('manual-mobile-show-left'); $(".m-manual").removeClass('manual-mobile-show-left');
var url = selected.node.a_attr.href; var url = selected.node.a_attr.href;
if(url === window.location.href){ if (url === window.location.href) {
return false; return false;
} }
loadDocument(url,selected.node.id);
loadDocument(url, selected.node.id);
}); });
$("#slidebar").on("click",function () { $("#slidebar").on("click", function () {
$(".m-manual").addClass('manual-mobile-show-left'); $(".m-manual").addClass('manual-mobile-show-left');
}); });
$(".manual-mask").on("click",function () { $(".manual-mask").on("click", function () {
$(".m-manual").removeClass('manual-mobile-show-left'); $(".m-manual").removeClass('manual-mobile-show-left');
}); });
/** /**
* 关闭侧边栏 * 关闭侧边栏
*/ */
$(".manual-fullscreen-switch").on("click",function () { $(".manual-fullscreen-switch").on("click", function () {
isFullScreen = !isFullScreen; isFullScreen = !isFullScreen;
if (isFullScreen) { if (isFullScreen) {
$(".m-manual").addClass('manual-fullscreen-active'); $(".m-manual").addClass('manual-fullscreen-active');
@ -126,24 +133,23 @@ $(function () {
} }
}); });
//处理打开事件 // 处理打开事件
events.on('article.open', function (event, $param) { events.on('article.open', function (event, $param) {
if ('pushState' in history) { if ('pushState' in history) {
if ($param.$init === false) { if ($param.$init === false) {
window.history.replaceState($param , $param.$id , $param.$url); window.history.replaceState($param, $param.$id, $param.$url);
} else { } else {
window.history.pushState($param, $param.$id , $param.$url); window.history.pushState($param, $param.$id, $param.$url);
} }
} else { } else {
window.location.hash = $param.$url; window.location.hash = $param.$url;
} }
initHighlighting(); initHighlighting();
$(".manual-right").scrollTop(0); $(".manual-right").scrollTop(0);
}); });
$(".navg-item[data-mode]").on("click",function () { $(".navg-item[data-mode]").on("click", function () {
var mode = $(this).data('mode'); var mode = $(this).data('mode');
$(this).siblings().removeClass('active').end().addClass('active'); $(this).siblings().removeClass('active').end().addClass('active');
$(".m-manual").removeClass("manual-mode-view manual-mode-collect manual-mode-search").addClass("manual-mode-" + mode); $(".m-manual").removeClass("manual-mode-view manual-mode-collect manual-mode-search").addClass("manual-mode-" + mode);
@ -155,25 +161,25 @@ $(function () {
$("#searchForm").ajaxForm({ $("#searchForm").ajaxForm({
beforeSubmit : function () { beforeSubmit : function () {
var keyword = $.trim($("#searchForm").find("input[name='keyword']").val()); var keyword = $.trim($("#searchForm").find("input[name='keyword']").val());
if(keyword === ""){ if (keyword === "") {
$(".search-empty").show(); $(".search-empty").show();
$("#searchList").html(""); $("#searchList").html("");
return false; return false;
} }
$("#btnSearch").attr("disabled","disabled").find("i").removeClass("fa-search").addClass("loading"); $("#btnSearch").attr("disabled", "disabled").find("i").removeClass("fa-search").addClass("loading");
window.keyword = keyword; window.keyword = keyword;
}, },
success :function (res) { success : function (res) {
var html = ""; var html = "";
if(res.errcode === 0){ if (res.errcode === 0) {
for(var i in res.data){ for(var i in res.data) {
var item = res.data[i]; var item = res.data[i];
html += '<li><a href="javascript:;" title="'+ item.doc_name +'" data-id="'+ item.doc_id+'"> '+ item.doc_name +' </a></li>'; html += '<li><a href="javascript:;" title="' + item.doc_name + '" data-id="' + item.doc_id + '"> ' + item.doc_name + ' </a></li>';
} }
} }
if(html !== ""){ if (html !== "") {
$(".search-empty").hide(); $(".search-empty").hide();
}else{ } else {
$(".search-empty").show(); $(".search-empty").show();
} }
$("#searchList").html(html); $("#searchList").html(html);
@ -184,7 +190,6 @@ $(function () {
}); });
window.onpopstate = function (e) { window.onpopstate = function (e) {
var $param = e.state; var $param = e.state;
console.log($param); console.log($param);
if($param.hasOwnProperty("$url")) { if($param.hasOwnProperty("$url")) {
@ -192,18 +197,18 @@ $(function () {
window.jsTree.jstree().select_node({ id : $param.$id }); window.jsTree.jstree().select_node({ id : $param.$id });
$param.$init = false; $param.$init = false;
//events.trigger('article.open', $param ); // events.trigger('article.open', $param);
}else{ } else {
console.log($param); console.log($param);
} }
}; };
try { try {
var $node = window.jsTree.jstree().get_selected(); var $node = window.jsTree.jstree().get_selected();
if (typeof $node === "object") { if (typeof $node === "object") {
$node = window.jsTree.jstree().get_node({id: $node[0]}); $node = window.jsTree.jstree().get_node({ id: $node[0] });
events.trigger('article.open', {$url: $node.a_attr.href, $init: true, $id: $node.a_attr.id}); events.trigger('article.open', { $url: $node.a_attr.href, $init: true, $id: $node.a_attr.id });
} }
}catch (e){ } catch (e) {
console.log(e); console.log(e);
} }
}); });

View File

@ -58,7 +58,8 @@
{{if eq .Model.PrivatelyOwned 0}} {{if eq .Model.PrivatelyOwned 0}}
<li><a href="javascript:" data-toggle="modal" data-target="#shareProject">项目分享</a> </li> <li><a href="javascript:" data-toggle="modal" data-target="#shareProject">项目分享</a> </li>
<li role="presentation" class="divider"></li> <li role="presentation" class="divider"></li>
<li><a href="{{urlfor "DocumentController.Export" ":key" .Model.Identify "output" "pdf"}}" target="_blank">项目导出PDF</a> </li> <li><a href="javascript:void(0);" onclick="ExportPdfDoc()">文档导出为 PDF</a> </li>
<li><a href="{{urlfor "DocumentController.ExportBook" ":key" .Model.Identify "output" "pdf"}}" target="_blank">项目导出为 PDF</a> </li>
{{end}} {{end}}
<li><a href="{{urlfor "HomeController.Index"}}" title="返回首页">返回首页</a> </li> <li><a href="{{urlfor "HomeController.Index"}}" title="返回首页">返回首页</a> </li>
@ -127,6 +128,7 @@
</div> </div>
<div class="col-md-8 text-center"> <div class="col-md-8 text-center">
<h1 id="article-title">{{.Title}}</h1> <h1 id="article-title">{{.Title}}</h1>
<h3 id="article-info">{{.Info}}</h3>
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
</div> </div>
@ -234,6 +236,13 @@
<script type="text/javascript" src="/static/js/jquery.highlight.js"></script> <script type="text/javascript" src="/static/js/jquery.highlight.js"></script>
<script type="text/javascript" src="/static/js/kancloud.js"></script> <script type="text/javascript" src="/static/js/kancloud.js"></script>
<script type="text/javascript"> <script type="text/javascript">
active_book_id = {{.Model.Identify}};
active_doc_id = {{.DocumentId}};
$(function () {
$("body").on('article.open', function (event, $param) {
active_doc_id = $param.$id;
});
});
$(function () { $(function () {
$("#searchList").on("click","a",function () { $("#searchList").on("click","a",function () {
var id = $(this).attr("data-id"); var id = $(this).attr("data-id");
@ -245,6 +254,12 @@ $(function () {
}); });
}); });
}); });
function ExportPdfDoc() {
var id = active_book_id;
if(active_doc_id != "0")
id += "/" + active_doc_id;
window.location.href = "/export/" + id + "?output=pdf";
}
</script> </script>
</body> </body>
</html> </html>