Consolidate the page thumbnail and staging folder thumbnail widgets.

Update the staging folder file image API end point to work
in the same way the document page image API works.
This commit is contained in:
Roberto Rosario
2016-11-16 19:05:56 -04:00
parent 1133577e4d
commit 4578eacce9
10 changed files with 286 additions and 320 deletions

View File

@@ -102,15 +102,6 @@ img.lazy-load-carousel {
height: 0px;
}
.tc {
margin: auto;
text-align: center;
}
.tc a {
text-align: center;
}
.img-nolazyload {
border: 1px solid black;
}
@@ -127,6 +118,10 @@ img.lazy-load-carousel {
visibility: visible;
}
.instance-image-widget {
text-align: center;
}
hr {
margin-top: 5px;
margin-bottom: 11px;
@@ -148,10 +143,6 @@ hr {
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
}
.a-caption {
color: white;
}
.radio ul li {
list-style-type:none;
}

View File

@@ -65,29 +65,6 @@ jQuery(document).ready(function() {
autoResize : true,
});
$('a.fancybox-staging').click(function(e) {
var $this = $(this);
$.get($this.attr('href'), function( result ) {
if (result.status == 'success') {
$.fancybox.open([
{
href : result.data,
title : $this.attr('title'),
openEffect : 'elastic',
closeEffect : 'elastic',
prevEffect : 'none',
nextEffect : 'none',
titleShow : true,
type : 'image',
autoResize : true,
},
]);
}
})
e.preventDefault();
})
$('img.lazy-load').lazyload({
appear: function(elements_left, settings) {
loadImage($(this));

View File

@@ -70,14 +70,13 @@ from .permissions import (
)
# Just import to initialize the search models
from .search import document_search, document_page_search # NOQA
from .settings import setting_display_size, setting_thumbnail_size
from .statistics import (
new_documents_per_month, new_document_pages_per_month,
new_document_pages_this_month, new_documents_this_month,
new_document_versions_per_month, total_document_per_month,
total_document_page_per_month, total_document_version_per_month
)
from .widgets import document_page_html_widget
from .widgets import DocumentThumbnailWidget, DocumentPageThumbnailWidget
class DocumentsApp(MayanAppConfig):
@@ -187,17 +186,14 @@ class DocumentsApp(MayanAppConfig):
model=DocumentPage, related='document',
)
# Document and document page thumbnail widget
document_thumbnail_widget = DocumentThumbnailWidget()
document_page_thumbnail_widget = DocumentPageThumbnailWidget()
SourceColumn(
source=Document, label=_('Thumbnail'),
func=lambda context: document_page_html_widget(
document_page=context['object'].latest_version.pages.first(),
click_view='rest_api:documentpage-image',
click_view_arguments_lazy=lambda: (
context['object'].latest_version.pages.first().pk,
), click_view_querydict={'size': setting_display_size.value},
gallery_name='documents:document_list',
size=setting_thumbnail_size.value,
title=getattr(context['object'], 'label', None),
func=lambda context: document_thumbnail_widget.render(
instance=context['object']
)
)
SourceColumn(
@@ -206,29 +202,18 @@ class DocumentsApp(MayanAppConfig):
SourceColumn(
source=DocumentPage, label=_('Thumbnail'),
func=lambda context: document_page_html_widget(
document_page=context['object'],
click_view='rest_api:documentpage-image',
click_view_arguments=(context['object'].pk,),
gallery_name='documents:document_page_list',
preview_click_view='documents:document_page_view',
size=setting_thumbnail_size.value,
title=unicode(context['object']),
func=lambda context: document_page_thumbnail_widget.render(
instance=context['object']
)
)
SourceColumn(
source=DocumentPageResult, label=_('Thumbnail'),
func=lambda context: document_page_html_widget(
document_page=context['object'],
click_view='rest_api:documentpage-image',
click_view_arguments=(context['object'].pk,),
gallery_name='documents:document_page_list',
preview_click_view='documents:document_page_view',
size=setting_thumbnail_size.value,
title=unicode(context['object']),
func=lambda context: document_page_thumbnail_widget.render(
instance=context['object']
)
)
SourceColumn(
source=DocumentPageResult, label=_('Type'),
attribute='document_version.document.document_type'
@@ -248,18 +233,11 @@ class DocumentsApp(MayanAppConfig):
SourceColumn(
source=DeletedDocument, label=_('Thumbnail'),
func=lambda context: document_page_html_widget(
document_page=context['object'].latest_version.pages.first(),
click_view='rest_api:documentpage-image',
click_view_arguments_lazy=lambda: (
context['object'].latest_version.pages.first().pk,
), click_view_querydict={'size': setting_display_size.value},
gallery_name='documents:delete_document_list',
size=setting_thumbnail_size.value,
title=getattr(context['object'], 'label', None),
disable_title_link=True
func=lambda context: document_thumbnail_widget.render(
instance=context['object']
)
)
SourceColumn(
source=DeletedDocument, label=_('Type'), attribute='document_type'
)

View File

@@ -15,12 +15,11 @@ LANGUAGE_CHOICES = [
]
namespace = Namespace(name='documents', label=_('Documents'))
setting_storage_backend = namespace.add_setting(
global_name='DOCUMENTS_STORAGE_BACKEND',
default='storage.backends.filebasedstorage.FileBasedStorage'
setting_display_size = namespace.add_setting(
global_name='DOCUMENTS_DISPLAY_SIZE', default='3600'
)
setting_preview_size = namespace.add_setting(
global_name='DOCUMENTS_PREVIEW_SIZE', default='640x480'
global_name='DOCUMENTS_PREVIEW_SIZE', default='800'
)
setting_print_size = namespace.add_setting(
global_name='DOCUMENTS_PRINT_SIZE', default='3600'
@@ -28,9 +27,6 @@ setting_print_size = namespace.add_setting(
setting_thumbnail_size = namespace.add_setting(
global_name='DOCUMENTS_THUMBNAIL_SIZE', default='50x50'
)
setting_display_size = namespace.add_setting(
global_name='DOCUMENTS_DISPLAY_SIZE', default='3600'
)
setting_recent_count = namespace.add_setting(
global_name='DOCUMENTS_RECENT_COUNT', default=40,
help_text=_(
@@ -38,6 +34,10 @@ setting_recent_count = namespace.add_setting(
'remember per user.'
)
)
setting_storage_backend = namespace.add_setting(
global_name='DOCUMENTS_STORAGE_BACKEND',
default='storage.backends.filebasedstorage.FileBasedStorage'
)
setting_zoom_percent_step = namespace.add_setting(
global_name='DOCUMENTS_ZOOM_PERCENT_STEP', default=25,
help_text=_(

View File

@@ -7,9 +7,9 @@ from django.utils.http import urlencode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext, ugettext_lazy as _
from converter.literals import DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL
from .settings import setting_display_size, setting_thumbnail_size
from .settings import (
setting_display_size, setting_preview_size, setting_thumbnail_size
)
class DocumentPageImageWidget(forms.widgets.Widget):
@@ -17,15 +17,19 @@ class DocumentPageImageWidget(forms.widgets.Widget):
final_attrs = self.build_attrs(attrs)
zoom = final_attrs.get('zoom')
rotation = final_attrs.get('rotation')
html_widget = InteractiveDocumentPageWidget()
if value:
output = []
output.append(
'<div class="full-height scrollable '
'mayan-page-wrapper-interactive" data-height-difference=230>'
)
output.append(document_page_html_widget(
value, zoom=zoom, rotation=rotation, image_class='lazy-load',
nolazyload=False, size=setting_display_size.value)
output.append(
html_widget.render(
instance=value, zoom=zoom, rotation=rotation,
)
)
output.append('</div>')
return mark_safe(''.join(output))
@@ -38,6 +42,8 @@ class DocumentPagesCarouselWidget(forms.widgets.Widget):
Display many small representations of a document pages
"""
def render(self, name, value, attrs=None):
html_widget = CarouselDocumentPageThumbnailWidget()
output = []
output.append(
'<div id="carousel-container" class="full-height scrollable" '
@@ -50,15 +56,9 @@ class DocumentPagesCarouselWidget(forms.widgets.Widget):
for document_page in document_pages:
output.append('<div class="carousel-item">')
output.append(
document_page_html_widget(
document_page=document_page,
click_view='documents:document_page_view',
click_view_arguments=(document_page.pk,),
fancybox_class='',
image_class='lazy-load-carousel',
size=setting_display_size.value,
)
html_widget.render(instance=document_page)
)
output.append(
'<div class="carousel-item-page-number">%s</div>' % ugettext(
'Page %(page_number)d of %(total_pages)d'
@@ -83,98 +83,212 @@ def document_link(document):
)
def document_page_html_widget(document_page, click_view=None, click_view_arguments=None, zoom=DEFAULT_ZOOM_LEVEL, rotation=DEFAULT_ROTATION, gallery_name=None, fancybox_class='fancybox', image_class='lazy-load', title=None, size=setting_thumbnail_size.value, nolazyload=False, disable_title_link=False, preview_click_view=None, click_view_querydict=None, click_view_arguments_lazy=None):
result = []
class InstanceImageWidget(object):
alt_text = _('Clickable image')
click_view_name = None
click_view_query_dict = {}
destination_view_name = None
destination_view_query_dict = {}
disable_title_link = False
fancybox_class = 'fancybox'
gallery_name = None
# TODO: update this to load a disk template
invalid_image_template = '<p>Invalid image</p>'
preview_view_name = None
preview_query_dict = {}
image_class = 'lazy-load'
title = None
alt_text = _('Document page image')
# Click view
def get_click_view_kwargs(self, instance):
return {
'pk': instance.pk
}
if not document_page:
return mark_safe(
'<div class="tc"><span class="fa-stack fa-lg"><i class="fa fa-file-o fa-stack-2x"></i><i class="fa fa-question fa-stack-1x text-danger"></i></span></div>'
def get_click_view_query_dict(self, instance):
return self.click_view_query_dict
def get_click_view_querystring(self, instance):
return urlencode(self.get_click_view_query_dict(instance=instance))
def get_click_view_url(self, instance):
return '{}?{}'.format(
reverse(
viewname=self.click_view_name,
kwargs=self.get_click_view_kwargs(instance=instance)
),
self.get_click_view_querystring(instance=instance)
)
document = document_page.document
# Destination view
def get_destination_view_querystring(self, instance):
return urlencode(self.get_destination_view_query_dict(instance=instance))
query_dict = {
'zoom': zoom or DEFAULT_ZOOM_LEVEL,
'rotation': rotation or DEFAULT_ROTATION,
'size': size,
'page': document_page.page_number
}
if gallery_name:
gallery_template = 'rel="%s"' % gallery_name
else:
gallery_template = ''
query_string = urlencode(query_dict)
preview_view = '%s?%s' % (
reverse('rest_api:documentpage-image', args=(document_page.pk,)),
query_string
)
result.append(
'<div class="tc" id="document-%d-%d">' % (
document.pk, document_page.page_number if document_page.page_number else 1
def get_destination_url(self, instance):
return '{}?{}'.format(
reverse(
viewname=self.destination_view_name,
kwargs=self.get_destination_view_kwargs(instance=instance)
),
self.get_destination_view_querystring(instance=instance)
)
)
if title:
if not disable_title_link:
if not preview_click_view:
preview_click_link = document.get_absolute_url()
def get_destination_view_kwargs(self, instance):
return {
'pk': instance.pk
}
# Preview view
def get_preview_view_kwargs(self, instance):
return {
'pk': instance.pk
}
def get_preview_view_query_dict(self, instance):
return self.preview_view_query_dict
def get_preview_view_querystring(self, instance):
return urlencode(self.get_preview_view_query_dict(instance=instance))
def get_preview_view_url(self, instance):
return '{}?{}'.format(
reverse(
viewname=self.preview_view_name,
kwargs=self.get_preview_view_kwargs(instance=instance)
),
self.get_preview_view_querystring(instance=instance)
)
def get_title(self, instance):
return self.title
def is_valid(self, instance):
return instance
def render(self, instance):
result = []
result.append('<div class="instance-image-widget">')
if not self.is_valid(instance=instance):
result.append(self.invalid_image_template)
else:
if self.gallery_name:
gallery_markup = 'rel="%s"' % self.gallery_name
else:
preview_click_link = reverse(
preview_click_view, args=(document_page.pk,)
gallery_markup = ''
if self.click_view_name:
click_full_url = self.get_click_view_url(instance=instance)
title = self.get_title(instance=instance)
if title:
if not self.disable_title_link:
title_markup = 'data-caption="<a class=\'a-caption\' href=\'{url}\'>{title} <i class=\'fa fa-external-link\'></i></a>"'.format(
title=strip_tags(title), url=self.get_destination_url(instance=instance) or '#'
)
else:
title_markup = 'data-caption="{title}"'.format(
title=strip_tags(title),
)
else:
title_markup = ''
result.append(
'<a {gallery_markup} class="{fancybox_class}" '
'href="{click_full_url}" {title_markup}>'.format(
gallery_markup=gallery_markup,
fancybox_class=self.fancybox_class,
click_full_url=click_full_url,
title_markup=title_markup
)
)
title_template = 'data-caption="<a class=\'a-caption\' href=\'{url}\'>{title}</a>"'.format(
title=strip_tags(title), url=preview_click_link or '#'
result.append(
'<i class="spinner fa fa-spinner fa-pulse fa-3x fa-fw"></i> '
'<img class="thin_border {image_class}" '
'data-url="{preview_full_url}" src="#" '
'alt="{alt_text}" /> '.format(
image_class=self.image_class,
preview_full_url=self.get_preview_view_url(instance=instance),
alt_text=self.alt_text
)
)
else:
title_template = 'data-caption="{title}"'.format(
title=strip_tags(title),
)
else:
title_template = ''
if click_view:
if click_view_arguments_lazy:
click_view_arguments = click_view_arguments_lazy()
if self.click_view_name:
result.append('</a>')
result.append(
'<a {gallery_template} class="{fancybox_class}" '
'href="{image_data}" {title_template}>'.format(
gallery_template=gallery_template,
fancybox_class=fancybox_class,
image_data='%s?%s' % (
reverse(
click_view, args=click_view_arguments
), urlencode(click_view_querydict or {})
),
title_template=title_template
)
)
result.append('</div>')
if nolazyload:
result.append(
'<img class="img-nolazyload" src="%s" alt="%s" />' % (
preview_view, alt_text
)
)
else:
result.append(
'<i class="spinner fa fa-spinner fa-pulse fa-3x fa-fw"></i> '
'<img class="thin_border {}" data-url="{}" '
'src="{}" alt="{}" />'.format(
image_class, preview_view,
'', alt_text
)
)
return mark_safe(''.join(result))
if click_view:
result.append('</a>')
result.append('</div>')
return mark_safe(''.join(result))
class BaseDocumentThumbnailWidget(InstanceImageWidget):
alt_text = _('Document page image')
click_view_name = 'rest_api:documentpage-image'
click_view_query_dict = {
'size': setting_preview_size.value
}
gallery_name = 'document_list'
invalid_image_template = """
<span class="fa-stack fa-lg"><i class="fa fa-file-o fa-stack-2x"></i><i class="fa fa-question fa-stack-1x text-danger"></i></span>
"""
preview_view_name = 'rest_api:documentpage-image'
preview_view_query_dict = {
'size': setting_thumbnail_size.value
}
def get_destination_url(self, instance):
return instance.get_absolute_url()
class CarouselDocumentPageThumbnailWidget(BaseDocumentThumbnailWidget):
click_view_name = 'documents:document_page_view'
fancybox_class = ''
image_class = 'lazy-load-carousel'
preview_view_query_dict = {
'size': setting_display_size.value
}
class DocumentThumbnailWidget(BaseDocumentThumbnailWidget):
def get_click_view_kwargs(self, instance):
return {
'pk': instance.latest_version.pages.first().pk
}
def get_preview_view_kwargs(self, instance):
return {
'pk': instance.latest_version.pages.first().pk
}
def get_title(self, instance):
return getattr(instance, 'label', None)
def is_valid(self, instance):
return instance.latest_version.pages.all()
class DocumentPageThumbnailWidget(BaseDocumentThumbnailWidget):
def get_title(self, instance):
return unicode(instance)
class InteractiveDocumentPageWidget(BaseDocumentThumbnailWidget):
click_view_name = None
def get_preview_view_query_dict(self, instance):
return {
'zoom': self.zoom,
'rotation': self.rotation,
'size': setting_display_size.value,
}
def render(self, instance, *args, **kwargs):
self.zoom = kwargs.pop('zoom')
self.rotation = kwargs.pop('rotation')
return super(
InteractiveDocumentPageWidget, self
).render(instance=instance, *args, **kwargs)

View File

@@ -1,19 +1,14 @@
from __future__ import unicode_literals
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from converter.exceptions import UnkownConvertError, UnknownFileFormat
from converter.models import Transformation
from rest_framework import generics
from rest_framework.response import Response
from documents.settings import setting_display_size
from .models import StagingFolderSource
from .serializers import (
StagingFolderFileSerializer,
StagingFolderSerializer, StagingSourceFileImageSerializer
)
from .serializers import StagingFolderFileSerializer, StagingFolderSerializer
class APIStagingSourceFileView(generics.GenericAPIView):
@@ -51,47 +46,37 @@ class APIStagingSourceView(generics.RetrieveAPIView):
queryset = StagingFolderSource.objects.all()
class APIStagingSourceFileImageView(generics.GenericAPIView):
class APIStagingSourceFileImageView(generics.RetrieveAPIView):
"""
Image of the selected staging file.
size -- 'x' seprated width and height of the desired image representation.
page -- Page number of the staging file to be imaged.
zoom -- Zoom level of the image to be generated, numeric value only.
Returns an image representation of the selected document.
---
GET:
omit_serializer: true
parameters:
- name: size
description: 'x' seprated width and height of the desired image representation.
paramType: query
type: number
"""
serializer_class = StagingSourceFileImageSerializer
def get_serializer_class(self):
return None
def get(self, request, staging_folder_pk, encoded_filename):
def retrieve(self, request, *args, **kwargs):
staging_folder = get_object_or_404(
StagingFolderSource, pk=staging_folder_pk
StagingFolderSource, pk=self.kwargs['staging_folder_pk']
)
staging_file = staging_folder.get_file(
encoded_filename=encoded_filename
encoded_filename=self.kwargs['encoded_filename']
)
size = request.GET.get('size', setting_display_size.value)
size = request.GET.get('size')
try:
return Response({
'status': 'success',
'data': staging_file.get_image(
as_base64=True, size=size,
transformations=Transformation.objects.get_for_model(
staging_folder, as_classes=True
)
return HttpResponse(
staging_file.get_image(
size=size,
transformations=Transformation.objects.get_for_model(
staging_folder, as_classes=True
)
})
except UnknownFileFormat as exception:
return Response(
{
'status': 'error', 'detail': 'unknown_file_format',
'message': unicode(exception)
}
)
except UnkownConvertError as exception:
return Response(
{
'status': 'error', 'detail': 'converter_error',
'message': unicode(exception)
}
)
), content_type='image'
)

View File

@@ -29,7 +29,7 @@ from .links import (
link_setup_source_edit, link_setup_source_logs, link_staging_file_delete,
link_upload_version
)
from .widgets import staging_file_thumbnail
from .widgets import StagingFileThumbnailWidget
class SourcesApp(MayanAppConfig):
@@ -67,13 +67,12 @@ class SourcesApp(MayanAppConfig):
func=lambda context: context['object'].get_date_time_created()
)
html_widget = StagingFileThumbnailWidget()
SourceColumn(
source=StagingFile,
label=_('Thumbnail'),
func=lambda context: staging_file_thumbnail(
context['object'],
gallery_name='sources:staging_list',
title=context['object'].filename, size='100'
func=lambda context: html_widget.render(
instance=context['object'],
)
)

View File

@@ -71,7 +71,7 @@ class StagingFile(object):
def get_full_path(self):
return os.path.join(self.staging_folder.folder_path, self.filename)
def get_image(self, size=None, as_base64=True, transformations=None):
def get_image(self, size=None, as_base64=False, transformations=None):
converter = converter_class(file_object=open(self.get_full_path()))
if size:

View File

@@ -46,11 +46,6 @@ class StagingFolderSerializer(serializers.HyperlinkedModelSerializer):
model = StagingFolderSource
class StagingSourceFileImageSerializer(serializers.Serializer):
status = serializers.CharField()
data = serializers.CharField()
class WebFormSourceSerializer(serializers.Serializer):
class Meta:
model = WebFormSource

View File

@@ -1,105 +1,32 @@
from __future__ import unicode_literals
from django.contrib.staticfiles.templatetags.staticfiles import static
from django.core.urlresolvers import reverse
from django.utils.html import strip_tags
from django.utils.http import urlencode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from converter.literals import (
DEFAULT_PAGE_NUMBER, DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL
)
from documents.settings import setting_preview_size, setting_thumbnail_size
from documents.widgets import BaseDocumentThumbnailWidget
def staging_file_thumbnail(staging_file, **kwargs):
return staging_file_html_widget(
staging_file, click_view='rest_api:stagingfolderfile-image-view',
**kwargs
)
def staging_file_html_widget(staging_file, click_view=None, page=DEFAULT_PAGE_NUMBER, zoom=DEFAULT_ZOOM_LEVEL, rotation=DEFAULT_ROTATION, gallery_name=None, fancybox_class='fancybox-staging', image_class='lazy-load', title=None, size=setting_thumbnail_size.value, nolazyload=False):
result = []
alt_text = _('Staging file page image')
query_dict = {
'page': page,
'zoom': zoom,
'rotation': rotation,
'size': size,
class StagingFileThumbnailWidget(BaseDocumentThumbnailWidget):
disable_title_link = True
gallery_name = 'sources:staging_list'
click_view_name = 'rest_api:stagingfolderfile-image-view'
click_view_query_dict = {
'size': setting_preview_size.value
}
preview_view_name = 'rest_api:stagingfolderfile-image-view'
preview_view_query_dict = {
'size': setting_thumbnail_size.value
}
if gallery_name:
gallery_template = 'rel="%s"' % gallery_name
else:
gallery_template = ''
def get_click_view_kwargs(self, instance):
return {
'staging_folder_pk': instance.staging_folder.pk,
'encoded_filename': instance.encoded_filename
}
query_string = urlencode(query_dict)
def get_preview_view_kwargs(self, instance):
return {
'staging_folder_pk': instance.staging_folder.pk,
'encoded_filename': instance.encoded_filename
}
preview_view = '%s?%s' % (
reverse(
'rest_api:stagingfolderfile-image-view',
args=(
staging_file.staging_folder.pk, staging_file.encoded_filename,
)
), query_string
)
plain_template = []
plain_template.append(
'<img src="%s" alt="%s" />' % (preview_view, alt_text)
)
result.append(
'<div class="tc" id="staging_file-%s-%d">' % (
staging_file.filename, page if page else DEFAULT_PAGE_NUMBER
)
)
if title:
title_template = 'title="%s"' % strip_tags(title)
else:
title_template = ''
if click_view:
# TODO: fix this hack
query_dict['size'] = setting_preview_size.value
query_string = urlencode(query_dict)
result.append(
'<a %s class="%s" href="%s" %s>' % (
gallery_template, fancybox_class,
'%s?%s' % (
reverse(
click_view,
args=(
staging_file.staging_folder.pk,
staging_file.encoded_filename,
)
),
query_string
), title_template
)
)
if nolazyload:
result.append(
'<img style="border: 1px solid black;" src="%s" alt="%s" />' % (
preview_view, alt_text
)
)
else:
result.append(
'<img class="thin_border %s" data-src="%s" src="%s" alt="%s" />' % (
image_class, preview_view,
static('appearance/images/loading.png'), alt_text
)
)
if click_view:
result.append('</a>')
result.append('</div>')
return mark_safe(''.join(result))
def get_title(self, instance):
return instance.filename