Commit 297aee23 authored by Liam Brenner's avatar Liam Brenner
Browse files

WIP

parent 29c5409c
default_app_config = 'wagtailvideos.apps.WagtailVideosApp'
from django.apps import AppConfig
from django.core.checks import Error, register
from wagtailvideos.utils import which
def ffmpeg_check(app_configs, path=None, **kwargs):
errors = []
if which('ffmpeg', path=path) is None:
errors.append(
Error(
'ffmpeg could not be found on your system, try installing it.',
hint=None,
obj='SystemCheckError',
id='wagtailvideos.E001',
)
)
return errors
class WagtailVideosApp(AppConfig):
name = 'wagtailvideos'
label = 'wagtailvideos'
verbose_name = 'Wagtail Videos'
def ready(self):
register(ffmpeg_check)
import os
from django.conf import settings
from django.core.exceptions import ValidationError
from django.forms.fields import FileField
from django.template.defaultfilters import filesizeformat
from django.utils.translation import ugettext_lazy as _
ALLOWED_EXTENSIONS = ['mov', 'mp4']
SUPPORTED_FORMATS_TEXT = _("MOV, MP4")
class WagtailVideoField(FileField):
def __init__(self, *args, **kwargs):
super(WagtailVideoField, self).__init__(*args, **kwargs)
# Get max upload size from settings
self.max_upload_size = getattr(settings, 'WAGTAILVIDEOS_MAX_UPLOAD_SIZE', 1024 * 1024 * 1024)
max_upload_size_text = filesizeformat(self.max_upload_size)
# Help text
if self.max_upload_size is not None:
self.help_text = _(
"Supported formats: %(supported_formats)s. Maximum filesize: %(max_upload_size)s."
) % {
'supported_formats': SUPPORTED_FORMATS_TEXT,
'max_upload_size': max_upload_size_text,
}
else:
self.help_text = _(
"Supported formats: %(supported_formats)s."
) % {
'supported_formats': SUPPORTED_FORMATS_TEXT,
}
# Error messages
self.error_messages['invalid_image'] = _(
"Not a supported image format. Supported formats: %s."
) % SUPPORTED_FORMATS_TEXT
self.error_messages['invalid_video_known_format'] = _(
"Not a valid %s video."
)
self.error_messages['file_too_large'] = _(
"This file is too big (%%s). Maximum filesize %s."
) % max_upload_size_text
self.error_messages['file_too_large_unknown_size'] = _(
"This file is too big. Maximum filesize %s."
) % max_upload_size_text
def check_video_file_format(self, f):
# Check file extension
extension = os.path.splitext(f.name)[1].lower()[1:]
if extension not in ALLOWED_EXTENSIONS:
raise ValidationError(self.error_messages['invalid_video'], code='invalid_video')
if hasattr(f, 'video'):
# Django 1.8 annotates the file object with the PIL image
pass
elif not f.closed:
# Open image file
file_position = f.tell()
f.seek(0)
f.seek(file_position)
else:
# Couldn't get the PIL image, skip checking the internal file format
return
def check_video_file_size(self, f):
# Upload size checking can be disabled by setting max upload size to None
if self.max_upload_size is None:
return
# Check the filesize
if f.size > self.max_upload_size:
raise ValidationError(self.error_messages['file_too_large'] % (
filesizeformat(f.size),
), code='file_too_large')
def to_python(self, data):
f = super(WagtailVideoField, self).to_python(data)
if f is not None:
self.check_video_file_size(f)
self.check_video_file_format(f)
return f
from django.utils.html import escape
from wagtail.utils.apps import get_app_submodules
from .shortcuts import get_rendition_or_not_found
class Format(object):
def __init__(self, name, label, classnames, filter_spec):
self.name = name
self.label = label
self.classnames = classnames
self.filter_spec = filter_spec
def editor_attributes(self, video, alt_text):
"""
Return string of additional attributes to go on the HTML element
when outputting this image within a rich text editor field
"""
return 'data-embedtype="image" data-id="%d" data-format="%s" data-alt="%s" ' % (
video.id, self.name, alt_text
)
def video_to_editor_html(self, image, alt_text):
return self.image_to_html(
image, alt_text, self.editor_attributes(image, alt_text)
)
def video_to_html(self, image, alt_text, extra_attributes=''):
rendition = get_rendition_or_not_found(image, self.filter_spec)
if self.classnames:
class_attr = 'class="%s" ' % escape(self.classnames)
else:
class_attr = ''
return '<img %s%ssrc="%s" width="%d" height="%d" alt="%s">' % (
extra_attributes, class_attr,
escape(rendition.url), rendition.width, rendition.height, alt_text
)
FORMATS = []
FORMATS_BY_NAME = {}
def register_video_format(format):
if format.name in FORMATS_BY_NAME:
raise KeyError("Image format '%s' is already registered" % format.name)
FORMATS_BY_NAME[format.name] = format
FORMATS.append(format)
def unregister_video_format(format_name):
global FORMATS
# handle being passed a format object rather than a format name string
try:
format_name = format_name.name
except AttributeError:
pass
try:
del FORMATS_BY_NAME[format_name]
FORMATS = [fmt for fmt in FORMATS if fmt.name != format_name]
except KeyError:
raise KeyError("Image format '%s' is not registered" % format_name)
def get_video_formats():
search_for_video_formats()
return FORMATS
def get_video_format(name):
search_for_video_formats()
return FORMATS_BY_NAME[name]
_searched_for_video_formats = False
def search_for_video_formats():
global _searched_for_video_formats
if not _searched_for_video_formats:
list(get_app_submodules('video_formats'))
_searched_for_video_formats = True
# Define default image formats
register_video_format(Format('fullwidth', 'Full width', 'richtext-image full-width', 'width-800'))
register_video_format(Format('left', 'Left-aligned', 'richtext-image left', 'width-500'))
register_video_format(Format('right', 'Right-aligned', 'richtext-image right', 'width-500'))
from django import forms
from django.forms.models import modelform_factory
from django.utils.translation import ugettext as _
from wagtail.wagtailadmin import widgets
from wagtail.wagtailadmin.forms import \
collection_member_permission_formset_factory
from wagtailvideos.fields import WagtailVideoField
from wagtailvideos.formats import get_video_formats
from wagtailvideos.models import Video
# Callback to allow us to override the default form field for the image file field
def formfield_for_dbfield(db_field, **kwargs):
# Check if this is the file field
if db_field.name == 'file':
return WagtailVideoField(**kwargs)
# For all other fields, just call its formfield() method.
return db_field.formfield(**kwargs)
def get_video_form(model):
fields = model.admin_form_fields
if 'collection' not in fields:
# force addition of the 'collection' field, because leaving it out can
# cause dubious results when multiple collections exist (e.g adding the
# document to the root collection where the user may not have permission) -
# and when only one collection exists, it will get hidden anyway.
fields = list(fields) + ['collection']
return modelform_factory(
model,
fields=fields,
formfield_callback=formfield_for_dbfield,
# set the 'file' widget to a FileInput rather than the default ClearableFileInput
# so that when editing, we don't get the 'currently: ...' banner which is
# a bit pointless here
widgets={
'tags': widgets.AdminTagWidget,
'file': forms.FileInput(),
'focal_point_x': forms.HiddenInput(attrs={'class': 'focal_point_x'}),
'focal_point_y': forms.HiddenInput(attrs={'class': 'focal_point_y'}),
'focal_point_width': forms.HiddenInput(attrs={'class': 'focal_point_width'}),
'focal_point_height': forms.HiddenInput(attrs={'class': 'focal_point_height'}),
})
class VideoInsertionForm(forms.Form):
"""
Form for selecting parameters of the image (e.g. format) prior to insertion
into a rich text area
"""
format = forms.ChoiceField(
choices=[(format.name, format.label) for format in get_video_formats()],
widget=forms.RadioSelect
)
alt_text = forms.CharField()
class URLGeneratorForm(forms.Form):
filter_method = forms.ChoiceField(
label=_("Filter"),
choices=(
('original', _("Original size")),
('width', _("Resize to width")),
('height', _("Resize to height")),
('min', _("Resize to min")),
('max', _("Resize to max")),
('fill', _("Resize to fill")),
),
)
width = forms.IntegerField(_("Width"), min_value=0)
height = forms.IntegerField(_("Height"), min_value=0)
closeness = forms.IntegerField(_("Closeness"), min_value=0, initial=0)
GroupImagePermissionFormSet = collection_member_permission_formset_factory(
Video,
[
('add_image', _("Add"), _("Add/edit images you own")),
('change_image', _("Edit"), _("Edit any image")),
],
'wagtailimages/permissions/includes/image_permissions_formset.html'
)
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-03-02 01:50
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import taggit.managers
import wagtail.wagtailadmin.taggable
import wagtail.wagtailcore.models
import wagtailvideos.models
class Migration(migrations.Migration):
initial = True
dependencies = [
('wagtailcore', '0028_merge'),
('taggit', '0002_auto_20150616_2121'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Video',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, verbose_name='title')),
('file', models.ImageField(height_field='height', upload_to=wagtailvideos.models.get_upload_to, verbose_name='file', width_field='width')),
('created_at', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='created at')),
('file_size', models.PositiveIntegerField(editable=False, null=True)),
('collection', models.ForeignKey(default=wagtail.wagtailcore.models.get_root_collection_id, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Collection', verbose_name='collection')),
('tags', taggit.managers.TaggableManager(blank=True, help_text=None, through='taggit.TaggedItem', to='taggit.Tag', verbose_name='tags')),
('uploaded_by_user', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='uploaded by user')),
],
options={
'abstract': False,
},
bases=(models.Model, wagtail.wagtailadmin.taggable.TagSearchable),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-03-21 05:10
from __future__ import unicode_literals
from django.db import migrations, models
import wagtailvideos.models
class Migration(migrations.Migration):
dependencies = [
('wagtailvideos', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='video',
name='thumbnail',
field=models.ImageField(default='', upload_to=''),
preserve_default=False,
),
migrations.AlterField(
model_name='video',
name='file',
field=models.FileField(upload_to=wagtailvideos.models.get_upload_to, verbose_name='file'),
),
]
from __future__ import unicode_literals
import os
import os.path
import shutil
import subprocess
import tempfile
from tempfile import NamedTemporaryFile
from PIL import Image
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.files.base import ContentFile
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.six import StringIO
from django.utils.translation import ugettext_lazy as _
from taggit.managers import TaggableManager
from unidecode import unidecode
from wagtail.wagtailadmin.taggable import TagSearchable
from wagtail.wagtailadmin.utils import get_object_usage
from wagtail.wagtailcore.models import CollectionMember
from wagtail.wagtailsearch import index
from wagtail.wagtailsearch.queryset import SearchableQuerySetMixin
class ImageQuerySet(SearchableQuerySetMixin, models.QuerySet):
pass
def get_upload_to(instance, filename):
# Dumb proxy to instance method.
return instance.get_upload_to(filename)
@python_2_unicode_compatible
class AbstractVideo(CollectionMember, TagSearchable):
title = models.CharField(max_length=255, verbose_name=_('title'))
file = models.FileField(
verbose_name=_('file'), upload_to=get_upload_to)
thumbnail = models.ImageField()
created_at = models.DateTimeField(verbose_name=_('created at'), auto_now_add=True, db_index=True)
uploaded_by_user = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_('uploaded by user'),
null=True, blank=True, editable=False, on_delete=models.SET_NULL
)
tags = TaggableManager(help_text=None, blank=True, verbose_name=_('tags'))
file_size = models.PositiveIntegerField(null=True, editable=False)
objects = ImageQuerySet.as_manager()
def is_stored_locally(self):
"""
Returns True if the image is hosted on the local filesystem
"""
try:
self.file.path
return True
except NotImplementedError:
return False
def get_file_size(self):
if self.file_size is None:
try:
self.file_size = self.file.size
except OSError:
# File doesn't exist
return
self.save(update_fields=['file_size'])
return self.file_size
def get_upload_to(self, filename):
folder_name = 'original_images'
filename = self.file.field.storage.get_valid_name(filename)
# do a unidecode in the filename and then
# replace non-ascii characters in filename with _ , to sidestep issues with filesystem encoding
filename = "".join((i if ord(i) < 128 else '_') for i in unidecode(filename))
# Truncate filename so it fits in the 100 character limit
# https://code.djangoproject.com/ticket/9893
while len(os.path.join(folder_name, filename)) >= 95:
prefix, dot, extension = filename.rpartition('.')
filename = prefix[:-1] + dot + extension
return os.path.join(folder_name, filename)
def get_usage(self):
return get_object_usage(self)
@property
def usage_url(self):
return reverse('wagtailvideos:image_usage',
args=(self.id,))
search_fields = TagSearchable.search_fields + CollectionMember.search_fields + (
index.FilterField('uploaded_by_user'),
)
def __str__(self):
return self.title
def get_rendition(self, filter):
pass # TODO
def get_thumbnail(self):
file_path = self.file.path
try:
output_dir = tempfile.mkdtemp()
output_file = os.path.join(output_dir, 'thumbnail.jpg')
try:
FNULL = open(os.devnull, 'r')
subprocess.check_call([
'ffmpeg',
'-itsoffset',
'-4',
'-i', file_path,
'-vcodec', 'mjpeg',
'-vframes', '1',
'-an', '-f', 'rawvideo',
'-s', '320x240',
output_file,
], stdin=FNULL)
except subprocess.CalledProcessError:
return None
return ContentFile(open(output_file, 'rb').read(), 'thumb.jpg')
finally:
shutil.rmtree(output_dir, ignore_errors=True)
def save(self, **kwargs):
self.thumbnail = self.get_thumbnail()
super(AbstractVideo, self).save(**kwargs)
@property
def filename(self):
return os.path.basename(self.file.name)
@property
def default_alt_text(self):
# by default the alt text field (used in rich text insertion) is populated
# from the title. Subclasses might provide a separate alt field, and
# override this
return self.title
def is_editable_by_user(self, user):
from wagtail.wagtailimages.permissions import permission_policy
return permission_policy.user_has_permission_for_instance(user, 'change', self)
class Meta:
abstract = True
class Video(AbstractVideo):
admin_form_fields = (
'title',
'file',
'collection',
'tags',
)
def get_video_model():
from django.conf import settings
from django.apps import apps
try:
app_label, model_name = settings.WAGTAILVIDEOS_VIDEO_MODEL.split('.')
except AttributeError:
return Video
except ValueError:
raise ImproperlyConfigured("WAGTAILIMAGES_IMAGE_MODEL must be of the form 'app_label.model_name'")
image_model = apps.get_model(app_label, model_name)
if image_model is None:
raise ImproperlyConfigured(
"WAGTAILIMAGES_IMAGE_MODEL refers to model '%s' that has not been installed" %
settings.WAGTAILIMAGES_IMAGE_MODEL
)
return image_model
from wagtail.wagtailcore.permission_policies.collections import \
CollectionOwnershipPermissionPolicy
from wagtailvideos.models import Video, get_video_model
permission_policy = CollectionOwnershipPermissionPolicy(
get_video_model(),
auth_model=Video,
owner_field_name='uploaded_by_user'
)
# coding=utf-8
def get_rendition_or_not_found(image, specs):
"""
Tries to get / create the rendition for the image or renders a not-found image if it does not exist.
:param image: AbstractImage
:param specs: str or Filter
:return: Rendition
"""
try:
return image.get_rendition(specs)
except image.DoesNotExist:
# Image file is (probably) missing from /media/original_images - generate a dummy
# rendition so that we just output a broken image, rather than crashing out completely
# during rendering.
Rendition = image.renditions.model # pick up any custom Image / Rendition classes that may be in use
rendition = Rendition(image=image, width=0, height=0)
rendition.file.name = 'not-found'
return rendition
.visuallyhidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.visuallyhidden:active, .visuallyhidden:focus {
clip: auto;
height: auto;
margin: 0;
overflow: visible;
position: static;
width: auto;
}
.visuallyvisible {
clip: none;
height: auto;
width: auto;
margin: auto;
overflow: visible;
position: initial;
}
.replace-file-input {
display: inline-block;
position: relative;
overflow: hidden;
padding-bottom: 2px;
}
.replace-file-input [type=file] {
padding: 0;
opacity: 0;
position: absolute;
top: 0;
right: 0;
direction: ltr;
width: auto;
display: block;
font-size: 5em;
}
.replace-file-input [type=file]:hover {
cursor: pointer;
}
.replace-file-input:hover {
cursor: pointer;
}
.replace-file-input:hover button {
background-color: #358c8b;
}
.upload-list > li {
padding: 1em;
}
.upload-list .left {
text-align: center;
}
.upload-list .preview {
width: 150px;
min-height: 150px;
display: block;
position: relative;
text-align: center;
max-width: 100%;
margin: auto;
}
.upload-list .progress,
.upload-list .thumb,
.upload-list .thumb:before,
.upload-list canvas,
.upload-list img {
position: absolute;
max-width: 100%;
}
.upload-list .progress {
box-shadow: 0 0 5px 2px rgba(255, 255, 255, 0.4);
z-index: 4;
top: 60%;
left: 20%;
right: 20%;
width: 60%;
}
.upload-list .thumb {
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
}
.upload-list .thumb:before,
.upload-list canvas,
.upload-list img {
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
}
.upload-list .thumb:before {
z-index: 2;
top: 0;
width: 1em;
font-size: 10em;
line-height: 1.4em;
color: #f0f0f0;
}
.upload-list canvas,
.upload-list img {
z-index: 3;
}
.upload-list .hasthumb:before {
display: none;
}
.upload-list .status-msg {
display: none;
}
.upload-list .upload-complete .progress {
opacity: 0;
}
.upload-list .upload-success .status-msg.success {
display: block;
}
.upload-list .upload-failure {
border-color: #cd3238;
}
.upload-list .upload-failure .preview {
display: none;
}
.upload-list .upload-failure .status-msg.failure {
display: block;
}
/* jquery.Jcrop.min.css v0.9.12 (build:20130126) */
.jcrop-holder{direction:ltr;text-align:left;}
.jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif);font-size:0;position:absolute;}
.jcrop-vline{height:100%;width:1px!important;}
.jcrop-vline.right{right:0;}
.jcrop-hline{height:1px!important;width:100%;}
.jcrop-hline.bottom{bottom:0;}
.jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;}
.jcrop-handle{background-color:#333;border:1px #EEE solid;font-size:1px;height:7px;width:7px;}
.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;}
.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;}
.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;}
.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;}
.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;}
.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;}
.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;}
.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;}
.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;}
.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;}
.jcrop-dragbar.ord-n{margin-top:-4px;}
.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;}
.jcrop-dragbar.ord-e{margin-right:-4px;right:0;}
.jcrop-dragbar.ord-w{margin-left:-4px;}
.jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:alpha(opacity=70)!important;opacity:.70!important;}
.jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;}
.jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important;}
.jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;}
.solid-line .jcrop-vline,.solid-line .jcrop-hline{background:#FFF;}
.jcrop-holder img,img.jcrop-preview{max-width:none;}
$(function() {
// Redirect users that don't support filereader
if (!$('html').hasClass('filereader')) {
document.location.href = window.fileupload_opts.simple_upload_url;
return false;
}
// prevents browser default drag/drop
$(document).bind('drop dragover', function(e) {
e.preventDefault();
});
$('#fileupload').fileupload({
dataType: 'html',
sequentialUploads: true,
dropZone: $('.drop-zone'),
acceptFileTypes: window.fileupload_opts.accepted_file_types,
maxFileSize: window.fileupload_opts.max_file_size,
previewMinWidth:150,
previewMaxWidth:150,
previewMinHeight:150,
previewMaxHeight:150,
messages: {
acceptFileTypes: window.fileupload_opts.errormessages.accepted_file_types,
maxFileSize: window.fileupload_opts.errormessages.max_file_size
},
add: function(e, data) {
$('.messages').empty();
var $this = $(this);
var that = $this.data('blueimp-fileupload') || $this.data('fileupload')
var li = $($('#upload-list-item').html()).addClass('upload-uploading')
var options = that.options;
$('#upload-list').append(li);
data.context = li;
data.process(function() {
return $this.fileupload('process', data);
}).always(function() {
data.context.removeClass('processing');
data.context.find('.left').each(function(index, elm) {
$(elm).append(escapeHtml(data.files[index].name));
});
data.context.find('.preview .thumb').each(function(index, elm) {
$(elm).addClass('hasthumb')
$(elm).append(data.files[index].preview);
});
}).done(function() {
data.context.find('.start').prop('disabled', false);
if ((that._trigger('added', e, data) !== false) &&
(options.autoUpload || data.autoUpload) &&
data.autoUpload !== false) {
data.submit()
}
}).fail(function() {
if (data.files.error) {
data.context.each(function(index) {
var error = data.files[index].error;
if (error) {
$(this).find('.error_messages').text(error);
}
});
}
});
},
processfail: function(e, data) {
var itemElement = $(data.context);
itemElement.removeClass('upload-uploading').addClass('upload-failure');
},
progress: function(e, data) {
if (e.isDefaultPrevented()) {
return false;
}
var progress = Math.floor(data.loaded / data.total * 100);
data.context.each(function() {
$(this).find('.progress').addClass('active').attr('aria-valuenow', progress).find('.bar').css(
'width',
progress + '%'
).html(progress + '%');
});
},
progressall: function(e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#overall-progress').addClass('active').attr('aria-valuenow', progress).find('.bar').css(
'width',
progress + '%'
).html(progress + '%');
if (progress >= 100) {
$('#overall-progress').removeClass('active').find('.bar').css('width', '0%');
}
},
done: function(e, data) {
var itemElement = $(data.context);
var response = $.parseJSON(data.result);
if (response.success) {
itemElement.addClass('upload-success')
$('.right', itemElement).append(response.form);
} else {
itemElement.addClass('upload-failure');
$('.right .error_messages', itemElement).append(response.error_message);
}
},
fail: function(e, data) {
var itemElement = $(data.context);
itemElement.addClass('upload-failure');
},
always: function(e, data) {
var itemElement = $(data.context);
itemElement.removeClass('upload-uploading').addClass('upload-complete');
}
});
// ajax-enhance forms added on done()
$('#upload-list').on('submit', 'form', function(e) {
var form = $(this);
var itemElement = form.closest('#upload-list > li');
e.preventDefault();
$.post(this.action, form.serialize(), function(data) {
if (data.success) {
var statusText = $('.status-msg.update-success').text();
addMessage('success', statusText);
itemElement.slideUp(function() {$(this).remove()});
} else {
form.replaceWith(data.form);
// run tagit enhancement on new form
$('.tag_field input', form).tagit(window.tagit_opts);
}
});
});
$('#upload-list').on('click', '.delete', function(e) {
var form = $(this).closest('form');
var itemElement = form.closest('#upload-list > li');
e.preventDefault();
var CSRFToken = $('input[name="csrfmiddlewaretoken"]', form).val();
$.post(this.href, {csrfmiddlewaretoken: CSRFToken}, function(data) {
if (data.success) {
itemElement.slideUp(function() {$(this).remove()});
}
});
});
});
// Generated by CoffeeScript 1.6.2
(function() {
(function($) {
return $.widget('IKS.hallowagtailvideo', {
options: {
uuid: '',
editable: null
},
populateToolbar: function(toolbar) {
var button, widget;
widget = this;
button = $('<span class="' + this.widgetName + '"></span>');
button.hallobutton({
uuid: this.options.uuid,
editable: this.options.editable,
label: 'Videos',
icon: 'icon-video',
command: null
});
toolbar.append(button);
return button.on('click', function(event) {
var insertionPoint, lastSelection;
lastSelection = widget.options.editable.getSelection();
insertionPoint = $(lastSelection.endContainer).parentsUntil('.richtext').last();
return ModalWorkflow({
url: window.chooserUrls.videoChooser + '?select_format=true',
responses: {
videoChosen: function(videoData) {
var elem;
elem = $(videoData.html).get(0);
lastSelection.insertNode(elem);
if (elem.getAttribute('contenteditable') === 'false') {
insertRichTextDeleteControl(elem);
}
return widget.options.editable.element.trigger('change');
}
}
});
});
}
});
})(jQuery);
}).call(this);
!function(a){"use strict";var b=a.HTMLCanvasElement&&a.HTMLCanvasElement.prototype,c=a.Blob&&function(){try{return Boolean(new Blob)}catch(a){return!1}}(),d=c&&a.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(a){return!1}}(),e=a.BlobBuilder||a.WebKitBlobBuilder||a.MozBlobBuilder||a.MSBlobBuilder,f=(c||e)&&a.atob&&a.ArrayBuffer&&a.Uint8Array&&function(a){var b,f,g,h,i,j;for(b=a.split(",")[0].indexOf("base64")>=0?atob(a.split(",")[1]):decodeURIComponent(a.split(",")[1]),f=new ArrayBuffer(b.length),g=new Uint8Array(f),h=0;h<b.length;h+=1)g[h]=b.charCodeAt(h);return i=a.split(",")[0].split(":")[1].split(";")[0],c?new Blob([d?g:f],{type:i}):(j=new e,j.append(f),j.getBlob(i))};a.HTMLCanvasElement&&!b.toBlob&&(b.mozGetAsFile?b.toBlob=function(a,c,d){d&&b.toDataURL&&f?a(f(this.toDataURL(c,d))):a(this.mozGetAsFile("blob",c))}:b.toDataURL&&f&&(b.toBlob=function(a,b,c){a(f(this.toDataURL(b,c)))})),"function"==typeof define&&define.amd?define(function(){return f}):a.dataURLtoBlob=f}(this);
\ No newline at end of file
/**
* jquery.Jcrop.min.js v0.9.12 (build:20130202)
* jQuery Image Cropping Plugin - released under MIT License
* Copyright (c) 2008-2013 Tapmodo Interactive LLC
* https://github.com/tapmodo/Jcrop
*/
(function(a){a.Jcrop=function(b,c){function i(a){return Math.round(a)+"px"}function j(a){return d.baseClass+"-"+a}function k(){return a.fx.step.hasOwnProperty("backgroundColor")}function l(b){var c=a(b).offset();return[c.left,c.top]}function m(a){return[a.pageX-e[0],a.pageY-e[1]]}function n(b){typeof b!="object"&&(b={}),d=a.extend(d,b),a.each(["onChange","onSelect","onRelease","onDblClick"],function(a,b){typeof d[b]!="function"&&(d[b]=function(){})})}function o(a,b,c){e=l(D),bc.setCursor(a==="move"?a:a+"-resize");if(a==="move")return bc.activateHandlers(q(b),v,c);var d=_.getFixed(),f=r(a),g=_.getCorner(r(f));_.setPressed(_.getCorner(f)),_.setCurrent(g),bc.activateHandlers(p(a,d),v,c)}function p(a,b){return function(c){if(!d.aspectRatio)switch(a){case"e":c[1]=b.y2;break;case"w":c[1]=b.y2;break;case"n":c[0]=b.x2;break;case"s":c[0]=b.x2}else switch(a){case"e":c[1]=b.y+1;break;case"w":c[1]=b.y+1;break;case"n":c[0]=b.x+1;break;case"s":c[0]=b.x+1}_.setCurrent(c),bb.update()}}function q(a){var b=a;return bd.watchKeys
(),function(a){_.moveOffset([a[0]-b[0],a[1]-b[1]]),b=a,bb.update()}}function r(a){switch(a){case"n":return"sw";case"s":return"nw";case"e":return"nw";case"w":return"ne";case"ne":return"sw";case"nw":return"se";case"se":return"nw";case"sw":return"ne"}}function s(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=l(D),W=!0,o(a,m(b)),b.stopPropagation(),b.preventDefault(),!1)}}function t(a,b,c){var d=a.width(),e=a.height();d>b&&b>0&&(d=b,e=b/a.width()*a.height()),e>c&&c>0&&(e=c,d=c/a.height()*a.width()),T=a.width()/d,U=a.height()/e,a.width(d).height(e)}function u(a){return{x:a.x*T,y:a.y*U,x2:a.x2*T,y2:a.y2*U,w:a.w*T,h:a.h*U}}function v(a){var b=_.getFixed();b.w>d.minSelect[0]&&b.h>d.minSelect[1]?(bb.enableHandles(),bb.done()):bb.release(),bc.setCursor(d.allowSelect?"crosshair":"default")}function w(a){if(d.disabled)return!1;if(!d.allowSelect)return!1;W=!0,e=l(D),bb.disableHandles(),bc.setCursor("crosshair");var b=m(a);return _.setPressed(b),bb.update(),bc.activateHandlers(x,v,a.type.substring
(0,5)==="touch"),bd.watchKeys(),a.stopPropagation(),a.preventDefault(),!1}function x(a){_.setCurrent(a),bb.update()}function y(){var b=a("<div></div>").addClass(j("tracker"));return g&&b.css({opacity:0,backgroundColor:"white"}),b}function be(a){G.removeClass().addClass(j("holder")).addClass(a)}function bf(a,b){function t(){window.setTimeout(u,l)}var c=a[0]/T,e=a[1]/U,f=a[2]/T,g=a[3]/U;if(X)return;var h=_.flipCoords(c,e,f,g),i=_.getFixed(),j=[i.x,i.y,i.x2,i.y2],k=j,l=d.animationDelay,m=h[0]-j[0],n=h[1]-j[1],o=h[2]-j[2],p=h[3]-j[3],q=0,r=d.swingSpeed;c=k[0],e=k[1],f=k[2],g=k[3],bb.animMode(!0);var s,u=function(){return function(){q+=(100-q)/r,k[0]=Math.round(c+q/100*m),k[1]=Math.round(e+q/100*n),k[2]=Math.round(f+q/100*o),k[3]=Math.round(g+q/100*p),q>=99.8&&(q=100),q<100?(bh(k),t()):(bb.done(),bb.animMode(!1),typeof b=="function"&&b.call(bs))}}();t()}function bg(a){bh([a[0]/T,a[1]/U,a[2]/T,a[3]/U]),d.onSelect.call(bs,u(_.getFixed())),bb.enableHandles()}function bh(a){_.setPressed([a[0],a[1]]),_.setCurrent([a[2],
a[3]]),bb.update()}function bi(){return u(_.getFixed())}function bj(){return _.getFixed()}function bk(a){n(a),br()}function bl(){d.disabled=!0,bb.disableHandles(),bb.setCursor("default"),bc.setCursor("default")}function bm(){d.disabled=!1,br()}function bn(){bb.done(),bc.activateHandlers(null,null)}function bo(){G.remove(),A.show(),A.css("visibility","visible"),a(b).removeData("Jcrop")}function bp(a,b){bb.release(),bl();var c=new Image;c.onload=function(){var e=c.width,f=c.height,g=d.boxWidth,h=d.boxHeight;D.width(e).height(f),D.attr("src",a),H.attr("src",a),t(D,g,h),E=D.width(),F=D.height(),H.width(E).height(F),M.width(E+L*2).height(F+L*2),G.width(E).height(F),ba.resize(E,F),bm(),typeof b=="function"&&b.call(bs)},c.src=a}function bq(a,b,c){var e=b||d.bgColor;d.bgFade&&k()&&d.fadeTime&&!c?a.animate({backgroundColor:e},{queue:!1,duration:d.fadeTime}):a.css("backgroundColor",e)}function br(a){d.allowResize?a?bb.enableOnly():bb.enableHandles():bb.disableHandles(),bc.setCursor(d.allowSelect?"crosshair":"default"),bb
.setCursor(d.allowMove?"move":"default"),d.hasOwnProperty("trueSize")&&(T=d.trueSize[0]/E,U=d.trueSize[1]/F),d.hasOwnProperty("setSelect")&&(bg(d.setSelect),bb.done(),delete d.setSelect),ba.refresh(),d.bgColor!=N&&(bq(d.shade?ba.getShades():G,d.shade?d.shadeColor||d.bgColor:d.bgColor),N=d.bgColor),O!=d.bgOpacity&&(O=d.bgOpacity,d.shade?ba.refresh():bb.setBgOpacity(O)),P=d.maxSize[0]||0,Q=d.maxSize[1]||0,R=d.minSize[0]||0,S=d.minSize[1]||0,d.hasOwnProperty("outerImage")&&(D.attr("src",d.outerImage),delete d.outerImage),bb.refresh()}var d=a.extend({},a.Jcrop.defaults),e,f=navigator.userAgent.toLowerCase(),g=/msie/.test(f),h=/msie [1-6]\./.test(f);typeof b!="object"&&(b=a(b)[0]),typeof c!="object"&&(c={}),n(c);var z={border:"none",visibility:"visible",margin:0,padding:0,position:"absolute",top:0,left:0},A=a(b),B=!0;if(b.tagName=="IMG"){if(A[0].width!=0&&A[0].height!=0)A.width(A[0].width),A.height(A[0].height);else{var C=new Image;C.src=A[0].src,A.width(C.width),A.height(C.height)}var D=A.clone().removeAttr("id").
css(z).show();D.width(A.width()),D.height(A.height()),A.after(D).hide()}else D=A.css(z).show(),B=!1,d.shade===null&&(d.shade=!0);t(D,d.boxWidth,d.boxHeight);var E=D.width(),F=D.height(),G=a("<div />").width(E).height(F).addClass(j("holder")).css({position:"relative",backgroundColor:d.bgColor}).insertAfter(A).append(D);d.addClass&&G.addClass(d.addClass);var H=a("<div />"),I=a("<div />").width("100%").height("100%").css({zIndex:310,position:"absolute",overflow:"hidden"}),J=a("<div />").width("100%").height("100%").css("zIndex",320),K=a("<div />").css({position:"absolute",zIndex:600}).dblclick(function(){var a=_.getFixed();d.onDblClick.call(bs,a)}).insertBefore(D).append(I,J);B&&(H=a("<img />").attr("src",D.attr("src")).css(z).width(E).height(F),I.append(H)),h&&K.css({overflowY:"hidden"});var L=d.boundary,M=y().width(E+L*2).height(F+L*2).css({position:"absolute",top:i(-L),left:i(-L),zIndex:290}).mousedown(w),N=d.bgColor,O=d.bgOpacity,P,Q,R,S,T,U,V=!0,W,X,Y;e=l(D);var Z=function(){function a(){var a={},b=["touchstart"
,"touchmove","touchend"],c=document.createElement("div"),d;try{for(d=0;d<b.length;d++){var e=b[d];e="on"+e;var f=e in c;f||(c.setAttribute(e,"return;"),f=typeof c[e]=="function"),a[b[d]]=f}return a.touchstart&&a.touchend&&a.touchmove}catch(g){return!1}}function b(){return d.touchSupport===!0||d.touchSupport===!1?d.touchSupport:a()}return{createDragger:function(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=l(D),W=!0,o(a,m(Z.cfilter(b)),!0),b.stopPropagation(),b.preventDefault(),!1)}},newSelection:function(a){return w(Z.cfilter(a))},cfilter:function(a){return a.pageX=a.originalEvent.changedTouches[0].pageX,a.pageY=a.originalEvent.changedTouches[0].pageY,a},isSupported:a,support:b()}}(),_=function(){function h(d){d=n(d),c=a=d[0],e=b=d[1]}function i(a){a=n(a),f=a[0]-c,g=a[1]-e,c=a[0],e=a[1]}function j(){return[f,g]}function k(d){var f=d[0],g=d[1];0>a+f&&(f-=f+a),0>b+g&&(g-=g+b),F<e+g&&(g+=F-(e+g)),E<c+f&&(f+=E-(c+f)),a+=f,c+=f,b+=g,e+=g}function l(a){var b=m();switch(a){case"ne":return[
b.x2,b.y];case"nw":return[b.x,b.y];case"se":return[b.x2,b.y2];case"sw":return[b.x,b.y2]}}function m(){if(!d.aspectRatio)return p();var f=d.aspectRatio,g=d.minSize[0]/T,h=d.maxSize[0]/T,i=d.maxSize[1]/U,j=c-a,k=e-b,l=Math.abs(j),m=Math.abs(k),n=l/m,r,s,t,u;return h===0&&(h=E*10),i===0&&(i=F*10),n<f?(s=e,t=m*f,r=j<0?a-t:t+a,r<0?(r=0,u=Math.abs((r-a)/f),s=k<0?b-u:u+b):r>E&&(r=E,u=Math.abs((r-a)/f),s=k<0?b-u:u+b)):(r=c,u=l/f,s=k<0?b-u:b+u,s<0?(s=0,t=Math.abs((s-b)*f),r=j<0?a-t:t+a):s>F&&(s=F,t=Math.abs(s-b)*f,r=j<0?a-t:t+a)),r>a?(r-a<g?r=a+g:r-a>h&&(r=a+h),s>b?s=b+(r-a)/f:s=b-(r-a)/f):r<a&&(a-r<g?r=a-g:a-r>h&&(r=a-h),s>b?s=b+(a-r)/f:s=b-(a-r)/f),r<0?(a-=r,r=0):r>E&&(a-=r-E,r=E),s<0?(b-=s,s=0):s>F&&(b-=s-F,s=F),q(o(a,b,r,s))}function n(a){return a[0]<0&&(a[0]=0),a[1]<0&&(a[1]=0),a[0]>E&&(a[0]=E),a[1]>F&&(a[1]=F),[Math.round(a[0]),Math.round(a[1])]}function o(a,b,c,d){var e=a,f=c,g=b,h=d;return c<a&&(e=c,f=a),d<b&&(g=d,h=b),[e,g,f,h]}function p(){var d=c-a,f=e-b,g;return P&&Math.abs(d)>P&&(c=d>0?a+P:a-P),Q&&Math.abs
(f)>Q&&(e=f>0?b+Q:b-Q),S/U&&Math.abs(f)<S/U&&(e=f>0?b+S/U:b-S/U),R/T&&Math.abs(d)<R/T&&(c=d>0?a+R/T:a-R/T),a<0&&(c-=a,a-=a),b<0&&(e-=b,b-=b),c<0&&(a-=c,c-=c),e<0&&(b-=e,e-=e),c>E&&(g=c-E,a-=g,c-=g),e>F&&(g=e-F,b-=g,e-=g),a>E&&(g=a-F,e-=g,b-=g),b>F&&(g=b-F,e-=g,b-=g),q(o(a,b,c,e))}function q(a){return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]}}var a=0,b=0,c=0,e=0,f,g;return{flipCoords:o,setPressed:h,setCurrent:i,getOffset:j,moveOffset:k,getCorner:l,getFixed:m}}(),ba=function(){function f(a,b){e.left.css({height:i(b)}),e.right.css({height:i(b)})}function g(){return h(_.getFixed())}function h(a){e.top.css({left:i(a.x),width:i(a.w),height:i(a.y)}),e.bottom.css({top:i(a.y2),left:i(a.x),width:i(a.w),height:i(F-a.y2)}),e.right.css({left:i(a.x2),width:i(E-a.x2)}),e.left.css({width:i(a.x)})}function j(){return a("<div />").css({position:"absolute",backgroundColor:d.shadeColor||d.bgColor}).appendTo(c)}function k(){b||(b=!0,c.insertBefore(D),g(),bb.setBgOpacity(1,0,1),H.hide(),l(d.shadeColor||d.bgColor,1),bb.
isAwake()?n(d.bgOpacity,1):n(1,1))}function l(a,b){bq(p(),a,b)}function m(){b&&(c.remove(),H.show(),b=!1,bb.isAwake()?bb.setBgOpacity(d.bgOpacity,1,1):(bb.setBgOpacity(1,1,1),bb.disableHandles()),bq(G,0,1))}function n(a,e){b&&(d.bgFade&&!e?c.animate({opacity:1-a},{queue:!1,duration:d.fadeTime}):c.css({opacity:1-a}))}function o(){d.shade?k():m(),bb.isAwake()&&n(d.bgOpacity)}function p(){return c.children()}var b=!1,c=a("<div />").css({position:"absolute",zIndex:240,opacity:0}),e={top:j(),left:j().height(F),right:j().height(F),bottom:j()};return{update:g,updateRaw:h,getShades:p,setBgColor:l,enable:k,disable:m,resize:f,refresh:o,opacity:n}}(),bb=function(){function k(b){var c=a("<div />").css({position:"absolute",opacity:d.borderOpacity}).addClass(j(b));return I.append(c),c}function l(b,c){var d=a("<div />").mousedown(s(b)).css({cursor:b+"-resize",position:"absolute",zIndex:c}).addClass("ord-"+b);return Z.support&&d.bind("touchstart.jcrop",Z.createDragger(b)),J.append(d),d}function m(a){var b=d.handleSize,e=l(a,c++
).css({opacity:d.handleOpacity}).addClass(j("handle"));return b&&e.width(b).height(b),e}function n(a){return l(a,c++).addClass("jcrop-dragbar")}function o(a){var b;for(b=0;b<a.length;b++)g[a[b]]=n(a[b])}function p(a){var b,c;for(c=0;c<a.length;c++){switch(a[c]){case"n":b="hline";break;case"s":b="hline bottom";break;case"e":b="vline right";break;case"w":b="vline"}e[a[c]]=k(b)}}function q(a){var b;for(b=0;b<a.length;b++)f[a[b]]=m(a[b])}function r(a,b){d.shade||H.css({top:i(-b),left:i(-a)}),K.css({top:i(b),left:i(a)})}function t(a,b){K.width(Math.round(a)).height(Math.round(b))}function v(){var a=_.getFixed();_.setPressed([a.x,a.y]),_.setCurrent([a.x2,a.y2]),w()}function w(a){if(b)return x(a)}function x(a){var c=_.getFixed();t(c.w,c.h),r(c.x,c.y),d.shade&&ba.updateRaw(c),b||A(),a?d.onSelect.call(bs,u(c)):d.onChange.call(bs,u(c))}function z(a,c,e){if(!b&&!c)return;d.bgFade&&!e?D.animate({opacity:a},{queue:!1,duration:d.fadeTime}):D.css("opacity",a)}function A(){K.show(),d.shade?ba.opacity(O):z(O,!0),b=!0}function B
(){F(),K.hide(),d.shade?ba.opacity(1):z(1),b=!1,d.onRelease.call(bs)}function C(){h&&J.show()}function E(){h=!0;if(d.allowResize)return J.show(),!0}function F(){h=!1,J.hide()}function G(a){a?(X=!0,F()):(X=!1,E())}function L(){G(!1),v()}var b,c=370,e={},f={},g={},h=!1;d.dragEdges&&a.isArray(d.createDragbars)&&o(d.createDragbars),a.isArray(d.createHandles)&&q(d.createHandles),d.drawBorders&&a.isArray(d.createBorders)&&p(d.createBorders),a(document).bind("touchstart.jcrop-ios",function(b){a(b.currentTarget).hasClass("jcrop-tracker")&&b.stopPropagation()});var M=y().mousedown(s("move")).css({cursor:"move",position:"absolute",zIndex:360});return Z.support&&M.bind("touchstart.jcrop",Z.createDragger("move")),I.append(M),F(),{updateVisible:w,update:x,release:B,refresh:v,isAwake:function(){return b},setCursor:function(a){M.css("cursor",a)},enableHandles:E,enableOnly:function(){h=!0},showHandles:C,disableHandles:F,animMode:G,setBgOpacity:z,done:L}}(),bc=function(){function f(b){M.css({zIndex:450}),b?a(document).bind("touchmove.jcrop"
,k).bind("touchend.jcrop",l):e&&a(document).bind("mousemove.jcrop",h).bind("mouseup.jcrop",i)}function g(){M.css({zIndex:290}),a(document).unbind(".jcrop")}function h(a){return b(m(a)),!1}function i(a){return a.preventDefault(),a.stopPropagation(),W&&(W=!1,c(m(a)),bb.isAwake()&&d.onSelect.call(bs,u(_.getFixed())),g(),b=function(){},c=function(){}),!1}function j(a,d,e){return W=!0,b=a,c=d,f(e),!1}function k(a){return b(m(Z.cfilter(a))),!1}function l(a){return i(Z.cfilter(a))}function n(a){M.css("cursor",a)}var b=function(){},c=function(){},e=d.trackDocument;return e||M.mousemove(h).mouseup(i).mouseout(i),D.before(M),{activateHandlers:j,setCursor:n}}(),bd=function(){function e(){d.keySupport&&(b.show(),b.focus())}function f(a){b.hide()}function g(a,b,c){d.allowMove&&(_.moveOffset([b,c]),bb.updateVisible(!0)),a.preventDefault(),a.stopPropagation()}function i(a){if(a.ctrlKey||a.metaKey)return!0;Y=a.shiftKey?!0:!1;var b=Y?10:1;switch(a.keyCode){case 37:g(a,-b,0);break;case 39:g(a,b,0);break;case 38:g(a,0,-b);break;
case 40:g(a,0,b);break;case 27:d.allowSelect&&bb.release();break;case 9:return!0}return!1}var b=a('<input type="radio" />').css({position:"fixed",left:"-120px",width:"12px"}).addClass("jcrop-keymgr"),c=a("<div />").css({position:"absolute",overflow:"hidden"}).append(b);return d.keySupport&&(b.keydown(i).blur(f),h||!d.fixedSupport?(b.css({position:"absolute",left:"-20px"}),c.append(b).insertBefore(D)):b.insertBefore(D)),{watchKeys:e}}();Z.support&&M.bind("touchstart.jcrop",Z.newSelection),J.hide(),br(!0);var bs={setImage:bp,animateTo:bf,setSelect:bg,setOptions:bk,tellSelect:bi,tellScaled:bj,setClass:be,disable:bl,enable:bm,cancel:bn,release:bb.release,destroy:bo,focus:bd.watchKeys,getBounds:function(){return[E*T,F*U]},getWidgetSize:function(){return[E,F]},getScaleFactor:function(){return[T,U]},getOptions:function(){return d},ui:{holder:G,selection:K}};return g&&G.bind("selectstart",function(){return!1}),A.data("Jcrop",bs),bs},a.fn.Jcrop=function(b,c){var d;return this.each(function(){if(a(this).data("Jcrop")){if(
b==="api")return a(this).data("Jcrop");a(this).data("Jcrop").setOptions(b)}else this.tagName=="IMG"?a.Jcrop.Loader(this,function(){a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d)}):(a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d))}),this},a.Jcrop.Loader=function(b,c,d){function g(){f.complete?(e.unbind(".jcloader"),a.isFunction(c)&&c.call(f)):window.setTimeout(g,50)}var e=a(b),f=e[0];e.bind("load.jcloader",g).bind("error.jcloader",function(b){e.unbind(".jcloader"),a.isFunction(d)&&d.call(f)}),f.complete&&a.isFunction(c)&&(e.unbind(".jcloader"),c.call(f))},a.Jcrop.defaults={allowSelect:!0,allowMove:!0,allowResize:!0,trackDocument:!0,baseClass:"jcrop",addClass:null,bgColor:"black",bgOpacity:.6,bgFade:!1,borderOpacity:.4,handleOpacity:.5,handleSize:null,aspectRatio:0,keySupport:!0,createHandles:["n","s","e","w","nw","ne","se","sw"],createDragbars:["n","s","e","w"],createBorders:["n","s","e","w"],drawBorders:!0,dragEdges
:!0,fixedSupport:!0,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}}})(jQuery);
\ No newline at end of file
/*
* jQuery File Upload Image Preview & Resize Plugin 1.7.2
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
/* jshint nomen:false */
/* global define, window, Blob */
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define([
'jquery',
'load-image',
'load-image-meta',
'load-image-exif',
'load-image-ios',
'canvas-to-blob',
'./jquery.fileupload-process'
], factory);
} else {
// Browser globals:
factory(
window.jQuery,
window.loadImage
);
}
}(function ($, loadImage) {
'use strict';
// Prepend to the default processQueue:
$.blueimp.fileupload.prototype.options.processQueue.unshift(
{
action: 'loadImageMetaData',
disableImageHead: '@',
disableExif: '@',
disableExifThumbnail: '@',
disableExifSub: '@',
disableExifGps: '@',
disabled: '@disableImageMetaDataLoad'
},
{
action: 'loadImage',
// Use the action as prefix for the "@" options:
prefix: true,
fileTypes: '@',
maxFileSize: '@',
noRevoke: '@',
disabled: '@disableImageLoad'
},
{
action: 'resizeImage',
// Use "image" as prefix for the "@" options:
prefix: 'image',
maxWidth: '@',
maxHeight: '@',
minWidth: '@',
minHeight: '@',
crop: '@',
orientation: '@',
forceResize: '@',
disabled: '@disableImageResize'
},
{
action: 'saveImage',
quality: '@imageQuality',
type: '@imageType',
disabled: '@disableImageResize'
},
{
action: 'saveImageMetaData',
disabled: '@disableImageMetaDataSave'
},
{
action: 'resizeImage',
// Use "preview" as prefix for the "@" options:
prefix: 'preview',
maxWidth: '@',
maxHeight: '@',
minWidth: '@',
minHeight: '@',
crop: '@',
orientation: '@',
thumbnail: '@',
canvas: '@',
disabled: '@disableImagePreview'
},
{
action: 'setImage',
name: '@imagePreviewName',
disabled: '@disableImagePreview'
},
{
action: 'deleteImageReferences',
disabled: '@disableImageReferencesDeletion'
}
);
// The File Upload Resize plugin extends the fileupload widget
// with image resize functionality:
$.widget('blueimp.fileupload', $.blueimp.fileupload, {
options: {
// The regular expression for the types of images to load:
// matched against the file type:
loadImageFileTypes: /^image\/(gif|jpeg|png|svg\+xml)$/,
// The maximum file size of images to load:
loadImageMaxFileSize: 10000000, // 10MB
// The maximum width of resized images:
imageMaxWidth: 1920,
// The maximum height of resized images:
imageMaxHeight: 1080,
// Defines the image orientation (1-8) or takes the orientation
// value from Exif data if set to true:
imageOrientation: false,
// Define if resized images should be cropped or only scaled:
imageCrop: false,
// Disable the resize image functionality by default:
disableImageResize: true,
// The maximum width of the preview images:
previewMaxWidth: 80,
// The maximum height of the preview images:
previewMaxHeight: 80,
// Defines the preview orientation (1-8) or takes the orientation
// value from Exif data if set to true:
previewOrientation: true,
// Create the preview using the Exif data thumbnail:
previewThumbnail: true,
// Define if preview images should be cropped or only scaled:
previewCrop: false,
// Define if preview images should be resized as canvas elements:
previewCanvas: true
},
processActions: {
// Loads the image given via data.files and data.index
// as img element, if the browser supports the File API.
// Accepts the options fileTypes (regular expression)
// and maxFileSize (integer) to limit the files to load:
loadImage: function (data, options) {
if (options.disabled) {
return data;
}
var that = this,
file = data.files[data.index],
dfd = $.Deferred();
if (($.type(options.maxFileSize) === 'number' &&
file.size > options.maxFileSize) ||
(options.fileTypes &&
!options.fileTypes.test(file.type)) ||
!loadImage(
file,
function (img) {
if (img.src) {
data.img = img;
}
dfd.resolveWith(that, [data]);
},
options
)) {
return data;
}
return dfd.promise();
},
// Resizes the image given as data.canvas or data.img
// and updates data.canvas or data.img with the resized image.
// Also stores the resized image as preview property.
// Accepts the options maxWidth, maxHeight, minWidth,
// minHeight, canvas and crop:
resizeImage: function (data, options) {
if (options.disabled || !(data.canvas || data.img)) {
return data;
}
options = $.extend({canvas: true}, options);
var that = this,
dfd = $.Deferred(),
img = (options.canvas && data.canvas) || data.img,
resolve = function (newImg) {
if (newImg && (newImg.width !== img.width ||
newImg.height !== img.height ||
options.forceResize)) {
data[newImg.getContext ? 'canvas' : 'img'] = newImg;
}
data.preview = newImg;
dfd.resolveWith(that, [data]);
},
thumbnail;
if (data.exif) {
if (options.orientation === true) {
options.orientation = data.exif.get('Orientation');
}
if (options.thumbnail) {
thumbnail = data.exif.get('Thumbnail');
if (thumbnail) {
loadImage(thumbnail, resolve, options);
return dfd.promise();
}
}
// Prevent orienting the same image twice:
if (data.orientation) {
delete options.orientation;
} else {
data.orientation = options.orientation;
}
}
if (img) {
resolve(loadImage.scale(img, options));
return dfd.promise();
}
return data;
},
// Saves the processed image given as data.canvas
// inplace at data.index of data.files:
saveImage: function (data, options) {
if (!data.canvas || options.disabled) {
return data;
}
var that = this,
file = data.files[data.index],
dfd = $.Deferred();
if (data.canvas.toBlob) {
data.canvas.toBlob(
function (blob) {
if (!blob.name) {
if (file.type === blob.type) {
blob.name = file.name;
} else if (file.name) {
blob.name = file.name.replace(
/\..+$/,
'.' + blob.type.substr(6)
);
}
}
// Don't restore invalid meta data:
if (file.type !== blob.type) {
delete data.imageHead;
}
// Store the created blob at the position
// of the original file in the files list:
data.files[data.index] = blob;
dfd.resolveWith(that, [data]);
},
options.type || file.type,
options.quality
);
} else {
return data;
}
return dfd.promise();
},
loadImageMetaData: function (data, options) {
if (options.disabled) {
return data;
}
var that = this,
dfd = $.Deferred();
loadImage.parseMetaData(data.files[data.index], function (result) {
$.extend(data, result);
dfd.resolveWith(that, [data]);
}, options);
return dfd.promise();
},
saveImageMetaData: function (data, options) {
if (!(data.imageHead && data.canvas &&
data.canvas.toBlob && !options.disabled)) {
return data;
}
var file = data.files[data.index],
blob = new Blob([
data.imageHead,
// Resized images always have a head size of 20 bytes,
// including the JPEG marker and a minimal JFIF header:
this._blobSlice.call(file, 20)
], {type: file.type});
blob.name = file.name;
data.files[data.index] = blob;
return data;
},
// Sets the resized version of the image as a property of the
// file object, must be called after "saveImage":
setImage: function (data, options) {
if (data.preview && !options.disabled) {
data.files[data.index][options.name || 'preview'] = data.preview;
}
return data;
},
deleteImageReferences: function (data, options) {
if (!options.disabled) {
delete data.img;
delete data.canvas;
delete data.preview;
delete data.imageHead;
}
return data;
}
}
});
}));
\ No newline at end of file
/*
* jQuery File Upload Validation Plugin 1.1.2
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2013, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
/* global define, window */
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define([
'jquery',
'./jquery.fileupload-process'
], factory);
} else {
// Browser globals:
factory(
window.jQuery
);
}
}(function ($) {
'use strict';
// Append to the default processQueue:
$.blueimp.fileupload.prototype.options.processQueue.push(
{
action: 'validate',
// Always trigger this action,
// even if the previous action was rejected:
always: true,
// Options taken from the global options map:
acceptFileTypes: '@',
maxFileSize: '@',
minFileSize: '@',
maxNumberOfFiles: '@',
disabled: '@disableValidation'
}
);
// The File Upload Validation plugin extends the fileupload widget
// with file validation functionality:
$.widget('blueimp.fileupload', $.blueimp.fileupload, {
options: {
/*
// The regular expression for allowed file types, matches
// against either file type or file name:
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
// The maximum allowed file size in bytes:
maxFileSize: 10000000, // 10 MB
// The minimum allowed file size in bytes:
minFileSize: undefined, // No minimal file size
// The limit of files to be uploaded:
maxNumberOfFiles: 10,
*/
// Function returning the current number of files,
// has to be overriden for maxNumberOfFiles validation:
getNumberOfFiles: $.noop,
// Error and info messages:
messages: {
maxNumberOfFiles: 'Maximum number of files exceeded',
acceptFileTypes: 'File type not allowed',
maxFileSize: 'File is too large',
minFileSize: 'File is too small'
}
},
processActions: {
validate: function (data, options) {
if (options.disabled) {
return data;
}
var dfd = $.Deferred(),
settings = this.options,
file = data.files[data.index],
fileSize;
if (options.minFileSize || options.maxFileSize) {
fileSize = file.size;
}
if ($.type(options.maxNumberOfFiles) === 'number' &&
(settings.getNumberOfFiles() || 0) + data.files.length >
options.maxNumberOfFiles) {
file.error = settings.i18n('maxNumberOfFiles');
} else if (options.acceptFileTypes &&
!(options.acceptFileTypes.test(file.type) ||
options.acceptFileTypes.test(file.name))) {
file.error = settings.i18n('acceptFileTypes');
} else if (fileSize > options.maxFileSize) {
file.error = settings.i18n('maxFileSize');
} else if ($.type(fileSize) === 'number' &&
fileSize < options.minFileSize) {
file.error = settings.i18n('minFileSize');
} else {
delete file.error;
}
if (file.error || data.files.error) {
data.files.error = true;
dfd.rejectWith(this, [data]);
} else {
dfd.resolveWith(this, [data]);
}
return dfd.promise();
}
}
});
}));
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment