From 20ec383ed872dd2722c819c4ac254b7778723714 Mon Sep 17 00:00:00 2001 From: Shuai Lin Date: Mon, 8 Jun 2015 12:30:50 +0800 Subject: [PATCH] improve office documents online preview --- media/css/doc_and_pdf.css | 227 +-------------- seahub/api2/urls.py | 1 - seahub/api2/views.py | 37 +-- seahub/templates/shared_file_view.html | 2 - seahub/templates/snippets/file_view_js.html | 3 - .../snippets/office_convert_html.html | 7 +- .../templates/snippets/office_convert_js.html | 274 +++++++++--------- .../snippets/office_convert_style.html | 3 - .../snippets/spreadsheet_convert_js.html | 7 +- seahub/templates/view_file_base.html | 2 - seahub/templates/view_file_document.html | 2 +- seahub/templates/view_file_pdf.html | 2 +- seahub/templates/view_history_file.html | 2 - seahub/urls.py | 4 +- seahub/utils/__init__.py | 65 +---- seahub/views/file.py | 81 ++---- 16 files changed, 195 insertions(+), 524 deletions(-) diff --git a/media/css/doc_and_pdf.css b/media/css/doc_and_pdf.css index d4caf4694f..7ffc01edba 100644 --- a/media/css/doc_and_pdf.css +++ b/media/css/doc_and_pdf.css @@ -1,219 +1,13 @@ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab filetype=css: */ -/* Demo CSS for pdf2htmlEX */ -/* Copyright 2012,2013 Lu Wang */ -/* Part 1: Web Page Layout: Free to modify, except for a few of them which are required by pdf2htmlEX.js, see the comments */ -#sidebar { /* Sidebar */ - position:absolute; - top:-30px; - left:0; - bottom:0; - width:250px; - overflow:auto; +.page-container { + width: 850px; + margin: auto; + margin-top: 20px; } -#page-container { /* PDF container */ - border:0; /* required for lazy page loading in pdf2htmlEX.js (page visibility test) */ +.page-container iframe { + width: 100%; + height: 100%; + margin: auto; } -@media screen { - /* for sidebar */ - #sidebar.opened + #page-container { margin-left:250px; } - #page-container { - /* `bottom' and `right' are required for lazy page loading in pdf2htmlEX.js (page visibility test) - * alternatively you may set width and height - */ - bottom:0; - right:0; - overflow:auto; - } -} -@media print { - @page { margin:0; } - html { margin:0; } - body { - margin:0; - -webkit-print-color-adjust:exact; /* enable printing background images for WebKit */ - } - #sidebar { display:none; } - #page-container { - width:auto; - height:auto; - overflow:visible; - background-color:transparent; - } - .d { display:none; } -} -/* Part 2: Page Elements: Modify with caution - * The followings are base classes, some of which are meant to be override by PDF specific classes - * So do not increase the specificity (e.g. ".classname" -> "#page-container .classname") - */ -.pd { /* page decoration */ - position:relative; - border: 1px solid #ccc; - overflow: hidden; -} -.pf { /* page */ - position:absolute; - top:0; - left:0; - width:100%; - height:100%; - background-color:white; - overflow: hidden; - margin:0; - border:0; /* required by pdf2htmlEX.js for page visibility test */ -} -.pc { /* content of a page */ - position:absolute; - border:0; - padding:0; - margin:0; - top:0; - left:0; - width:100%; - height:100%; - overflow:hidden; - display:block; - /* set transform-origin for scaling */ - transform-origin:0% 0%; - -ms-transform-origin:0% 0%; - -moz-transform-origin:0% 0%; - -webkit-transform-origin:0% 0%; - -o-transform-origin:0% 0%; -} -.pc.opened { /* used by pdf2htmlEX.js, to show/hide pages */ - display:block; -} -.bi { - position:absolute; - left:0; - top:0; - width:100%; - height:100%; - -ms-user-select:none; - -moz-user-select:none; - -webkit-user-select:none; - user-select:none; -} -@media print { - .pd { - margin:0; - box-shadow:none; - page-break-after:always; - page-break-inside:avoid; - } - @-moz-document url-prefix() { - /* fix page truncation for FireFox */ - .pd { - overflow:visible; - border:1px solid #FFFFFF; - } - .pf {overflow:visible;} - .pc {overflow:visible;} - } -} -.c { /* clip box */ - position:absolute; - border:0; - padding:0; - margin:0; - overflow:hidden; - display:block; -} -.t { /* text line */ - position:absolute; - white-space:pre; - font-size:1px; - transform-origin:0% 100%; - -ms-transform-origin:0% 100%; - -moz-transform-origin:0% 100%; - -webkit-transform-origin:0% 100%; - -o-transform-origin:0% 100%; -} -.pd span { /* text blocks within a line */ - position:relative; - vertical-align: baseline; - /* _ for spaces may need display:inline, which will override this */ - display:inline-block; -} -._ { /* text shift */ - color:transparent; - z-index:-1; -} -/* selection background should not be opaque, for fallback mode */ -::selection{ - background: rgba(127,255,255,0.4); -} -::-moz-selection{ - background: rgba(127,255,255,0.4); -} -.pi { /* info for Javascript */ - display:none; -} -.l { /* annotation links */ -} -/* transparent color - WebKit */ -.d { /* css drawing */ - position:absolute; - transform-origin:0% 100%; - -ms-transform-origin:0% 100%; - -moz-transform-origin:0% 100%; - -webkit-transform-origin:0% 100%; - -o-transform-origin:0% 100%; -} -/* Base CSS END */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab filetype=css: */ -/* Fancy styles */ -/* Copyright 2013 Lu Wang */ -@media screen { - #sidebar { - background-color:#fff; - box-shadow:0 3px 6px #ccc; - z-index:1; /*to make outline scrollbar work after zoom in page-container*/ - } - #outline { - font-family:Georgia,Times,"Times New Roman",serif; - font-size:13px; - padding:25px 20px; - width:210px; - overflow:auto; - background: #fff; - } - #outline ul { - padding:0; - } - #outline li { - list-style-type:none; - margin:1em 0; - } - #outline li > ul { - margin-left: 1em; - } - #outline a, - #outline a:visited, - #outline a:hover, - #outline a:active { - line-height:1.2; - text-overflow:ellipsis; - white-space:nowrap; - display:block; - overflow:hidden; - outline:0; - } - .pd { - margin: 13px auto; - box-shadow: 0 0 6px #ccc; - } - @keyframes fadein { from { opacity:0;} to { opacity:1;} } - @-moz-keyframes fadein { from { opacity:0;} to { opacity:1;} } - @-webkit-keyframes fadein { from { opacity:0;} to { opacity:1;} } - @-o-keyframes fadein { from { opacity:0;} to { opacity: 1;} } - .pc.opened { /* used by pdf2htmlEX.js, to show/hide pages */ - -moz-animation: fadein 100ms; - -webkit-animation: fadein 100ms; - -o-animation: fadein 100ms; - animation: fadein 100ms; - } -} -/* Fancy CSS END */ #convert-loading { text-align: center; font-size: 1.2em; @@ -223,11 +17,6 @@ position:relative; min-height:400px; } -.fixed-outline { - position:fixed; - left:0; - top:0; -} .pdf2html-toolbar { position:fixed; left:50%; diff --git a/seahub/api2/urls.py b/seahub/api2/urls.py index 94ea0a28d3..bc50fd7c60 100644 --- a/seahub/api2/urls.py +++ b/seahub/api2/urls.py @@ -114,7 +114,6 @@ if HAS_OFFICE_CONVERTER: ) urlpatterns += patterns('', url(r'^office-convert/status/$', OfficeConvertQueryStatus.as_view()), - url(r'^office-convert/page-num/$', OfficeConvertQueryPageNum.as_view()), ) urlpatterns += patterns('', url(r'^office-convert/generate/repos/(?P[-0-9-a-f]{36})/$', OfficeGenerateView.as_view()), diff --git a/seahub/api2/views.py b/seahub/api2/views.py index 2d12fbed88..c183b85e70 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -82,8 +82,7 @@ if HAS_FILE_SEARCH: from seahub_extra.search.views import search_keyword from seahub.utils import HAS_OFFICE_CONVERTER if HAS_OFFICE_CONVERTER: - from seahub.utils import query_office_convert_status, \ - query_office_file_pages, prepare_converted_html + from seahub.utils import query_office_convert_status, prepare_converted_html import seahub.settings as settings from seahub.settings import THUMBNAIL_EXTENSION, THUMBNAIL_ROOT, \ ENABLE_THUMBNAIL, THUMBNAIL_IMAGE_SIZE_LIMIT, ENABLE_GLOBAL_ADDRESSBOOK @@ -4010,37 +4009,6 @@ class OfficeConvertQueryStatus(APIView): return HttpResponse(json.dumps(ret), content_type=content_type) -# based on views/file.py::office_convert_query_page_num -class OfficeConvertQueryPageNum(APIView): - authentication_classes = (TokenAuthentication, ) - permission_classes = (IsAuthenticated, ) - throttle_classes = (UserRateThrottle, ) - - def get(self, request, format=None): - if not HAS_OFFICE_CONVERTER: - return api_error(status.HTTP_404_NOT_FOUND, 'Office converter not enabled.') - - content_type = 'application/json; charset=utf-8' - - ret = {'success': False} - - file_id = request.GET.get('file_id', '') - if len(file_id) != 40: - ret['error'] = 'invalid param' - else: - try: - d = query_office_file_pages(file_id) - if d.error: - ret['error'] = d.error - else: - ret['success'] = True - ret['count'] = d.count - except Exception, e: - logging.exception('failed to call query_office_file_pages') - ret['error'] = str(e) - - return HttpResponse(json.dumps(ret), content_type=content_type) - # based on views/file.py::view_file and views/file.py::handle_document class OfficeGenerateView(APIView): authentication_classes = (TokenAuthentication, ) @@ -4090,10 +4058,9 @@ class OfficeGenerateView(APIView): ret_dict = {} if HAS_OFFICE_CONVERTER: - err, html_exists = prepare_converted_html(inner_path, obj_id, fileext, ret_dict) + err = prepare_converted_html(inner_path, obj_id, fileext, ret_dict) # populate return value dict ret_dict['err'] = err - ret_dict['html_exists'] = html_exists ret_dict['obj_id'] = obj_id else: ret_dict['filetype'] = 'Unknown' diff --git a/seahub/templates/shared_file_view.html b/seahub/templates/shared_file_view.html index 85680ee4b3..b21940679f 100644 --- a/seahub/templates/shared_file_view.html +++ b/seahub/templates/shared_file_view.html @@ -75,8 +75,6 @@ $(function () { }); {% if filetype == 'PDF' and use_pdfjs %} -{% elif filetype == 'PDF' and not use_pdfjs and not html_exists %} -{% elif filetype == 'Document' and not html_exists %} {% else %} function setFileViewAreaHeight() { var file_view = $('#file-view'); diff --git a/seahub/templates/snippets/file_view_js.html b/seahub/templates/snippets/file_view_js.html index 86af6317f2..362a306ca2 100644 --- a/seahub/templates/snippets/file_view_js.html +++ b/seahub/templates/snippets/file_view_js.html @@ -1,9 +1,6 @@ {% if filetype == 'Text' %} {% endif %} -{% if filetype == 'Document' or filetype == 'PDF' and not use_pdfjs %} - -{% endif %} {% if filetype == 'PDF' and use_pdfjs %} {% endif %} diff --git a/seahub/templates/snippets/office_convert_html.html b/seahub/templates/snippets/office_convert_html.html index 3135cf59d5..70d0dd058e 100644 --- a/seahub/templates/snippets/office_convert_html.html +++ b/seahub/templates/snippets/office_convert_html.html @@ -5,11 +5,6 @@
-
+
diff --git a/seahub/templates/snippets/office_convert_js.html b/seahub/templates/snippets/office_convert_js.html index ccfef689ce..f5a7792e02 100644 --- a/seahub/templates/snippets/office_convert_js.html +++ b/seahub/templates/snippets/office_convert_js.html @@ -1,148 +1,158 @@ {% load i18n %} - function prepareOfficePreviewToken(xhr, settings) { - xhr.setRequestHeader('X-Seafile-Office-Preview-Token', '{{ office_preview_token }}'); - } - /** - * @param {boolean} html_exists True if the html has already been converted. - * @param {number} page_num The number of pages of this document - * @param {string|undefined} outline The outline content of the converted html. - * If html_exists is true, then it is undefined since the outline is already rendered in the HTML. - */ - function load_document(html_exists, page_num) { - $('#convert-loading').remove(); - var base_page_url = "{% url 'office_convert_get_page' obj_id %}/", - page_urls = []; - for (var i = 1; i < page_num + 1; i++) { - page_urls.push(base_page_url + i + '.page'); +var OfficePreviewer = function(file_id, preview_token) { + this.file_id = file_id; + this.preview_token = preview_token; + this.total_pages = null; + + this.orig_page_width = null; + this.orig_page_height = null; + + this.server_processed_pages = 0; + this.current_loading_page = 1; + this.iframes = []; + + this.FIT_TO_WIDTH = 850; // hardcoded in seafevents + this.scale_ratio = 1; + + this.page_status_url = function(page) { + return "{% url 'office_convert_query_status' %}?" + + $.param({file_id: this.file_id, page: page}); + } + this.page_content_url = function(page) { + return "{% url 'office_convert_get_page' obj_id %}/" + page + '.page'; + } +}; + +OfficePreviewer.prototype.start = function() { + this.check_page_status(); + return this; +}; + +OfficePreviewer.prototype.check_page_status = function() { + var page = this.current_loading_page; + if (this.server_processed_pages >= page) { + this.load_page(page); + return; + } + $.ajax({ + context: this, + url: this.page_status_url(page), + cache: false, + dataType: 'json', + beforeSend: this.prepareOfficePreviewToken, + success: function(data) { + var status = data['status']; + switch (status) { + case 'PROCESSING': + setTimeout($.proxy(this.check_page_status, this), 2000); + break; + case 'ERROR': + var str = "{% trans "Document convertion failed." %}"; + $('#file-view').html('

' + str + '

'); + break; + case 'DONE': + var info = data['info']; + if (info) { + this.total_pages = info['final_pages']; + this.server_processed_pages = info['processed_pages']; + this.orig_page_width = info['page_width']; + this.orig_page_height = info['page_height']; + } + this.load_page(page); + } + }, + error: function(xhr, textStatus, errorThrown) { + var str; + if (xhr.responseText) { + str = "{% trans "Document convertion failed." %}"; + } else { + str = "{% trans "Failed. Please check the network." %}"; + } + $('#file-view').html('

' + str + '

'); + } + }); +}; + +OfficePreviewer.prototype.add_toolbar = function() { + $('#convert-loading').remove(); + $('#file-view').append('
'); + $('#pdf2html-toolbar-2') + .append('') + .css({'left': $(window).width()/2 - $('#pdf2html-toolbar-2').outerWidth(true)/2}); + + var scale_ratio_offset = 0.1; + $('#zoom-in, #zoom-out').click($.proxy(function(event) { + // zoom in/out + var scale_ratio = this.scale_ratio; + var op = event.target.id; + if (op == 'zoom-in') { + scale_ratio += scale_ratio_offset; + } else { + scale_ratio -= scale_ratio_offset; } - new pdf2htmlEX.Viewer({ - before_send: prepareOfficePreviewToken, - container_id : 'page-container', - sidebar_id : 'sidebar', - outline_id : 'outline', - page_urls : page_urls + if (scale_ratio <= 0) { + return ; + } + this.scale_ratio = scale_ratio; + + var self = this; + $(this.iframes).each(function(index, iframe) { + self.scale_iframe(iframe); }); - // zoom in, zoom out - var scale_ratio = 1, - scale_ratio_offset = 0.1; - var scale = function(ele, ratio) { - ele.css({ - 'transform':'scale(' + ratio + ')', - '-webkit-transform':'scale(' + ratio + ')', - '-ms-transform':'scale(' + ratio + ')', - 'transform-origin':'center 0%', - '-webkit-transform-origin':'center 0%', - '-ms-transform-origin':'center 0%' - }); - }; + this.set_page_container_size(); - $('#converted-html').append('
'); - $('#pdf2html-toolbar-2').append('').css({'left': $(window).width()/2 - $('#pdf2html-toolbar-2').outerWidth(true)/2}); + }, this)); +} - var file_cont = $('#file-view'), //file container - orig_pg_total_h; +OfficePreviewer.prototype.scale_iframe = function(iframe) { + iframe.contentWindow.postMessage({scale: this.scale_ratio}, "http://seafile-dev:8000"); +} - $('#zoom-in, #zoom-out').click(function() { - // get orig data before zoom in/out - var op = $(this).attr('id'), - pg_num = $('.pd').length, - orig_win_scrollTop = $(window).scrollTop(), - orig_pg_h, cur_pg, pg_h_offset; +OfficePreviewer.prototype.set_page_container_size = function(elt) { + // orig_page_height / h = orig_page_width / this.FIT_TO_WIDTH + elt = elt || $('.page-container'); + var h = this.orig_page_height * this.FIT_TO_WIDTH / this.orig_page_width; + elt.css({ + width: this.FIT_TO_WIDTH * this.scale_ratio, + height: h * this.scale_ratio + }); +} - if (!orig_pg_total_h && scale_ratio == 1) { - orig_pg_total_h = file_cont.height(); - } - - orig_pg_h = orig_pg_total_h*scale_ratio/pg_num; - cur_pg = (orig_win_scrollTop - $('#page-container').offset().top)/orig_pg_h; - - // zoom in/out - if (op == 'zoom-in') { - scale_ratio += scale_ratio_offset; - } else { - scale_ratio -= scale_ratio_offset; - } - if (scale_ratio <= 0) { - return ; - } - scale($('#page-container'), scale_ratio); - - // modify file container's height - file_cont.height(orig_pg_total_h*scale_ratio); - - // scroll to the right cur page - pg_h_offset = (orig_pg_total_h * scale_ratio_offset)/pg_num; - if (op == 'zoom-in') { - $(window).scrollTop(orig_win_scrollTop + cur_pg*pg_h_offset); - } else { - $(window).scrollTop(orig_win_scrollTop - cur_pg*pg_h_offset); - } - }); +OfficePreviewer.prototype.load_page = function(index) { + if (index == 1) { + this.add_toolbar(); + $('#file-view').css({'height': 'auto'}); } - {% if html_exists %} - load_document(true, {{ html_detail.page_num }}); - {% else %} + var page_container = $('
'); + this.set_page_container_size(page_container); + $('#pages').append(page_container); - function get_file_css() { - var css_href = "{% url 'office_convert_get_page' obj_id %}/file.css"; - $('head').append(''); + var iframe = $('